From 5159bf51e216dfbfbab18e2b5b659526fd960479 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 14:08:34 +0200 Subject: [PATCH 001/407] cu_cp,e1ap: add e1ap test doubles --- tests/test_doubles/CMakeLists.txt | 1 + tests/test_doubles/e1ap/CMakeLists.txt | 11 ++++ .../e1ap/e1ap_test_message_validators.cpp | 53 +++++++++++++++++++ .../e1ap/e1ap_test_message_validators.h | 30 +++++++++++ 4 files changed, 95 insertions(+) create mode 100644 tests/test_doubles/e1ap/CMakeLists.txt create mode 100644 tests/test_doubles/e1ap/e1ap_test_message_validators.cpp create mode 100644 tests/test_doubles/e1ap/e1ap_test_message_validators.h diff --git a/tests/test_doubles/CMakeLists.txt b/tests/test_doubles/CMakeLists.txt index 29f3c4e31f..c5098bf7ea 100644 --- a/tests/test_doubles/CMakeLists.txt +++ b/tests/test_doubles/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(mac) add_subdirectory(rrc) +add_subdirectory(e1ap) add_subdirectory(f1ap) add_subdirectory(ngap) add_subdirectory(scheduler) diff --git a/tests/test_doubles/e1ap/CMakeLists.txt b/tests/test_doubles/e1ap/CMakeLists.txt new file mode 100644 index 0000000000..4dc64eb54f --- /dev/null +++ b/tests/test_doubles/e1ap/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# 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_library(e1ap_test_doubles e1ap_test_message_validators.cpp) +set_target_properties(e1ap_test_doubles PROPERTIES UNITY_BUILD ON) +target_link_libraries(e1ap_test_doubles srsran_support srslog e1ap_asn1) diff --git a/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp b/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp new file mode 100644 index 0000000000..628123fce4 --- /dev/null +++ b/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp @@ -0,0 +1,53 @@ +/* + * + * 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 "e1ap_test_message_validators.h" +#include "srsran/asn1/e1ap/e1ap.h" +#include "srsran/e1ap/common/e1ap_message.h" + +using namespace srsran; + +#define TRUE_OR_RETURN(cond) \ + if (not(cond)) \ + return false; + +static bool is_packable(const e1ap_message& msg) +{ + byte_buffer temp_pdu; + asn1::bit_ref bref{temp_pdu}; + return msg.pdu.pack(bref) == asn1::SRSASN_SUCCESS; +} + +bool srsran::test_helpers::is_valid_bearer_context_setup_request(const e1ap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::e1ap::e1ap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_E1AP_ID_BEARER_CONTEXT_SETUP); + TRUE_OR_RETURN(is_packable(msg)); + + return true; +} + +bool srsran::test_helpers::is_valid_bearer_context_modification_request(const e1ap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::e1ap::e1ap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_E1AP_ID_BEARER_CONTEXT_MOD); + TRUE_OR_RETURN(is_packable(msg)); + + return true; +} + +bool srsran::test_helpers::is_valid_bearer_context_release_command(const e1ap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::e1ap::e1ap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_E1AP_ID_BEARER_CONTEXT_RELEASE); + TRUE_OR_RETURN(is_packable(msg)); + + return true; +} diff --git a/tests/test_doubles/e1ap/e1ap_test_message_validators.h b/tests/test_doubles/e1ap/e1ap_test_message_validators.h new file mode 100644 index 0000000000..8ea68f2400 --- /dev/null +++ b/tests/test_doubles/e1ap/e1ap_test_message_validators.h @@ -0,0 +1,30 @@ +/* + * + * 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 e1ap_message; +class byte_buffer; + +namespace test_helpers { + +/// \brief Check if an E1AP message is a valid Bearer Context Setup Request message. +bool is_valid_bearer_context_setup_request(const e1ap_message& msg); + +/// \brief Check if an E1AP message is a valid Bearer Context Modification Request message. +bool is_valid_bearer_context_modification_request(const e1ap_message& msg); + +/// \brief Check if an E1AP message is a valid Bearer Context Release Command message. +bool is_valid_bearer_context_release_command(const e1ap_message& msg); + +} // namespace test_helpers +} // namespace srsran From 1cdb3ac17a518f627cee82d93f961ea9dab2b046 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 14:13:28 +0200 Subject: [PATCH 002/407] cu_cp,ngap: improve ngap test doubles --- .../ngap/ngap_test_message_validators.cpp | 30 ++++++++++++++++++- .../ngap/ngap_test_message_validators.h | 8 +++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.cpp b/tests/test_doubles/ngap/ngap_test_message_validators.cpp index 98bd8da233..638302b5b5 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.cpp +++ b/tests/test_doubles/ngap/ngap_test_message_validators.cpp @@ -53,4 +53,32 @@ bool srsran::test_helpers::is_valid_ue_radio_capability_info_indication(const sr TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::init_msg); TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_NGAP_ID_UE_RADIO_CAP_INFO_IND); return true; -} \ No newline at end of file +} + +bool srsran::test_helpers::is_valid_ue_context_release_complete(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::successful_outcome); + TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_NGAP_ID_UE_CONTEXT_RELEASE); + return true; +} + +bool srsran::test_helpers::is_valid_pdu_session_resource_setup_response(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::successful_outcome); + TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_NGAP_ID_PDU_SESSION_RES_SETUP); + return true; +} + +bool srsran::test_helpers::is_valid_pdu_session_resource_release_response(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::successful_outcome); + TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_NGAP_ID_PDU_SESSION_RES_RELEASE); + return true; +} + +bool srsran::test_helpers::is_valid_pdu_session_resource_modify_response(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::successful_outcome); + TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_NGAP_ID_PDU_SESSION_RES_MODIFY); + return true; +} diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.h b/tests/test_doubles/ngap/ngap_test_message_validators.h index c5be693df6..9434f453ae 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.h +++ b/tests/test_doubles/ngap/ngap_test_message_validators.h @@ -30,5 +30,13 @@ bool is_valid_ue_context_release_request(const srs_cu_cp::ngap_message& msg); bool is_valid_ue_radio_capability_info_indication(const srs_cu_cp::ngap_message& msg); +bool is_valid_ue_context_release_complete(const srs_cu_cp::ngap_message& msg); + +bool is_valid_pdu_session_resource_setup_response(const srs_cu_cp::ngap_message& msg); + +bool is_valid_pdu_session_resource_release_response(const srs_cu_cp::ngap_message& msg); + +bool is_valid_pdu_session_resource_modify_response(const srs_cu_cp::ngap_message& msg); + } // namespace test_helpers } // namespace srsran \ No newline at end of file From 2bc8f78f278f40ae73069b94291563acebee22c5 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 14:13:52 +0200 Subject: [PATCH 003/407] cu_cp,rrc: improve rrc test doubles --- .../rrc/rrc_test_message_validators.cpp | 61 +++++++++++++++++-- .../rrc/rrc_test_message_validators.h | 15 ++++- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/tests/test_doubles/rrc/rrc_test_message_validators.cpp b/tests/test_doubles/rrc/rrc_test_message_validators.cpp index 894dc947dd..ca3513c36e 100644 --- a/tests/test_doubles/rrc/rrc_test_message_validators.cpp +++ b/tests/test_doubles/rrc/rrc_test_message_validators.cpp @@ -85,21 +85,74 @@ bool srsran::test_helpers::is_valid_rrc_ue_capability_enquiry(const byte_buffer& return is_valid_rrc_ue_capability_enquiry(dcch); } -bool srsran::test_helpers::is_valid_rrc_reconfiguration(const asn1::rrc_nr::dl_dcch_msg_s& msg) +bool srsran::test_helpers::is_valid_rrc_reconfiguration( + const asn1::rrc_nr::dl_dcch_msg_s& msg, + bool contains_nas_pdu, + const std::optional>& expected_srbs_to_add_mod, + const std::optional>& expected_drbs_to_add_mod, + const std::optional>& expected_drbs_to_release) { TRUE_OR_RETURN(msg.msg.type().value == asn1::rrc_nr::dl_dcch_msg_type_c::types_opts::c1); TRUE_OR_RETURN(msg.msg.c1().type().value == asn1::rrc_nr::dl_dcch_msg_type_c::c1_c_::types_opts::rrc_recfg); TRUE_OR_RETURN(msg.msg.c1().rrc_recfg().crit_exts.type().value == asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types_opts::rrc_recfg); TRUE_OR_RETURN(msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().non_crit_ext_present); - TRUE_OR_RETURN(msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size() != 0); + if (contains_nas_pdu) { + TRUE_OR_RETURN(msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size() != 0); + } + + if (!msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().radio_bearer_cfg_present && + (expected_drbs_to_add_mod.has_value() or expected_drbs_to_add_mod.has_value())) { + return false; + } + + if (msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().radio_bearer_cfg_present) { + if (expected_srbs_to_add_mod.has_value()) { + std::vector srbs_to_add_mod; + for (const auto& srb : msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().radio_bearer_cfg.srb_to_add_mod_list) { + srbs_to_add_mod.push_back(int_to_srb_id(srb.srb_id)); + } + + TRUE_OR_RETURN(srbs_to_add_mod.size() == expected_srbs_to_add_mod.value().size()); + TRUE_OR_RETURN( + std::equal(srbs_to_add_mod.begin(), srbs_to_add_mod.end(), expected_srbs_to_add_mod.value().begin())) + } + + if (expected_drbs_to_add_mod.has_value()) { + std::vector drbs_to_add_mod; + for (const auto& drb : msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().radio_bearer_cfg.drb_to_add_mod_list) { + drbs_to_add_mod.push_back(uint_to_drb_id(drb.drb_id)); + } + + TRUE_OR_RETURN(drbs_to_add_mod.size() == expected_drbs_to_add_mod.value().size()); + TRUE_OR_RETURN( + std::equal(drbs_to_add_mod.begin(), drbs_to_add_mod.end(), expected_drbs_to_add_mod.value().begin())) + } + + if (expected_drbs_to_release.has_value()) { + std::vector drbs_to_release; + for (const auto& drb : msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg().radio_bearer_cfg.drb_to_release_list) { + drbs_to_release.push_back(uint_to_drb_id(drb)); + } + + TRUE_OR_RETURN(drbs_to_release.size() == expected_drbs_to_release.value().size()); + TRUE_OR_RETURN( + std::equal(drbs_to_release.begin(), drbs_to_release.end(), expected_drbs_to_release.value().begin())) + } + } return true; } -bool srsran::test_helpers::is_valid_rrc_reconfiguration(const byte_buffer& dl_dcch_msg) +bool srsran::test_helpers::is_valid_rrc_reconfiguration( + const byte_buffer& dl_dcch_msg, + bool contains_nas_pdu, + const std::optional>& expected_srbs_to_add_mod, + const std::optional>& expected_drbs_to_add_mod, + const std::optional>& expected_drbs_to_release) { asn1::cbit_ref bref{dl_dcch_msg}; asn1::rrc_nr::dl_dcch_msg_s dcch; TRUE_OR_RETURN(dcch.unpack(bref) == asn1::SRSASN_SUCCESS); - return is_valid_rrc_reconfiguration(dcch); + return is_valid_rrc_reconfiguration( + dcch, contains_nas_pdu, expected_srbs_to_add_mod, expected_drbs_to_add_mod, expected_drbs_to_release); } \ No newline at end of file diff --git a/tests/test_doubles/rrc/rrc_test_message_validators.h b/tests/test_doubles/rrc/rrc_test_message_validators.h index 52edd8a607..68154d2b3e 100644 --- a/tests/test_doubles/rrc/rrc_test_message_validators.h +++ b/tests/test_doubles/rrc/rrc_test_message_validators.h @@ -12,6 +12,9 @@ #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" #include "srsran/asn1/rrc_nr/dl_dcch_msg.h" +#include "srsran/asn1/rrc_nr/dl_dcch_msg_ies.h" +#include "srsran/ran/lcid.h" +#include namespace srsran { namespace test_helpers { @@ -33,8 +36,16 @@ bool is_valid_rrc_ue_capability_enquiry(const asn1::rrc_nr::dl_dcch_msg_s& msg); bool is_valid_rrc_ue_capability_enquiry(const byte_buffer& dl_dcch_msg); /// \brief Check if DL-DCCH message is a valid RRC Reconfiguration message. -bool is_valid_rrc_reconfiguration(const asn1::rrc_nr::dl_dcch_msg_s& msg); -bool is_valid_rrc_reconfiguration(const byte_buffer& dl_dcch_msg); +bool is_valid_rrc_reconfiguration(const asn1::rrc_nr::dl_dcch_msg_s& msg, + bool contains_nas_pdu, + const std::optional>& expected_srbs_to_add_mod, + const std::optional>& expected_drbs_to_add_mod, + const std::optional>& expected_drbs_to_release); +bool is_valid_rrc_reconfiguration(const byte_buffer& dl_dcch_msg, + bool contains_nas_pdu = true, + const std::optional>& expected_srbs_to_add_mod = std::nullopt, + const std::optional>& expected_drbs_to_add_mod = std::nullopt, + const std::optional>& expected_drbs_to_release = std::nullopt); } // namespace test_helpers } // namespace srsran \ No newline at end of file From c9439c98b9693fcd17a843f52dc87a13b01838e6 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 14:44:07 +0200 Subject: [PATCH 004/407] cu_cp: fix handling of pdu sessions with failed sessions --- .../pdu_session_resource_modification_routine.cpp | 3 ++- .../routines/pdu_session_resource_setup_routine.cpp | 12 ++++++++---- lib/cu_cp/routines/pdu_session_routine_helpers.cpp | 6 +++++- lib/cu_cp/routines/pdu_session_routine_helpers.h | 3 ++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index 2e45dd72f4..0986f59482 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -257,7 +257,8 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& // Traverse failed list update_failed_list(response_msg.pdu_session_res_failed_to_modify_list, - bearer_context_modification_response.pdu_session_resource_failed_list); + bearer_context_modification_response.pdu_session_resource_failed_list, + next_config); return bearer_context_modification_response.success; } diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 674a2a0def..52b309a0b1 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -268,7 +268,8 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& // Traverse failed list update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, - bearer_context_modification_response.pdu_session_resource_failed_list); + bearer_context_modification_response.pdu_session_resource_failed_list, + next_config); for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_modified_list) { // modified list @@ -308,7 +309,8 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r // Traverse failed list update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, - bearer_context_setup_response.pdu_session_resource_failed_list); + bearer_context_setup_response.pdu_session_resource_failed_list, + next_config); return bearer_context_setup_response.success; } @@ -373,6 +375,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r // Helper to mark all PDU sessions that were requested to be set up as failed. void mark_all_sessions_as_failed(cu_cp_pdu_session_resource_setup_response& response_msg, const cu_cp_pdu_session_resource_setup_request& setup_msg, + up_config_update& next_config, e1ap_cause_t cause) { slotted_id_vector failed_list; @@ -382,7 +385,7 @@ void mark_all_sessions_as_failed(cu_cp_pdu_session_resource_setup_response& fail_item.cause = cause; failed_list.emplace(setup_item.pdu_session_id, fail_item); } - update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, failed_list); + update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, failed_list, next_config); // No PDU session setup can be successful at the same time. response_msg.pdu_session_res_setup_response_items.clear(); } @@ -402,7 +405,8 @@ pdu_session_resource_setup_routine::handle_pdu_session_resource_setup_result(boo } else { logger.info("ue={}: \"{}\" failed", setup_msg.ue_index, name()); - mark_all_sessions_as_failed(response_msg, setup_msg, e1ap_cause_t{e1ap_cause_radio_network_t::unspecified}); + mark_all_sessions_as_failed( + response_msg, setup_msg, next_config, e1ap_cause_t{e1ap_cause_radio_network_t::unspecified}); } return response_msg; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index a15bcb97ae..ef5aa669a0 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -498,9 +498,13 @@ void srsran::srs_cu_cp::fill_drb_to_remove_list(std::vector& e1a void srsran::srs_cu_cp::update_failed_list( slotted_id_vector& ngap_failed_list, - const slotted_id_vector& pdu_session_resource_failed_list) + const slotted_id_vector& pdu_session_resource_failed_list, + up_config_update& next_config) { for (const auto& e1ap_item : pdu_session_resource_failed_list) { + // Remove from next config + next_config.pdu_sessions_to_setup_list.erase(e1ap_item.pdu_session_id); + // Add to list taking cause received from CU-UP. cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = e1ap_item.pdu_session_id; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index 6abdb8b332..1344a8c46d 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -101,7 +101,8 @@ bool update_setup_list(e1ap_bearer_context_modification_request& void update_failed_list( slotted_id_vector& ngap_failed_list, - const slotted_id_vector& pdu_session_resource_failed_list); + const slotted_id_vector& pdu_session_resource_failed_list, + up_config_update& next_config); /// \brief Processes the result of a Bearer Context Modifcation Result's PDU session modify list. /// \param[out] ngap_response_list Reference to the final NGAP response From 53429bcaea211bfaa601e22e2f7caaa8fdaf769f Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 15:07:09 +0200 Subject: [PATCH 005/407] cu_cp: refactor cu-cp pdu session and ue context releated unittests to use cu-cp test environment --- tests/unittests/cu_cp/CMakeLists.txt | 15 +- .../cu_cp_initial_context_setup_test.cpp | 12 +- ...cu_cp_pdu_session_resource_modify_test.cpp | 492 +++++++++++++++++ ...u_cp_pdu_session_resource_release_test.cpp | 323 +++++++++++ .../cu_cp_pdu_session_resource_setup_test.cpp | 454 +++++++++++++++ .../cu_cp/cu_cp_reestablishment_test.cpp | 25 +- tests/unittests/cu_cp/cu_cp_test.cpp | 4 +- .../cu_cp/cu_cp_test_environment.cpp | 417 ++++++++++++-- .../unittests/cu_cp/cu_cp_test_environment.h | 103 +++- tests/unittests/cu_cp/cu_cp_test_helpers.cpp | 4 +- .../cu_cp/cu_cp_ue_context_release_test.cpp | 161 ++++++ tests/unittests/cu_cp/routines/CMakeLists.txt | 33 -- .../cu_cp_routine_manager_test_helpers.cpp | 63 --- .../cu_cp_routine_manager_test_helpers.h | 53 -- ...ion_resource_modification_routine_test.cpp | 441 --------------- ..._session_resource_release_routine_test.cpp | 176 ------ ...du_session_resource_routine_test_helpers.h | 92 ---- ...du_session_resource_setup_routine_test.cpp | 516 ------------------ .../ue_context_release_routine_test.cpp | 77 --- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 147 +++-- .../e1ap/common/e1ap_cu_cp_test_messages.h | 22 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 36 +- .../f1ap/common/f1ap_cu_test_messages.h | 9 +- ..._session_resource_setup_procedure_test.cpp | 4 +- tests/unittests/ngap/ngap_test_helpers.cpp | 2 +- tests/unittests/ngap/ngap_test_messages.cpp | 138 +++-- tests/unittests/ngap/ngap_test_messages.h | 23 +- tests/unittests/ngap/ngap_validators_test.cpp | 10 +- 28 files changed, 2218 insertions(+), 1634 deletions(-) create mode 100644 tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp create mode 100644 tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp create mode 100644 tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp create mode 100644 tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp delete mode 100644 tests/unittests/cu_cp/routines/CMakeLists.txt delete mode 100644 tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp delete mode 100644 tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h delete mode 100644 tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp delete mode 100644 tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp delete mode 100644 tests/unittests/cu_cp/routines/pdu_session_resource_routine_test_helpers.h delete mode 100644 tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp delete mode 100644 tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index 7ff825c995..1143064073 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -13,7 +13,6 @@ include_directories(../../..) add_subdirectory(cell_meas_manager) add_subdirectory(cu_up_processor) add_subdirectory(du_processor) -add_subdirectory(routines) add_subdirectory(ue_manager) add_subdirectory(up_resource_manager) add_subdirectory(mobility) @@ -32,7 +31,17 @@ target_include_directories(cu_cp_test_helpers PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(cu_cp_test_helpers srsran_cu_cp srsran_support srslog f1ap_test_helpers e1ap_test_helpers f1ap_asn1 ngap_asn1 e1ap_asn1) -add_executable(cu_cp_test cu_cp_test.cpp cu_cp_connectivity_test.cpp cu_cp_setup_test.cpp cu_cp_reestablishment_test.cpp cu_cp_initial_context_setup_test.cpp) +add_executable(cu_cp_test + cu_cp_test.cpp + cu_cp_connectivity_test.cpp + cu_cp_setup_test.cpp + cu_cp_reestablishment_test.cpp + cu_cp_initial_context_setup_test.cpp + cu_cp_ue_context_release_test.cpp + cu_cp_pdu_session_resource_setup_test.cpp + cu_cp_pdu_session_resource_release_test.cpp + cu_cp_pdu_session_resource_modify_test.cpp + ) set_target_properties(cu_cp_test PROPERTIES UNITY_BUILD ON) target_link_libraries(cu_cp_test cu_cp_test_helpers @@ -45,12 +54,14 @@ target_link_libraries(cu_cp_test f1ap_asn1 ngap_asn1 rrc_test_doubles + e1ap_test_doubles f1ap_test_doubles ngap_test_doubles gtest gtest_main) target_include_directories(cu_cp_test PRIVATE ${CMAKE_SOURCE_DIR}) add_test(cu_cp_test cu_cp_test) +gtest_discover_tests(cu_cp_test) add_executable(cu_cp_config_test cu_cp_config_test.cpp) target_link_libraries(cu_cp_config_test cu_cp_test_helpers srsran_cu_cp gtest gtest_main) diff --git a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp index bbfc61ad7c..51d34d9ca0 100644 --- a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp @@ -176,15 +176,21 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : // Make sure RRC Reconfiguration contains NAS PDU const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); report_fatal_error_if_not( - test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container)), + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), + true, + std::vector{srb_id_t::srb2}, + std::vector{drb_id_t::drb1}), "Invalid RRC Reconfiguration"); } void send_rrc_reconfiguration_complete_and_await_initial_context_setup_response() { // Inject UL RRC Message Transfer (containing RRC Reconfiguration Complete) - f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - ue_ctx->cu_ue_id.value(), du_ue_id, srb_id_t::srb1, make_byte_buffer("00050e00a18bc2b3").value()); + f1ap_message ul_rrc_msg_transfer = + generate_ul_rrc_message_transfer(ue_ctx->cu_ue_id.value(), + du_ue_id, + srb_id_t::srb1, + cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(3, 5)); get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); // Wait for Initial Context Setup Response diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp new file mode 100644 index 0000000000..5441c7da27 --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp @@ -0,0 +1,492 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/asn1/ngap/ngap_pdu_contents.h" +#include "srsran/e1ap/common/e1ap_types.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" +#include "srsran/ran/cu_types.h" +#include "srsran/ran/lcid.h" +#include +#include +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_pdu_session_resource_modify_test() : + cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(du_idx)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + + // Connect UE 0x4601. + EXPECT_TRUE(attach_ue(du_idx, cu_up_idx, du_ue_id, crnti, amf_ue_id, cu_up_e1ap_id, psi, drb_id_t::drb1, qfi)); + ue_ctx = this->find_ue_context(du_idx, du_ue_id); + + EXPECT_NE(ue_ctx, nullptr); + } + + unsigned du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = amf_ue_id_t::min; + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + + const ue_context* ue_ctx = nullptr; + + pdu_session_id_t psi = uint_to_pdu_session_id(1); + pdu_session_id_t psi2 = uint_to_pdu_session_id(2); + qos_flow_id_t qfi = uint_to_qos_flow_id(1); + qos_flow_id_t qfi2 = uint_to_qos_flow_id(2); + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; + e1ap_message e1ap_pdu; + + bool is_expected_pdu_session_resource_modify_response( + const std::vector& expected_pdu_sessions_to_modify, + const std::vector& expected_pdu_sessions_failed_to_modify) + { + // Check failed PDU sessions + if (expected_pdu_sessions_failed_to_modify.empty() && ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_failed_to_modify_list_mod_res_present) { + return false; + } + + if (!expected_pdu_sessions_failed_to_modify.empty() && + !ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_failed_to_modify_list_mod_res_present) { + return false; + } + + if (expected_pdu_sessions_failed_to_modify.size() != ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_failed_to_modify_list_mod_res.size()) { + return false; + } + + for (const auto& asn1_failed_item : ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_failed_to_modify_list_mod_res) { + if (std::find(expected_pdu_sessions_failed_to_modify.begin(), + expected_pdu_sessions_failed_to_modify.end(), + uint_to_pdu_session_id(asn1_failed_item.pdu_session_id)) == + expected_pdu_sessions_failed_to_modify.end()) { + return false; + } + } + + // Check successful PDU sessions + if (expected_pdu_sessions_to_modify.empty() && ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_modify_list_mod_res_present) { + return false; + } + + if (!expected_pdu_sessions_to_modify.empty() && !ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_modify_list_mod_res_present) { + return false; + } + + if (expected_pdu_sessions_to_modify.size() != ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_modify_resp() + ->pdu_session_res_modify_list_mod_res.size()) { + return false; + } + + for (const auto& asn1_modify_item : + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_modify_resp()->pdu_session_res_modify_list_mod_res) { + if (std::find(expected_pdu_sessions_to_modify.begin(), + expected_pdu_sessions_to_modify.end(), + uint_to_pdu_session_id(asn1_modify_item.pdu_session_id)) == expected_pdu_sessions_to_modify.end()) { + return false; + } + } + + return true; + } + + void send_pdu_session_modify_request_and_await_pdu_session_modify_response() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject PDU Session Resource Modify Request and wait for PDU Session Resource Modify Response + get_amf().push_tx_pdu( + generate_valid_pdu_session_resource_modify_request_message(amf_ue_id, ue_ctx->ran_ue_id.value(), psi2, {qfi2})); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi2}), + "Unsuccessful PDU Session Resource Modify Response"); + } + + void send_pdu_session_modify_request_and_await_bearer_context_modification_request( + pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1), + const std::vector& flows_to_add = {uint_to_qos_flow_id(2)}, + const std::vector& flows_to_release = {}) + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject PDU Session Resource Modify Request and wait for Bearer Context Modification Request + get_amf().push_tx_pdu(generate_valid_pdu_session_resource_modify_request_message( + amf_ue_id, ue_ctx->ran_ue_id.value(), pdu_session_id, flows_to_add, flows_to_release)); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + } + + void send_bearer_context_modification_failure_and_await_pdu_session_modify_response() + { + // Inject Bearer Context Modification Failure and wait for PDU Session Resource Setup Response + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi}), + "Unsuccessful PDU Session Resource Modify Response"); + } + + void send_bearer_context_modification_response_and_await_ue_context_modification_request( + pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1), + drb_id_t drb_id = drb_id_t::drb2) + { + // Inject Bearer Context Modification Response and wait for PDU Session Resource Setup Response + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( + ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value(), {}, {{pdu_session_id, drb_id}})); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + } + + void send_ue_context_modification_failure_and_await_pdu_session_modify_response() + { + // Inject UE Context Modification Failure and wait for PDU Session Resource Setup Response + get_du(du_idx).push_ul_pdu( + generate_ue_context_modification_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi}), + "Unsuccessful PDU Session Resource Modify Response"); + } + + void send_ue_context_modification_response_and_await_bearer_context_modification_request( + const std::vector& drbs_setup_mod_list = {drb_id_t::drb2}, + const std::vector& drbs_modified_list = {}) + { + // Inject UE Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) + get_du(du_idx).push_ul_pdu(generate_ue_context_modification_response( + ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value(), crnti, drbs_setup_mod_list, drbs_modified_list)); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + } + + void send_bearer_context_modification_response_and_await_rrc_reconfiguration( + pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1), + drb_id_t drb_to_modify = drb_id_t::drb2, + bool is_drb_release = false) + { + // Inject Bearer Context Modification Response and wait for PDU Session Resource Setup Response + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( + ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value(), {}, {{pdu_session_id, drb_to_modify}})); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), + "Invalid DL RRC Message Transfer"); + { + const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); + + if (is_drb_release) { + report_fatal_error_if_not( + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), + false, + std::vector{}, + std::vector{}, + std::vector{drb_to_modify}), + "Invalid RRC Reconfiguration"); + } else { + report_fatal_error_if_not( + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), + false, + std::vector{}, + std::vector{drb_to_modify}), + "Invalid RRC Reconfiguration"); + } + } + } + + void timeout_rrc_reconfiguration_and_await_pdu_session_modify_response() + { + // Fail RRC Reconfiguration (UE doesn't respond) and wait for PDU Session Resource Setup Response + ASSERT_FALSE(tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), + [&]() { return false; })); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi}), + "Unsuccessful PDU Session Resource Modify Response"); + } + + bool send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00080800e6847bbd").value()) + { + // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for PDU Session Resource Modify Response + get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( + du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, std::move(rrc_reconfiguration_complete))); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({psi}, {}), + "Unsuccessful PDU Session Resource Modify Response"); + + return true; + } + + void modify_pdu_session_and_add_qos_flow( + pdu_session_id_t pdu_session_id, + drb_id_t drb_id, + qos_flow_id_t qos_flow_id, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00080800e6847bbd").value()) + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(pdu_session_id, {qos_flow_id}, {}); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(pdu_session_id, drb_id); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration(pdu_session_id, drb_id); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response + send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response(std::move(rrc_reconfiguration_complete)); + } +}; + +TEST_F(cu_cp_pdu_session_resource_modify_test, + when_modify_request_with_inactive_pdu_session_arrives_then_modification_fails) +{ + // Inject PDU Session Resource Modify Request and await PDU Session Resource Modify Response + send_pdu_session_modify_request_and_await_pdu_session_modify_response(); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_bearer_ctxt_modification_fails_then_pdu_session_modify_fails) +{ + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Failure and await PDU Session Resource Modify Response + send_bearer_context_modification_failure_and_await_pdu_session_modify_response(); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_ue_ctxt_modification_fails_then_pdu_session_modify_fails) +{ + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Failure and await PDU Session Resource Modify Response + send_ue_context_modification_failure_and_await_pdu_session_modify_response(); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_second_bearer_ctxt_modification_fails_then_pdu_session_modify_fails) +{ + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Failure and await PDU Session Resource Modify Response + send_bearer_context_modification_failure_and_await_pdu_session_modify_response(); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_rrc_reconfiguration_fails_then_pdu_session_modify_fails) +{ + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration(); + + // Let the RRC Reconfiguration timeout and await PDU Session Resource Modify Response + timeout_rrc_reconfiguration_and_await_pdu_session_modify_response(); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_rrc_reconfiguration_succeeds_then_pdu_session_modify_succeeds) +{ + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration(); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response + send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response(); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, + when_valid_modification_arrives_and_qos_flow_can_be_removed_then_pdu_session_modification_succeeds) +{ + // Run PDU session modification and add second QoS flow + modify_pdu_session_and_add_qos_flow(psi, drb_id_t::drb2, qfi2); + + // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request + send_pdu_session_modify_request_and_await_bearer_context_modification_request(psi, {}, {qfi2}); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request({}, {drb_id_t::drb2}); + + // Inject Bearer Context Modification Response and await RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration(psi, drb_id_t::drb2, true); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response + send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( + cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(1, 9)); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_many_qos_flows_are_added_pdu_session_modification_succeeds) +{ + // Add QoS flows until maximum number of DRBs is reached + unsigned transaction_id = 0; + unsigned count = 8; + for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { + modify_pdu_session_and_add_qos_flow( + psi, + uint_to_drb_id(i), + uint_to_qos_flow_id(i), + cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); + count++; + transaction_id++; + if (transaction_id == 4) { + transaction_id = 0; + } + } +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_one_to_many_qos_flows_are_added_last_pdu_session_modification_fails) +{ + // Add QoS flows until maximum number of DRBs is reached + unsigned transaction_id = 0; + unsigned count = 8; + for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { + modify_pdu_session_and_add_qos_flow( + psi, + uint_to_drb_id(i), + uint_to_qos_flow_id(i), + cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); + count++; + transaction_id++; + if (transaction_id == 4) { + transaction_id = 0; + } + } + + // Try to add one more QoS flow and expect failure + // Inject PDU Session Resource Modify Request and wait for PDU Session Resource Modify Response + get_amf().push_tx_pdu( + generate_valid_pdu_session_resource_modify_request_message(amf_ue_id, ue_ctx->ran_ue_id.value(), psi2, {qfi2})); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi2}), + "Unsuccessful PDU Session Resource Modify Response"); +} + +TEST_F(cu_cp_pdu_session_resource_modify_test, when_valid_modification_is_received_twice_then_second_modification_fails) +{ + // Run PDU session modification and add second QoS flow + modify_pdu_session_and_add_qos_flow(psi, drb_id_t::drb2, qfi2); + + // Run PDU session modification again and try to add same QoS flow + // Inject PDU Session Resource Modify Request and wait for PDU Session Resource Modify Response + get_amf().push_tx_pdu( + generate_valid_pdu_session_resource_modify_request_message(amf_ue_id, ue_ctx->ran_ue_id.value(), psi2, {qfi2})); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), + "Invalid PDU Session Resource Modify Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi2}), + "Unsuccessful PDU Session Resource Modify Response"); +} diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp new file mode 100644 index 0000000000..7a312d13f7 --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp @@ -0,0 +1,323 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/e1ap/common/e1ap_types.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" +#include "srsran/ran/cu_types.h" +#include +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_pdu_session_resource_release_test() : + cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(du_idx)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + + // Connect UE 0x4601. + EXPECT_TRUE(attach_ue(du_idx, cu_up_idx, du_ue_id, crnti, amf_ue_id, cu_up_e1ap_id, psi, drb_id_t::drb1, qfi)); + ue_ctx = this->find_ue_context(du_idx, du_ue_id); + + EXPECT_NE(ue_ctx, nullptr); + } + + unsigned du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = amf_ue_id_t::min; + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + + const ue_context* ue_ctx = nullptr; + + pdu_session_id_t psi = uint_to_pdu_session_id(1); + pdu_session_id_t psi2 = uint_to_pdu_session_id(2); + qos_flow_id_t qfi = uint_to_qos_flow_id(1); + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; + e1ap_message e1ap_pdu; + + void setup_second_pdu_session() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Modification Request + get_amf().push_tx_pdu(generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi2, {{uint_to_qos_flow_id(2), 7}}}})); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), + cu_up_e1ap_id, + {{psi2, drb_test_params{drb_id_t::drb2, uint_to_qos_flow_id(2)}}}, + {})); + result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + ASSERT_TRUE( + cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( + du_idx, cu_up_idx, du_ue_id, crnti)); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( + ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value(), {}, {{psi2, drb_id_t::drb2}})); + result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), + "Invalid DL RRC Message Transfer"); + { + const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); + report_fatal_error_if_not( + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), + true, + std::vector{}, + std::vector{drb_id_t::drb2}), + "Invalid RRC Reconfiguration"); + } + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response + get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( + du_ue_id, + ue_ctx->cu_ue_id.value(), + srb_id_t::srb1, + cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(0, 8))); + result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not( + cu_cp_test_environment::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi2}, {}), + "Unsuccessful PDU Session Resource Setup Response"); + } + + void send_pdu_session_release_command_and_await_bearer_context_modification_request() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject Bearer Context Setup Response and wait for UE Context Modification Request + get_amf().push_tx_pdu( + generate_valid_pdu_session_resource_release_command(amf_ue_id, ue_ctx->ran_ue_id.value(), psi)); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + } + + void send_pdu_session_release_command_and_await_bearer_context_release_command() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject Bearer Context Setup Response and wait for UE Context Release Command + get_amf().push_tx_pdu( + generate_valid_pdu_session_resource_release_command(amf_ue_id, ue_ctx->ran_ue_id.value(), psi)); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Release Command"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_release_command(e1ap_pdu), + "Invalid Bearer Context Release Command"); + } + + void send_bearer_context_modification_failure_and_await_ue_context_modification_request() + { + // Inject Bearer Context Modification Failure and wait for UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + } + + void send_bearer_context_modification_response_and_await_ue_context_modification_request() + { + // Inject Bearer Context Modification Response and wait for UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + } + + void send_bearer_context_release_complete_and_await_ue_context_modification_request() + { + // Inject Bearer Context Release Complete and wait for UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_release_complete(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + } + + void send_ue_context_modification_response_and_await_rrc_reconfiguration() + { + // Inject UE Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) + get_du(du_idx).push_ul_pdu( + test_helpers::generate_ue_context_modification_response(du_ue_id, ue_ctx->cu_ue_id.value(), crnti)); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), + "Invalid DL RRC Message Transfer"); + { + const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); + report_fatal_error_if_not( + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), {}, {}), + "Invalid RRC Reconfiguration"); + } + } + + void send_ue_context_modification_failure_and_await_rrc_reconfiguration() + { + // Inject UE Context Modification Failure and wait for DL RRC Message (containing RRC Reconfiguration) + get_du(du_idx).push_ul_pdu( + generate_ue_context_modification_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), + "Invalid DL RRC Message Transfer"); + { + const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); + report_fatal_error_if_not( + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), {}, {}), + "Invalid RRC Reconfiguration"); + } + } + + bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response() + { + // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for PDU Session Resource Release + // Response + get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( + du_ue_id, + ue_ctx->cu_ue_id.value(), + srb_id_t::srb1, + cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(3, 7))); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Release Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_release_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + + return true; + } +}; + +TEST_F(cu_cp_pdu_session_resource_release_test, when_bearer_context_modification_failure_received_then_release_succeeds) +{ + // Add second PDU session + setup_second_pdu_session(); + + // Inject NGAP PDU Session Resource Release Command and await Bearer Context Modification Request + send_pdu_session_release_command_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Failure and await UE Context Modification Request + send_bearer_context_modification_failure_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await RRC Reconfiguration + send_ue_context_modification_response_and_await_rrc_reconfiguration(); + + // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_release_test, when_ue_context_modification_failure_received_then_release_succeeds) +{ + // Add second PDU session + setup_second_pdu_session(); + + // Inject NGAP PDU Session Resource Release Command and await Bearer Context Modification Request + send_pdu_session_release_command_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Failure and await RRC Reconfiguration + send_ue_context_modification_failure_and_await_rrc_reconfiguration(); + + // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_release_test, when_all_sub_actions_succeed_then_release_succeeds) +{ + // Add second PDU session + setup_second_pdu_session(); + + // Inject NGAP PDU Session Resource Release Command and await Bearer Context Modification Request + send_pdu_session_release_command_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await RRC Reconfiguration + send_ue_context_modification_response_and_await_rrc_reconfiguration(); + + // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_release_test, when_only_pdu_session_released_then_bearer_context_release_command_sent) +{ + // Inject NGAP PDU Session Resource Release Command and await Bearer Context Release Command + send_pdu_session_release_command_and_await_bearer_context_release_command(); + + // Inject Bearer Context Release Complete and await UE Context Modification Request + send_bearer_context_release_complete_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await RRC Reconfiguration + send_ue_context_modification_response_and_await_rrc_reconfiguration(); + + // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); +} \ No newline at end of file diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp new file mode 100644 index 0000000000..c5c431ef9d --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp @@ -0,0 +1,454 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/e1ap/common/e1ap_types.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" +#include "srsran/ran/cu_types.h" +#include "srsran/ran/lcid.h" +#include +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_pdu_session_resource_setup_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(du_idx)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + + // Connect UE 0x4601. + EXPECT_TRUE(connect_new_ue(du_idx, du_ue_id, crnti)); + EXPECT_TRUE(authenticate_ue(du_idx, du_ue_id, amf_ue_id)); + EXPECT_TRUE(setup_ue_security(du_idx, du_ue_id)); + ue_ctx = this->find_ue_context(du_idx, du_ue_id); + + EXPECT_TRUE(finish_ue_registration(du_idx, cu_up_idx, du_ue_id)); + EXPECT_TRUE(request_pdu_session_resource_setup(du_idx, cu_up_idx, du_ue_id)); + + EXPECT_NE(ue_ctx, nullptr); + } + + void setup_pdu_session(pdu_session_id_t psi_, + drb_id_t drb_id_, + qos_flow_id_t qfi_, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), + bool is_initial_session_ = true) + { + EXPECT_TRUE(cu_cp_test_environment::setup_pdu_session(du_idx, + cu_up_idx, + du_ue_id, + crnti, + cu_up_e1ap_id, + psi_, + drb_id_, + qfi_, + std::move(rrc_reconfiguration_complete), + is_initial_session_)); + } + + ngap_message generate_pdu_session_resource_setup_request_with_unconfigured_fiveqi() const + { + ngap_message request = generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 99}}}}); + + return request; + } + + void send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( + const ngap_message& pdu_session_resource_setup_request) + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject PDU Session Resource Setup Request and wait for PDU Session Resource Setup Response + get_amf().push_tx_pdu(pdu_session_resource_setup_request); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + "Unsuccessful PDU Session Resource Setup Response"); + } + + void send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + const ngap_message& pdu_session_resource_setup_request) + { + ASSERT_TRUE(cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + pdu_session_resource_setup_request, du_idx, cu_up_idx, du_ue_id)); + } + + void send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + const ngap_message& pdu_session_resource_setup_request) + { + ASSERT_TRUE( + cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + pdu_session_resource_setup_request, du_idx)); + } + + void send_bearer_context_setup_failure_and_await_pdu_session_setup_response() + { + // Inject Bearer Context Setup Failure and wait for PDU Session Resource Setup Response + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_setup_failure(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + "Unsuccessful PDU Session Resource Setup Response"); + } + + void send_bearer_context_setup_response_and_await_ue_context_modification_request() + { + ASSERT_TRUE(cu_cp_test_environment::send_bearer_context_setup_response_and_await_ue_context_modification_request( + du_idx, cu_up_idx, du_ue_id, cu_up_e1ap_id, psi, qfi)); + } + + void send_bearer_context_modification_response_and_await_ue_context_modification_request() + { + ASSERT_TRUE( + cu_cp_test_environment::send_bearer_context_modification_response_and_await_ue_context_modification_request( + du_idx, cu_up_idx, du_ue_id, psi2, drb_id_t::drb2, qfi2)); + } + + void send_ue_context_modification_failure_and_await_pdu_session_setup_response() + { + // Inject UE Context Modification Failure and wait for PDU Session Resource Setup Response + get_du(du_idx).push_ul_pdu( + generate_ue_context_modification_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + "Unsuccessful PDU Session Resource Setup Response"); + } + + void send_ue_context_modification_response_and_await_bearer_context_modification_request() + { + ASSERT_TRUE( + cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( + du_idx, cu_up_idx, du_ue_id, crnti)); + } + + void send_bearer_context_modification_failure_and_await_pdu_session_setup_response() + { + // Inject Bearer Context Modification Failure and wait for PDU Session Resource Setup Response + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + "Unsuccessful PDU Session Resource Setup Response"); + } + + void send_bearer_context_modification_response_and_await_rrc_reconfiguration( + const std::map& pdu_sessions_to_add = {}, + const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}, + const std::optional>& expected_srbs_to_add_mod = std::nullopt, + const std::optional>& expected_drbs_to_add_mod = std::nullopt) + { + ASSERT_TRUE(cu_cp_test_environment::send_bearer_context_modification_response_and_await_rrc_reconfiguration( + du_idx, + cu_up_idx, + du_ue_id, + pdu_sessions_to_add, + pdu_sessions_to_modify, + expected_srbs_to_add_mod, + expected_drbs_to_add_mod)); + } + + void timeout_rrc_reconfiguration_and_await_pdu_session_setup_response() + { + // Fail RRC Reconfiguration (UE doesn't respond) and wait for PDU Session Resource Setup Response + ASSERT_FALSE(tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), + [&]() { return false; })); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + "Unsuccessful PDU Session Resource Setup Response"); + } + + void send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + byte_buffer rrc_container, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup) + { + ASSERT_TRUE(cu_cp_test_environment::send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + du_idx, + du_ue_id, + std::move(rrc_container), + expected_pdu_sessions_to_setup, + expected_pdu_sessions_failed_to_setup)); + } + + unsigned du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = amf_ue_id_t::min; + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + + const ue_context* ue_ctx = nullptr; + + pdu_session_id_t psi = uint_to_pdu_session_id(1); + pdu_session_id_t psi2 = uint_to_pdu_session_id(2); + qos_flow_id_t qfi = uint_to_qos_flow_id(1); + qos_flow_id_t qfi2 = uint_to_qos_flow_id(2); + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; + e1ap_message e1ap_pdu; +}; + +TEST_F(cu_cp_pdu_session_resource_setup_test, + when_pdu_session_setup_request_with_unconfigured_fiveqi_received_setup_fails) +{ + // Inject NGAP PDU Session Resource Setup Request and await PDU Session Setup Response + send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( + generate_pdu_session_resource_setup_request_with_unconfigured_fiveqi()); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_bearer_context_setup_failure_received_then_setup_fails) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + + // Inject Bearer Context Setup Failure and await PDU Session Resource Setup Response + send_bearer_context_setup_failure_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_ue_context_modification_failure_received_then_setup_fails) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + send_bearer_context_setup_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Failure and await PDU Session Resource Setup Response + send_ue_context_modification_failure_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_bearer_context_modification_failure_received_then_setup_fails) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + send_bearer_context_setup_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Failure and await PDU Session Resource Setup Response + send_bearer_context_modification_failure_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_rrc_reconfiguration_fails_then_setup_fails) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + send_bearer_context_setup_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1}); + + // Let the RRC Reconfiguration timeout and await PDU Session Resource Setup Response + timeout_rrc_reconfiguration_and_await_pdu_session_setup_response(); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_rrc_reconfiguration_succeeds_then_setup_succeeds) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + send_bearer_context_setup_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1}); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + make_byte_buffer("00070e00cc6fcda5").value(), {psi}, {}); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_pdu_session_setup_for_existing_session_arrives_then_setup_fails) +{ + // Setup first PDU session + setup_pdu_session(psi, drb_id_t::drb1, qfi); + + // Inject NGAP PDU Session Resource Setup Request and await PDU Session Setup Response + send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_setup_for_pdu_sessions_with_two_qos_flows_received_setup_succeeds) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}, {qfi2, 9}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + send_bearer_context_setup_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, + {{psi, drb_id_t::drb1}, {psi2, drb_id_t::drb2}}, + std::vector{srb_id_t::srb2}, + std::vector{drb_id_t::drb1, drb_id_t::drb2}); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + make_byte_buffer("00070e00cc6fcda5").value(), {psi}, {}); +} + +TEST_F( + cu_cp_pdu_session_resource_setup_test, + when_setup_for_two_pdu_sessions_is_requested_but_only_first_could_be_setup_at_cu_up_setup_succeeds_with_fail_list) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), + ue_ctx->ran_ue_id.value(), + {{psi, {qos_flow_test_params{qfi, 9}}}, {psi2, {qos_flow_test_params{qfi2, 7}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_setup_response( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {{psi, drb_test_params{drb_id_t::drb1, qfi}}}, {psi2})); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); + result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), + "Invalid DL RRC Message Transfer"); + { + const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); + report_fatal_error_if_not( + test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), + true, + std::vector{srb_id_t::srb2}, + std::vector{drb_id_t::drb1}), + "Invalid RRC Reconfiguration"); + } + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response + get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( + du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, make_byte_buffer("00070e00cc6fcda5").value())); + result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi}, {psi2}), + "Unsuccessful PDU Session Resource Setup Response"); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, + when_setup_for_two_pdu_sessions_is_requested_and_both_succeed_setup_succeeds) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}, {psi2, {{qfi2, 9}}}})); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + send_bearer_context_setup_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + send_ue_context_modification_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, + {{psi, drb_id_t::drb1}, {psi2, drb_id_t::drb2}}, + std::vector{srb_id_t::srb2}, + std::vector{drb_id_t::drb1, drb_id_t::drb2}); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response + send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + make_byte_buffer("00070e00cc6fcda5").value(), {psi}, {}); +} + +TEST_F(cu_cp_pdu_session_resource_setup_test, when_two_consecutive_setups_arrive_bearer_setup_and_modification_succeed) +{ + // Setup first PDU session + setup_pdu_session(psi, drb_id_t::drb1, qfi); + + // Setup second PDU session + setup_pdu_session(psi2, drb_id_t::drb2, qfi2, make_byte_buffer("00080800e6847bbd").value(), false); +} \ No newline at end of file diff --git a/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp b/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp index e72aac07fe..f49a62f5ca 100644 --- a/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp @@ -131,9 +131,11 @@ class cu_cp_reestablishment_test : public cu_cp_test_environment, public ::testi unsigned du_idx = 0; unsigned cu_up_idx = 0; - gnb_du_ue_f1ap_id_t old_du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t old_crnti = to_rnti(0x4601); - pci_t old_pci = 0; + gnb_du_ue_f1ap_id_t old_du_ue_id = gnb_du_ue_f1ap_id_t::min; + rnti_t old_crnti = to_rnti(0x4601); + pci_t old_pci = 0; + amf_ue_id_t amf_ue_id = amf_ue_id_t::min; + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; }; TEST_F(cu_cp_reestablishment_test, when_old_ue_does_not_exist_then_reestablishment_fails) @@ -189,13 +191,14 @@ TEST_F(cu_cp_reestablishment_test, { // Connect UE 0x4601. EXPECT_TRUE(connect_new_ue(du_idx, old_du_ue_id, old_crnti)); - EXPECT_TRUE(authenticate_ue(du_idx, old_du_ue_id, uint_to_amf_ue_id(0))); + EXPECT_TRUE(authenticate_ue(du_idx, old_du_ue_id, amf_ue_id)); EXPECT_TRUE(setup_ue_security(du_idx, old_du_ue_id)); // Run Reestablishment. gnb_du_ue_f1ap_id_t new_du_ue_id = int_to_gnb_du_ue_f1ap_id(1); rnti_t new_crnti = to_rnti(0x4602); - ASSERT_FALSE(reestablish_ue(du_idx, new_du_ue_id, new_crnti, old_crnti, old_pci)) << "Reestablishment failed"; + ASSERT_FALSE(reestablish_ue(du_idx, cu_up_idx, new_du_ue_id, new_crnti, old_crnti, old_pci)) + << "Reestablishment failed"; // STATUS: Given that the old UE has an AMF-UE-ID, the CU-CP should request its release. ngap_message ngap_pdu; @@ -212,12 +215,13 @@ TEST_F(cu_cp_reestablishment_test, when_old_ue_has_drb_then_reestablishment_succeeds_and_no_ngap_release_request_is_sent_for_old_ue) { // Attach UE 0x4601. - EXPECT_TRUE(attach_ue(du_idx, old_du_ue_id, old_crnti, uint_to_amf_ue_id(0))); + EXPECT_TRUE(attach_ue(du_idx, cu_up_idx, old_du_ue_id, old_crnti, amf_ue_id, cu_up_e1ap_id)); // Send RRC Reestablishment Request and DU receives RRC Reestablishment. gnb_du_ue_f1ap_id_t new_du_ue_id = int_to_gnb_du_ue_f1ap_id(1); rnti_t new_crnti = to_rnti(0x4602); - ASSERT_TRUE(reestablish_ue(du_idx, new_du_ue_id, new_crnti, old_crnti, old_pci)) << "Reestablishment failed"; + ASSERT_TRUE(reestablish_ue(du_idx, cu_up_idx, new_du_ue_id, new_crnti, old_crnti, old_pci)) + << "Reestablishment failed"; // old UE should not be removed at this stage. auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); @@ -270,7 +274,7 @@ TEST_F(cu_cp_reestablishment_test, when_f1_removal_request_is_sent_before_reestablishment_completion_then_cu_cp_ue_is_removed) { // Attach UE 0x4601. - EXPECT_TRUE(attach_ue(du_idx, old_du_ue_id, old_crnti, uint_to_amf_ue_id(0))); + EXPECT_TRUE(attach_ue(du_idx, cu_up_idx, old_du_ue_id, old_crnti, amf_ue_id, cu_up_e1ap_id)); // Send RRC Reestablishment Request and DU receives RRC Reestablishment. gnb_du_ue_f1ap_id_t new_du_ue_id = int_to_gnb_du_ue_f1ap_id(1); @@ -294,7 +298,7 @@ TEST_F(cu_cp_reestablishment_test, when_reestablishment_request_for_same_ue_is_received_twice_then_second_reestablishment_fails) { // Attach UE 0x4601. - EXPECT_TRUE(attach_ue(du_idx, old_du_ue_id, old_crnti, uint_to_amf_ue_id(0))); + EXPECT_TRUE(attach_ue(du_idx, cu_up_idx, old_du_ue_id, old_crnti, amf_ue_id, cu_up_e1ap_id)); // Send RRC Reestablishment Request and DU receives RRC Reestablishment. gnb_du_ue_f1ap_id_t du_ue_id2 = int_to_gnb_du_ue_f1ap_id(1); @@ -305,5 +309,6 @@ TEST_F(cu_cp_reestablishment_test, // Run second Reestablishment. This should fail. auto du_ue_id3 = int_to_gnb_du_ue_f1ap_id(2); auto crnti3 = to_rnti(0x4603); - ASSERT_FALSE(reestablish_ue(du_idx, du_ue_id3, crnti3, old_crnti, old_pci)) << "Fallback should have occurred"; + ASSERT_FALSE(reestablish_ue(du_idx, cu_up_idx, du_ue_id3, crnti3, old_crnti, old_pci)) + << "Fallback should have occurred"; } diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index ff806db329..da17b0b50c 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -397,8 +397,8 @@ TEST_F(cu_cp_test, ASSERT_TRUE(last_f1ap_msgs.back().pdu.init_msg().value.ue_context_release_cmd()->srb_id_present); // Inject PDU Session Resource Setup Request - cu_cp_obj->get_ngap_message_handler().handle_message( - generate_valid_pdu_session_resource_setup_request_message(amf_ue_id, ran_ue_id, uint_to_pdu_session_id(1))); + cu_cp_obj->get_ngap_message_handler().handle_message(generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id, ran_ue_id, {{uint_to_pdu_session_id(1), {{uint_to_qos_flow_id(1), 9}}}})); // Inject F1AP UE Context Release Complete f1c_gw.get_du(uint_to_du_index(0)) diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index ca1284e998..7852e434e9 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -9,6 +9,7 @@ */ #include "cu_cp_test_environment.h" +#include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_message_validators.h" @@ -28,6 +29,8 @@ #include "srsran/e1ap/common/e1ap_types.h" #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/ngap/ngap_message.h" +#include "srsran/ran/cu_types.h" +#include "srsran/security/integrity.h" #include "srsran/support/executors/task_worker.h" using namespace srsran; @@ -82,6 +85,8 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : security::ciphering_algorithm::nea1, security::ciphering_algorithm::nea3}; + cu_cp_cfg.f1ap.json_log_enabled = true; + // create CU-CP instance. cu_cp_inst = create_cu_cp(cu_cp_cfg); } @@ -442,28 +447,12 @@ bool cu_cp_test_environment::setup_ue_security(unsigned du_idx, gnb_du_ue_f1ap_i return true; } -bool cu_cp_test_environment::attach_ue(unsigned du_idx, - gnb_du_ue_f1ap_id_t du_ue_id, - rnti_t crnti, - amf_ue_id_t amf_ue_id) +bool cu_cp_test_environment::finish_ue_registration(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id) { - if (not connect_new_ue(du_idx, du_ue_id, crnti)) { - return false; - } - if (not authenticate_ue(du_idx, du_ue_id, amf_ue_id)) { - return false; - } - if (not setup_ue_security(du_idx, du_ue_id)) { - return false; - } - auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); - ngap_message ngap_pdu; srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - f1ap_message f1ap_pdu; - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - e1ap_message e1ap_pdu; - srsran_assert(not this->get_cu_up(0).try_pop_rx_pdu(e1ap_pdu), "there are still E1AP messages to pop from CU-UP"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); // Inject Registration Complete and wait UL NAS message. get_du(du_idx).push_ul_pdu( @@ -474,6 +463,20 @@ bool cu_cp_test_environment::attach_ue(unsigned du_idx, bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); report_fatal_error_if_not(result, "Failed to receive Registration Complete"); + return true; +} + +bool cu_cp_test_environment::request_pdu_session_resource_setup(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id) +{ + ngap_message ngap_pdu; + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + f1ap_message f1ap_pdu; + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + // Inject PDU Session Establishment Request and wait UL NAS message. get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( du_ue_id, @@ -482,12 +485,12 @@ bool cu_cp_test_environment::attach_ue(unsigned du_idx, make_byte_buffer("00063a253f011ffa9203013f0033808018970080e0ffffc9d8bd8013404010880080000840830000000041830000000" "00000800001800005000006000006800008800900c092838339b939b0b83700e03a21bb") .value())); - result = this->wait_for_ngap_tx_pdu(ngap_pdu); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); report_fatal_error_if_not(result, "Failed to receive Registration Complete"); // Inject Configuration Update Command ngap_message dl_nas_transport_msg = generate_downlink_nas_transport_message( - amf_ue_id, + ue_ctx.amf_ue_id.value(), ue_ctx.ran_ue_id.value(), make_byte_buffer("7e0205545bfc027e0054430f90004f00700065006e00350047005346004732800131235200490100").value()); get_amf().push_tx_pdu(dl_nas_transport_msg); @@ -496,53 +499,379 @@ bool cu_cp_test_environment::attach_ue(unsigned du_idx, report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); - // Inject PDU Session Resource Setup Request and wait for E1AP Bearer Context Setup Request. - ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( - amf_ue_id, ue_ctx.ran_ue_id.value(), uint_to_pdu_session_id(1)); + return true; +} + +bool cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + const ngap_message& pdu_session_resource_setup_request, + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id) +{ + e1ap_message e1ap_pdu; + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject PDU Session Resource Setup Request and wait for Bearer Context Setup Request get_amf().push_tx_pdu(pdu_session_resource_setup_request); - result = this->wait_for_e1ap_tx_pdu(0, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive E1AP Bearer Context Setup Request"); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Setup Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_setup_request(e1ap_pdu), + "Invalid Bearer Context Setup Request"); - gnb_cu_cp_ue_e1ap_id_t cu_cp_e1ap_id = + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + ue_ctx.cu_cp_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(e1ap_pdu.pdu.init_msg().value.bearer_context_setup_request()->gnb_cu_cp_ue_e1ap_id); - gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = int_to_gnb_cu_up_ue_e1ap_id(0); - // Inject Bearer Context Setup Response and wait for F1AP UE Context Modification Request. - get_cu_up(0).push_tx_pdu(generate_bearer_context_setup_response(cu_cp_e1ap_id, cu_up_e1ap_id)); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP UE Context Modification Request"); + return true; +} + +bool cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + const ngap_message& pdu_session_resource_setup_request, + unsigned cu_up_idx) +{ + e1ap_message e1ap_pdu; + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject PDU Session Resource Setup Request and wait for Bearer Context Setup Request + get_amf().push_tx_pdu(pdu_session_resource_setup_request); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + + return true; +} + +bool cu_cp_test_environment::send_bearer_context_setup_response_and_await_ue_context_modification_request( + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi, + qos_flow_id_t qfi) +{ + f1ap_message f1ap_pdu; + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + ue_ctx.cu_up_e1ap_id = cu_up_e1ap_id; + + // Inject Bearer Context Setup Response and wait for UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_setup_response( + ue_ctx.cu_cp_e1ap_id.value(), ue_ctx.cu_up_e1ap_id.value(), {{psi, drb_test_params{drb_id_t::drb1, qfi}}})); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), - "Invalid UE Context Modification"); + "Invalid UE Context Modification Request"); - // Inject UE Context Modification Response and wait for Bearer Context Modification to be sent to CU-UP. + return true; +} + +bool cu_cp_test_environment::send_bearer_context_modification_response_and_await_ue_context_modification_request( + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + pdu_session_id_t psi, + drb_id_t drb_id, + qos_flow_id_t qfi) +{ + f1ap_message f1ap_pdu; + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + + // Inject Bearer Context Modification Response and wait for UE Context Modification Request + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( + ue_ctx.cu_cp_e1ap_id.value(), ue_ctx.cu_up_e1ap_id.value(), {{psi, drb_test_params{drb_id, qfi}}})); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + + return true; +} + +bool cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti) +{ + e1ap_message e1ap_pdu; + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + + // Inject UE Context Modification Response and wait for Bearer Context Modification Request get_du(du_idx).push_ul_pdu( test_helpers::generate_ue_context_modification_response(du_ue_id, ue_ctx.cu_ue_id.value(), crnti)); - result = this->wait_for_e1ap_tx_pdu(0, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive E1AP Bearer Context Modification"); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + + return true; +} + +bool cu_cp_test_environment::send_bearer_context_modification_response_and_await_rrc_reconfiguration( + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + const std::map& pdu_sessions_to_add, + const std::map& pdu_sessions_to_modify, + const std::optional>& expected_srbs_to_add_mod, + const std::optional>& expected_drbs_to_add_mod) +{ + f1ap_message f1ap_pdu; + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); // Inject E1AP Bearer Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) - get_cu_up(0).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( + ue_ctx.cu_cp_e1ap_id.value(), ue_ctx.cu_up_e1ap_id.value(), pdu_sessions_to_add, pdu_sessions_to_modify)); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); { const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); report_fatal_error_if_not( - test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container)), + test_helpers::is_valid_rrc_reconfiguration( + test_helpers::extract_dl_dcch_msg(rrc_container), true, expected_srbs_to_add_mod, expected_drbs_to_add_mod), "Invalid RRC Reconfiguration"); } - // Inject RRC Reconfiguration Complete and wait for PDU Session Resource Setup Response to be sent to AMF. + return true; +} + +bool cu_cp_test_environment::is_expected_pdu_session_resource_setup_response( + const ngap_message& ngap_pdu, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup) +{ + // Check failed PDU sessions + if (expected_pdu_sessions_failed_to_setup.empty() && ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res_present) { + return false; + } + + if (!expected_pdu_sessions_failed_to_setup.empty() && !ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res_present) { + return false; + } + + if (expected_pdu_sessions_failed_to_setup.size() != ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res.size()) { + return false; + } + + for (const auto& asn1_failed_item : ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res) { + if (std::find(expected_pdu_sessions_failed_to_setup.begin(), + expected_pdu_sessions_failed_to_setup.end(), + uint_to_pdu_session_id(asn1_failed_item.pdu_session_id)) == + expected_pdu_sessions_failed_to_setup.end()) { + return false; + } + } + + // Check successful PDU sessions + if (expected_pdu_sessions_to_setup.empty() && + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res_present) { + return false; + } + + if (!expected_pdu_sessions_to_setup.empty() && !ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_setup_list_su_res_present) { + return false; + } + + if (expected_pdu_sessions_to_setup.size() != + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res.size()) { + return false; + } + + for (const auto& asn1_setup_item : + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res) { + if (std::find(expected_pdu_sessions_to_setup.begin(), + expected_pdu_sessions_to_setup.end(), + uint_to_pdu_session_id(asn1_setup_item.pdu_session_id)) == expected_pdu_sessions_to_setup.end()) { + return false; + } + } + + return true; +} + +byte_buffer cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(unsigned transaction_id, uint8_t count) +{ + byte_buffer pdu_with_count = byte_buffer::create({0x00, count}).value(); + if (!pdu_with_count.append(pack_ul_dcch_msg(create_rrc_reconfiguration_complete(transaction_id)))) { + return {}; + } + + security::sec_mac mac_exp = {}; + auto k_128_int = std::array{ + 0xf3, 0xd5, 0x99, 0x4a, 0x3b, 0x29, 0x06, 0xfb, 0x27, 0x00, 0x4a, 0x44, 0x90, 0x6c, 0x6b, 0xd1}; + byte_buffer_view buf = pdu_with_count; + + security::security_nia2( + mac_exp, k_128_int, count, srb_id_to_uint(srb_id_t::srb1) - 1, security::security_direction::uplink, buf); + + if (!pdu_with_count.append(mac_exp)) { + return {}; + } + + return pdu_with_count; +} + +bool cu_cp_test_environment::send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + unsigned du_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + byte_buffer rrc_reconfiguration_complete, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup) +{ + ngap_message ngap_pdu; + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + + // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for PDU Session Resource Setup Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( - du_ue_id, ue_ctx.cu_ue_id.value(), srb_id_t::srb1, make_byte_buffer("00070e00cc6fcda5").value())); - result = this->wait_for_ngap_tx_pdu(ngap_pdu); + du_ue_id, ue_ctx.cu_ue_id.value(), srb_id_t::srb1, std::move(rrc_reconfiguration_complete))); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), + "Invalid PDU Session Resource Setup Response"); + report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response( + ngap_pdu, expected_pdu_sessions_to_setup, expected_pdu_sessions_failed_to_setup), + "Unsuccessful PDU Session Resource Setup Response"); + + return true; +} + +bool cu_cp_test_environment::setup_pdu_session(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi, + drb_id_t drb_id, + qos_flow_id_t qfi, + byte_buffer rrc_reconfiguration_complete, + bool is_initial_session) +{ + ngap_message ngap_pdu; + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + f1ap_message f1ap_pdu; + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + e1ap_message e1ap_pdu; + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); + + ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( + ue_ctx.amf_ue_id.value(), ue_ctx.ran_ue_id.value(), {{psi, {{qfi, 9}}}}); + + if (is_initial_session) { + // Inject PDU Session Resource Setup Request and wait for Bearer Context Setup Request. + send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + pdu_session_resource_setup_request, du_idx, cu_up_idx, du_ue_id); + + // Inject Bearer Context Setup Response and wait for F1AP UE Context Modification Request. + if (not send_bearer_context_setup_response_and_await_ue_context_modification_request( + du_idx, cu_up_idx, du_ue_id, cu_up_e1ap_id, psi, qfi)) { + return false; + } + } else { + // Inject PDU Session Resource Setup Request and wait for Bearer Context Modification Request. + send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + pdu_session_resource_setup_request, du_idx); + + // Inject Bearer Context Modification Response and wait for F1AP UE Context Modification Request. + if (not send_bearer_context_modification_response_and_await_ue_context_modification_request( + du_idx, cu_up_idx, du_ue_id, psi, drb_id, qfi)) { + return false; + } + } + + // Inject UE Context Modification Response and wait for Bearer Context Modification to be sent to CU-UP. + if (not send_ue_context_modification_response_and_await_bearer_context_modification_request( + du_idx, cu_up_idx, du_ue_id, crnti)) { + return false; + } + + // Inject Bearer Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) + if (not send_bearer_context_modification_response_and_await_rrc_reconfiguration( + du_idx, cu_up_idx, du_ue_id, {}, {{psi, drb_id}})) { + return false; + } + + // Inject RRC Reconfiguration Complete and wait for PDU Session Resource Setup Response to be sent to AMF. + if (not send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + du_idx, du_ue_id, std::move(rrc_reconfiguration_complete), {psi}, {})) { + return false; + } + return true; + + return true; +} + +bool cu_cp_test_environment::attach_ue(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + amf_ue_id_t amf_ue_id, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi, + drb_id_t drb_id, + qos_flow_id_t qfi, + byte_buffer rrc_reconfiguration_complete) +{ + if (not connect_new_ue(du_idx, du_ue_id, crnti)) { + return false; + } + if (not authenticate_ue(du_idx, du_ue_id, amf_ue_id)) { + return false; + } + if (not setup_ue_security(du_idx, du_ue_id)) { + return false; + } + if (not finish_ue_registration(du_idx, cu_up_idx, du_ue_id)) { + return false; + } + if (not request_pdu_session_resource_setup(du_idx, cu_up_idx, du_ue_id)) { + return false; + } + if (not setup_pdu_session(du_idx, + cu_up_idx, + du_ue_id, + crnti, + cu_up_e1ap_id, + psi, + drb_id, + qfi, + std::move(rrc_reconfiguration_complete), + true)) { + return false; + } return true; } bool cu_cp_test_environment::reestablish_ue(unsigned du_idx, + unsigned cu_up_idx, gnb_du_ue_f1ap_id_t new_du_ue_id, rnti_t new_crnti, rnti_t old_crnti, @@ -626,7 +955,7 @@ bool cu_cp_test_environment::reestablish_ue(unsigned du_idx, int_to_gnb_cu_up_ue_e1ap_id(e1ap_pdu.pdu.init_msg().value.bearer_context_mod_request()->gnb_cu_up_ue_e1ap_id); // EVENT: Inject E1AP Bearer Context Modification Response - get_cu_up(0).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); // STATUS: CU-CP sends F1AP UE Context Modification Request to DU. report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), "F1AP UEContextModificationRequest NOT sent"); @@ -639,7 +968,7 @@ bool cu_cp_test_environment::reestablish_ue(unsigned du_idx, report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(0, e1ap_pdu), "E1AP BearerContextModificationRequest NOT sent"); // EVENT: CU-UP sends E1AP Bearer Context Modification Response - get_cu_up(0).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); // STATUS: CU-CP sends F1AP DL RRC Message Transfer (containing RRC Reconfiguration). report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), "F1AP DL RRC Message NOT sent"); diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index 040ec1b1ae..f3230d579d 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -13,6 +13,7 @@ #include "test_doubles/mock_amf.h" #include "test_doubles/mock_cu_up.h" #include "test_doubles/mock_du.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "srsran/cu_cp/cu_cp.h" #include "srsran/cu_cp/cu_cp_configuration.h" #include @@ -32,11 +33,13 @@ class cu_cp_test_environment { public: struct ue_context { - rnti_t crnti = rnti_t::INVALID_RNTI; - std::optional du_ue_id; - std::optional cu_ue_id; - std::optional ran_ue_id; - std::optional amf_ue_id; + rnti_t crnti = rnti_t::INVALID_RNTI; + std::optional du_ue_id; + std::optional cu_ue_id; + std::optional ran_ue_id; + std::optional amf_ue_id; + std::optional cu_cp_e1ap_id; + std::optional cu_up_e1ap_id; }; explicit cu_cp_test_environment(cu_cp_test_env_params params = {}); @@ -73,12 +76,40 @@ class cu_cp_test_environment bool authenticate_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, amf_ue_id_t amf_ue_id); /// Runs the Security Mode procedure for a given UE. bool setup_ue_security(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id); - /// Runs RRC setup, authentication, security, RRC Reconfiguration for a given UE. - bool attach_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, rnti_t crnti, amf_ue_id_t amf_ue_id); + /// Finishes the registration for a given UE. + bool finish_ue_registration(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); + /// Requests PDU Session Resource Setup + bool request_pdu_session_resource_setup(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); + /// Runs PDU Session Resource Setup for a given UE. + bool setup_pdu_session(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi = pdu_session_id_t::min, + drb_id_t drb_id = drb_id_t::drb1, + qos_flow_id_t qfi = qos_flow_id_t::min, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), + bool is_initial_session = true); + /// Runs RRC setup, authentication, security, RRC Reconfiguration, PDU session setup for a given UE. + bool attach_ue(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + amf_ue_id_t amf_ue_id, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi = pdu_session_id_t::min, + drb_id_t drb_id = drb_id_t::drb1, + qos_flow_id_t qfi = qos_flow_id_t::min, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value()); /// Reestablishes a UE connection, including RRC Reestablishment and RRC Reconfiguration procedures. /// \return True if the reestablishment was successful, false if RRC Setup/Reject was performed instead. - bool - reestablish_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t new_du_ue_id, rnti_t new_crnti, rnti_t old_crnti, pci_t old_pci); + bool reestablish_ue(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t new_du_ue_id, + rnti_t new_crnti, + rnti_t old_crnti, + pci_t old_pci); /// Tick the CU-CP clock. void tick(); @@ -104,6 +135,60 @@ class cu_cp_test_environment /// Get CU-CP configuration used to instantiate CU-CP. const cu_cp_configuration& get_cu_cp_cfg() const { return cu_cp_cfg; } + // Helper functions + bool send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + const ngap_message& pdu_session_resource_setup_request, + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id); + + bool send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + const ngap_message& pdu_session_resource_setup_request, + unsigned cu_up_idx); + + bool + send_bearer_context_setup_response_and_await_ue_context_modification_request(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi, + qos_flow_id_t qfi); + + bool send_bearer_context_modification_response_and_await_ue_context_modification_request(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + pdu_session_id_t psi, + drb_id_t drb_id, + qos_flow_id_t qfi); + + bool send_ue_context_modification_response_and_await_bearer_context_modification_request(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti); + + bool send_bearer_context_modification_response_and_await_rrc_reconfiguration( + unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + const std::map& pdu_sessions_to_add = {}, + const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}, + const std::optional>& expected_srbs_to_add_mod = std::nullopt, + const std::optional>& expected_drbs_to_add_mod = std::nullopt); + + bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + unsigned du_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + byte_buffer rrc_reconfiguration_complete, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup); + + bool is_expected_pdu_session_resource_setup_response( + const ngap_message& ngap_pdu, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup); + + byte_buffer generate_rrc_reconfiguration_complete_pdu(unsigned transaction_id, uint8_t count); + private: class worker_manager; diff --git a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp index 1a369cde39..4ee06c688f 100644 --- a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp @@ -299,8 +299,8 @@ void cu_cp_test::add_pdu_sessions(std::vector psis, for (const auto psi : psis) { // Inject PDU Session Resource Setup Request - ngap_message pdu_session_resource_setup_request = - generate_valid_pdu_session_resource_setup_request_message(amf_ue_id, ran_ue_id, psi); + ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id, ran_ue_id, {{psi, {{uint_to_qos_flow_id(1), 9}}}}); cu_cp_obj->get_ngap_message_handler().handle_message(pdu_session_resource_setup_request); if (initial_pdu_session) { diff --git a/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp b/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp new file mode 100644 index 0000000000..c975215dd5 --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp @@ -0,0 +1,161 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/e1ap/common/e1ap_types.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_ue_context_release_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_ue_context_release_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(du_idx)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + + // Connect UE 0x4601. + EXPECT_TRUE(connect_new_ue(du_idx, du_ue_id, crnti)); + EXPECT_TRUE(authenticate_ue(du_idx, du_ue_id, amf_ue_id)); + EXPECT_TRUE(setup_ue_security(du_idx, du_ue_id)); + ue_ctx = this->find_ue_context(du_idx, du_ue_id); + + EXPECT_TRUE(finish_ue_registration(du_idx, cu_up_idx, du_ue_id)); + + EXPECT_NE(ue_ctx, nullptr); + } + + void setup_ue_pdu_session() + { + EXPECT_TRUE(request_pdu_session_resource_setup(du_idx, cu_up_idx, du_ue_id)); + EXPECT_TRUE(setup_pdu_session(du_idx, cu_up_idx, du_ue_id, crnti, cu_up_e1ap_id)); + } + + void send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject NGAP UE Context Release Command and wait for F1AP UE Context Release Command + get_amf().push_tx_pdu(generate_valid_ue_context_release_command_with_amf_ue_ngap_id(ue_ctx->amf_ue_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), + "Invalid UE Context Release Command"); + } + + void send_ngap_ue_context_release_command_and_await_bearer_context_release_command() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject NGAP UE Context Release Command and wait for Bearer Context Release Command + get_amf().push_tx_pdu(generate_valid_ue_context_release_command_with_amf_ue_ngap_id(ue_ctx->amf_ue_id.value())); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Release Command"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_release_command(e1ap_pdu), + "Invalid Bearer Context Release Command"); + } + + void send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command() + { + // Inject Bearer Context Release Complete and wait for F1AP UE Context Release Command + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_release_complete(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), + "Invalid UE Context Release Command"); + } + + void send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete() + { + // Inject F1AP UE Context Release Complete and wait for N1AP UE Context Release Command + get_du(du_idx).push_ul_pdu( + generate_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Complete"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_complete(ngap_pdu), + "Invalid UE Context Release Complete"); + } + + unsigned du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = amf_ue_id_t::min; + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + + const ue_context* ue_ctx = nullptr; + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; + e1ap_message e1ap_pdu; +}; + +TEST_F(cu_cp_ue_context_release_test, + when_ue_context_release_command_but_no_pdu_session_setup_received_then_release_succeeds) +{ + // Inject NGAP UE Context Release Command and await F1AP UE Context Release Command + send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command(); + + // Inject F1AP UE Context Release Complete and await NGAP UE Context Release Complete + send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete(); + + // STATUS: UE should be removed at this stage + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; +} + +TEST_F(cu_cp_ue_context_release_test, when_ue_context_release_command_received_then_release_succeeds) +{ + // Setup PDU Session + setup_ue_pdu_session(); + + // Inject NGAP UE Context Release Command and await Bearer Context Release Command + send_ngap_ue_context_release_command_and_await_bearer_context_release_command(); + + // Inject Bearer Context Release Complete and await F1AP UE Context Release Command + send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command(); + + // Inject F1AP UE Context Release Complete and await NGAP UE Context Release Complete + send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete(); + + // STATUS: UE should be removed at this stage + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; +} diff --git a/tests/unittests/cu_cp/routines/CMakeLists.txt b/tests/unittests/cu_cp/routines/CMakeLists.txt deleted file mode 100644 index 1359d7964a..0000000000 --- a/tests/unittests/cu_cp/routines/CMakeLists.txt +++ /dev/null @@ -1,33 +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. -# - -add_library(cu_cp_routine_manager_test_helpers cu_cp_routine_manager_test_helpers.cpp) -target_include_directories(cu_cp_routine_manager_test_helpers PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(cu_cp_routine_manager_test_helpers - cu_cp_test_helpers - srsran_cu_cp - e1ap_test_helpers - f1ap_test_helpers - ngap_test_helpers - rrc_ue_test_helpers - f1ap_test_doubles - srsran_support - f1ap_asn1 - srslog) - -set(SOURCES - pdu_session_resource_setup_routine_test.cpp - pdu_session_resource_release_routine_test.cpp - pdu_session_resource_modification_routine_test.cpp - ue_context_release_routine_test.cpp - ) - -add_executable(cu_cp_routine_test ${SOURCES}) -target_include_directories(cu_cp_routine_test PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(cu_cp_routine_test cu_cp_routine_manager_test_helpers srsran_support srslog gtest gtest_main) -gtest_discover_tests(cu_cp_routine_test PROPERTIES "LABELS;cu_cp_routine_test") diff --git a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp b/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp deleted file mode 100644 index 49f25da08d..0000000000 --- a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp +++ /dev/null @@ -1,63 +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_cp_routine_manager_test_helpers.h" -#include "tests/unittests/rrc/rrc_ue_test_messages.h" -#include "srsran/cu_cp/cu_cp_configuration_helpers.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -static srsran::security::sec_as_config init_security_config() -{ - const char* k_enc_cstr = "4ea96992c8c7e82977231ad001309062ae9f31ead90a4d0842af6cd25cb44dc4"; - const char* k_int_cstr = "aeeb5e0ae02c6188ecb1625c4a9e022fdfc2a1fc845b44b44443ac9a3bda667c"; - - // Pack hex strings into srsgnb types - security::sec_key k_enc = make_sec_key(k_enc_cstr); - security::sec_key k_int = make_sec_key(k_int_cstr); - - // Create expected SRB1 sec config - srsran::security::sec_as_config security_cfg; - security_cfg.domain = security::sec_domain::rrc; - security_cfg.integ_algo = security::integrity_algorithm::nia2; - security_cfg.cipher_algo = security::ciphering_algorithm::nea0; - security_cfg.k_enc = k_enc; - security_cfg.k_int = k_int; - return security_cfg; -} - -cu_cp_routine_manager_test::cu_cp_routine_manager_test() : - security_cfg(init_security_config()), cu_cp_cfg([this]() { - cu_cp_configuration cucfg = config_helpers::make_default_cu_cp_config(); - cucfg.services.timers = &timers; - cucfg.services.cu_cp_executor = &ctrl_worker; - cucfg.ue.inactivity_timer = std::chrono::seconds{10}; - pdcp_config pdcp_cfg{ - pdcp_rb_type::drb, pdcp_rlc_mode::am, {}, {}, {pdcp_sn_size::size12bits}, {pdcp_sn_size::size12bits}}; - cucfg.bearers.drb_config = {{uint_to_five_qi(9), {pdcp_cfg}}, {uint_to_five_qi(7), {pdcp_cfg}}}; - return cucfg; - }()) -{ - test_logger.set_level(srslog::basic_levels::debug); - cu_cp_logger.set_level(srslog::basic_levels::debug); - srslog::init(); - - // create routine manager - routine_mng = - std::make_unique(ue_mng, cu_cp_cfg.security.default_security_indication, cu_cp_logger); -} - -cu_cp_routine_manager_test::~cu_cp_routine_manager_test() -{ - // flush logger after each test - srslog::flush(); -} diff --git a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h b/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h deleted file mode 100644 index 448d0eca0a..0000000000 --- a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h +++ /dev/null @@ -1,53 +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 "../test_helpers.h" -#include "lib/cu_cp/routine_managers/cu_cp_routine_manager.h" -#include "lib/cu_cp/ue_manager/ue_manager_impl.h" -#include "srsran/pdcp/pdcp_config.h" -#include "srsran/ran/five_qi.h" -#include "srsran/support/executors/manual_task_worker.h" -#include - -namespace srsran { -namespace srs_cu_cp { - -/// Fixture class for DU processor creation -class cu_cp_routine_manager_test : public ::testing::Test -{ -protected: - cu_cp_routine_manager_test(); - ~cu_cp_routine_manager_test() override; - - srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); - srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP"); - - srsran::security::sec_as_config security_cfg; - - timer_manager timers; - manual_task_worker ctrl_worker{128}; - cu_cp_configuration cu_cp_cfg; - - dummy_e1ap_bearer_context_manager e1ap_bearer_ctxt_mng; - dummy_f1ap_ue_context_manager f1ap_ue_ctxt_mng; - dummy_ngap_control_message_handler ngap_control_handler; - dummy_ue_task_scheduler ue_task_sched{timers, ctrl_worker}; - ue_manager ue_mng{cu_cp_cfg}; - dummy_du_processor_rrc_ue_control_message_notifier rrc_ue_ctrl_notifier; - dummy_du_processor_rrc_ue_srb_control_notifier rrc_ue_srb_ctrl_notifier; - dummy_cu_cp_rrc_ue_interface cu_cp_notifier; - dummy_cu_cp_ue_removal_handler ue_removal_handler{&ue_mng}; - std::unique_ptr routine_mng; -}; - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp b/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp deleted file mode 100644 index 37d69d4039..0000000000 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp +++ /dev/null @@ -1,441 +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_cp_test_messages.h" -#include "cu_cp_routine_manager_test_helpers.h" -#include "pdu_session_resource_routine_test_helpers.h" -#include "srsran/support/async/async_test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -/// Note: Check if UE ID is valid is done by caller. Injection of invalid ue_index results in assertion. - -class pdu_session_resource_modification_test : public pdu_session_resource_routine_test -{ -protected: - void set_expected_results(const bearer_context_outcome_t& first_e1ap_message_outcome, - const ue_context_outcome_t& ue_context_modification_outcome, - const bearer_context_outcome_t& second_e1ap_message_outcome, - bool rrc_reconfiguration_outcome) - { - e1ap_bearer_ctxt_mng.set_first_message_outcome(first_e1ap_message_outcome); - f1ap_ue_ctxt_mng.set_ue_context_modification_outcome(ue_context_modification_outcome); - e1ap_bearer_ctxt_mng.set_second_message_outcome(second_e1ap_message_outcome); - rrc_ue_ctrl_notifier.set_rrc_reconfiguration_outcome(rrc_reconfiguration_outcome); - } - - void start_procedure(const cu_cp_pdu_session_resource_modify_request& msg) - { - t = routine_mng->start_pdu_session_resource_modification_routine( - msg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_mng.find_ue(msg.ue_index)->get_task_sched(), - ue_mng.find_ue(msg.ue_index)->get_up_resource_manager()); - t_launcher.emplace(t); - } - - bool procedure_ready() const { return t.ready(); } - - const cu_cp_pdu_session_resource_modify_response& result() { return t.get(); } - - // Preamble to setup a initial PDU session. - void setup_pdu_session(ue_index_t ue_index) - { - // Set expected results for sub-procedures. - e1ap_bearer_ctxt_mng.set_first_message_outcome({true, {1}, {}}); - f1ap_ue_ctxt_mng.set_ue_context_modification_outcome({true}); - e1ap_bearer_ctxt_mng.set_second_message_outcome({true}); - rrc_ue_ctrl_notifier.set_rrc_reconfiguration_outcome(true); - - ASSERT_FALSE(rrc_ue_ctrl_notifier.last_radio_bearer_cfg.has_value()); - ASSERT_FALSE(e1ap_bearer_ctxt_mng.first_e1ap_request.has_value()); - ASSERT_FALSE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); - - // Run setup procedure. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - async_task setup_task = - routine_mng->start_pdu_session_resource_setup_routine( - request, - security_cfg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_mng.find_ue(request.ue_index)->get_task_sched(), - ue_mng.find_ue(request.ue_index)->get_up_resource_manager()); - lazy_task_launcher setup_launcher(setup_task); - - // Verify successful outcome. - ASSERT_TRUE(setup_task.ready()); - ASSERT_EQ(setup_task.get().pdu_session_res_setup_response_items.size(), 1); - ASSERT_EQ(setup_task.get().pdu_session_res_failed_to_setup_items.size(), 0); - - // clear stored requests for next procedure - e1ap_bearer_ctxt_mng.reset(); - rrc_ue_ctrl_notifier.reset(); - } - - void - modify_pdu_session_and_add_qos_flow(ue_index_t ue_index, unsigned psi, unsigned drb_id, unsigned qfi, bool success) - { - // Set expected results for sub-procedures. - bearer_context_outcome_t first_bearer_ctxt_mod_outcome; - first_bearer_ctxt_mod_outcome.outcome = true; - first_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - first_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item; - modify_item.psi = uint_to_pdu_session_id(psi); - modify_item.drb_added = {uint_to_drb_id(drb_id)}; - first_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item); - ue_context_outcome_t ue_cxt_mod_outcome; - ue_cxt_mod_outcome.outcome = true; - ue_cxt_mod_outcome.drb_success_list = {drb_id}; // setup of DRB was ok - ue_cxt_mod_outcome.drb_failed_list = {}; - bearer_context_outcome_t second_bearer_ctxt_mod_outcome; - second_bearer_ctxt_mod_outcome.outcome = true; - second_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - second_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item2; - modify_item2.psi = uint_to_pdu_session_id(psi); - second_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item2); - set_expected_results(first_bearer_ctxt_mod_outcome, ue_cxt_mod_outcome, second_bearer_ctxt_mod_outcome, true); - - ASSERT_FALSE(rrc_ue_ctrl_notifier.last_radio_bearer_cfg.has_value()); - ASSERT_FALSE(e1ap_bearer_ctxt_mng.first_e1ap_request.has_value()); - ASSERT_FALSE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); - - // Run PDU session modification. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index, psi, qfi); - async_task modify_task = - routine_mng->start_pdu_session_resource_modification_routine( - request, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_mng.find_ue(request.ue_index)->get_task_sched(), - ue_mng.find_ue(request.ue_index)->get_up_resource_manager()); - lazy_task_launcher modify_launcher(modify_task); - - // Verify content of UE context modification. - ASSERT_EQ(f1ap_ue_ctxt_mng.get_ctxt_mod_request().drbs_to_be_setup_mod_list.size(), 1); - - // PDU session resource modification succeeded. - ASSERT_TRUE(modify_task.ready()); - if (success) { - ASSERT_EQ(modify_task.get().pdu_session_res_modify_list.size(), 1); - ASSERT_EQ(modify_task.get().pdu_session_res_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); - ASSERT_EQ(modify_task.get().pdu_session_res_failed_to_modify_list.size(), 0); - } else { - ASSERT_EQ(modify_task.get().pdu_session_res_modify_list.size(), 0); - ASSERT_EQ(modify_task.get().pdu_session_res_failed_to_modify_list.size(), 1); - ASSERT_EQ(modify_task.get().pdu_session_res_failed_to_modify_list.begin()->pdu_session_id, - uint_to_pdu_session_id(1)); - } - - // clear stored E1AP requests for next procedure - e1ap_bearer_ctxt_mng.reset(); - rrc_ue_ctrl_notifier.reset(); - } - -private: - async_task t; - std::optional> t_launcher; -}; - -TEST_F(pdu_session_resource_modification_test, - when_modification_request_with_inactive_pdu_session_arrives_then_modification_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index, 1, 1); - - // Start modification routine (without setting any results). - start_procedure(request); - - // PDU session resource modification for session 1 failed. - ASSERT_TRUE(procedure_ready()); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.size(), 1); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); -} - -TEST_F(pdu_session_resource_modification_test, when_bearer_ctxt_modification_fails_then_pdu_session_modification_fails) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Set expected results for sub-procedures. - set_expected_results({false}, {}, {}, false); - - // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index, 1, 2); - start_procedure(request); - - // Verify content of initial bearer modification request. - ASSERT_TRUE(e1ap_bearer_ctxt_mng.first_e1ap_request.has_value()); - ASSERT_TRUE(std::holds_alternative( - e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - const auto& bearer_ctxt_mod_req = - std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value()); - ASSERT_TRUE(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.has_value()); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value().pdu_session_res_to_modify_list.size(), 1); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->pdu_session_id, - uint_to_pdu_session_id(1)); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->drb_to_setup_list_ng_ran.size(), - 1); - - // PDU session resource modification for session 1 failed. - ASSERT_TRUE(procedure_ready()); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.size(), 1); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); -} - -TEST_F(pdu_session_resource_modification_test, when_ue_ctxt_modification_fails_then_pdu_session_modification_fails) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Set expected results for sub-procedures. - bearer_context_outcome_t first_bearer_ctxt_mod_outcome; - first_bearer_ctxt_mod_outcome.outcome = true; - first_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - first_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item; - modify_item.psi = uint_to_pdu_session_id(1); - modify_item.drb_added = {uint_to_drb_id(1)}; - first_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item); - set_expected_results(first_bearer_ctxt_mod_outcome, {false}, {}, false); - - // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index); - start_procedure(request); - - // Verify content of UE context modification. - ASSERT_EQ(f1ap_ue_ctxt_mng.get_ctxt_mod_request().drbs_to_be_setup_mod_list.size(), 1); - - // PDU session resource modification for session 1 failed. - ASSERT_TRUE(procedure_ready()); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.size(), 1); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); -} - -TEST_F(pdu_session_resource_modification_test, - when_second_bearer_ctxt_modification_fails_then_pdu_session_modification_fails) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Set expected results for sub-procedures. - bearer_context_outcome_t first_bearer_ctxt_mod_outcome; - first_bearer_ctxt_mod_outcome.outcome = true; - first_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - first_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item; - modify_item.psi = uint_to_pdu_session_id(1); - modify_item.drb_added = {uint_to_drb_id(2)}; - first_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item); - ue_context_outcome_t ue_cxt_mod_outcome; - ue_cxt_mod_outcome.outcome = true; - ue_cxt_mod_outcome.drb_success_list = {2}; // setup of DRB was ok - ue_cxt_mod_outcome.drb_failed_list = {}; - bearer_context_outcome_t second_bearer_ctxt_mod_outcome; - second_bearer_ctxt_mod_outcome.outcome = false; - set_expected_results(first_bearer_ctxt_mod_outcome, ue_cxt_mod_outcome, second_bearer_ctxt_mod_outcome, false); - - // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index); - start_procedure(request); - - // Verify content of 2nd bearer context modification request. - ASSERT_TRUE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); - ASSERT_TRUE(e1ap_bearer_ctxt_mng.second_e1ap_request.value().ng_ran_bearer_context_mod_request.has_value()); - ASSERT_EQ(e1ap_bearer_ctxt_mng.second_e1ap_request.value() - .ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.size(), - 1); - - // PDU session resource modification for session 1 failed. - ASSERT_TRUE(procedure_ready()); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.size(), 1); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); -} - -TEST_F(pdu_session_resource_modification_test, when_rrc_reconfiguration_fails_then_pdu_session_modification_fails) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Set expected results for sub-procedures. - bearer_context_outcome_t first_bearer_ctxt_mod_outcome; - first_bearer_ctxt_mod_outcome.outcome = true; - first_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - first_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item; - modify_item.psi = uint_to_pdu_session_id(1); - modify_item.drb_added = {uint_to_drb_id(1)}; - first_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item); - ue_context_outcome_t ue_cxt_mod_outcome; - ue_cxt_mod_outcome.outcome = true; - ue_cxt_mod_outcome.drb_success_list = {2}; // setup of DRB was ok - ue_cxt_mod_outcome.drb_failed_list = {}; - bearer_context_outcome_t second_bearer_ctxt_mod_outcome; - second_bearer_ctxt_mod_outcome.outcome = true; - second_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - second_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item2; - modify_item2.psi = uint_to_pdu_session_id(1); - second_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item2); - set_expected_results(first_bearer_ctxt_mod_outcome, ue_cxt_mod_outcome, second_bearer_ctxt_mod_outcome, false); - - // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index); - start_procedure(request); - - // Verify content of UE context modification. - ASSERT_EQ(f1ap_ue_ctxt_mng.get_ctxt_mod_request().drbs_to_be_setup_mod_list.size(), 1); - - // PDU session resource modification for session 1 failed. - ASSERT_TRUE(procedure_ready()); - ASSERT_EQ(result().pdu_session_res_modify_list.size(), 0); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.size(), 1); - ASSERT_EQ(result().pdu_session_res_failed_to_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); -} - -TEST_F(pdu_session_resource_modification_test, - when_valid_modification_arrives_and_subprocedures_succeed_then_pdu_session_modification_succeeds) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Run PDU session modification and add second QoS flow. - modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, true); -} - -TEST_F(pdu_session_resource_modification_test, - when_valid_modification_arrives_and_qos_flow_can_be_removed_then_pdu_session_modification_succeeds) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Run PDU session modification and add second QoS flow. - modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, true); - - // Test body. - - // Set expected results for sub-procedures. - bearer_context_outcome_t first_bearer_ctxt_mod_outcome; - first_bearer_ctxt_mod_outcome.outcome = true; - pdu_session_modified_outcome_t modify_item; - modify_item.psi = uint_to_pdu_session_id(1); - modify_item.drb_removed = {uint_to_drb_id(1)}; - first_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item); - - ue_context_outcome_t ue_cxt_mod_outcome; - ue_cxt_mod_outcome.outcome = true; - ue_cxt_mod_outcome.drb_removed_list = {2}; // DRB2 was removed - - bearer_context_outcome_t second_bearer_ctxt_mod_outcome; - second_bearer_ctxt_mod_outcome.outcome = true; - second_bearer_ctxt_mod_outcome.pdu_sessions_setup_list = {}; - second_bearer_ctxt_mod_outcome.pdu_sessions_failed_list = {}; - pdu_session_modified_outcome_t modify_item2; - modify_item2.psi = uint_to_pdu_session_id(1); - second_bearer_ctxt_mod_outcome.pdu_sessions_modified_list.push_back(modify_item2); - set_expected_results(first_bearer_ctxt_mod_outcome, ue_cxt_mod_outcome, second_bearer_ctxt_mod_outcome, true); - - // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = - generate_pdu_session_resource_modification_with_qos_flow_removal(uint_to_qos_flow_id(2)); - start_procedure(request); - - // Verify content of initial bearer modification request. - ASSERT_TRUE(e1ap_bearer_ctxt_mng.first_e1ap_request.has_value()); - ASSERT_TRUE(std::holds_alternative( - e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - const auto& bearer_ctxt_mod_req = - std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value()); - ASSERT_TRUE(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.has_value()); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value().pdu_session_res_to_modify_list.size(), 1); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->pdu_session_id, - uint_to_pdu_session_id(1)); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->drb_to_rem_list_ng_ran.size(), - 1); - - // Verify content of UE context modification. - ASSERT_EQ(f1ap_ue_ctxt_mng.get_ctxt_mod_request().drbs_to_be_released_list.size(), 1); - - // Verify RRC reconfig. - ASSERT_TRUE(rrc_ue_ctrl_notifier.last_radio_bearer_cfg.has_value()); - ASSERT_EQ(rrc_ue_ctrl_notifier.last_radio_bearer_cfg.value().drb_to_release_list.size(), 1); - - // PDU session resource modification for session 1 succeeded. - ASSERT_TRUE(procedure_ready()); - ASSERT_EQ(result().pdu_session_res_modify_list.size(), 1); - ASSERT_EQ(result().pdu_session_res_modify_list.begin()->pdu_session_id, uint_to_pdu_session_id(1)); -} - -TEST_F(pdu_session_resource_modification_test, when_many_qos_flows_are_added_pdu_session_modification_succeeds) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Add QoS flows until maximum number of DRBs is reached. - for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow(ue_index, 1, i, i, true); - } -} - -TEST_F(pdu_session_resource_modification_test, when_one_to_many_qos_flows_are_added_last_pdu_session_modification_fails) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Add QoS flows until maximum number of DRBs is reached. - for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow(ue_index, 1, i, i, true); - } - - // Try to add one more QoS flow but addtion should fail. - modify_pdu_session_and_add_qos_flow(ue_index, 1, MAX_NOF_DRBS + 1, MAX_NOF_DRBS + 1, false); -} - -TEST_F(pdu_session_resource_modification_test, when_valid_modification_is_received_twice_then_second_modification_fails) -{ - // Test Preamble - Setup a single PDU session initially. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - // Run PDU session modification and add second QoS flow. - modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, true); - - // Run PDU session modification again and try to add same QoS flow. - modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, false); -} diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp b/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp deleted file mode 100644 index 4be3a44cc7..0000000000 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp +++ /dev/null @@ -1,176 +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_cp_test_messages.h" -#include "cu_cp_routine_manager_test_helpers.h" -#include "pdu_session_resource_routine_test_helpers.h" -#include "srsran/support/async/async_test_utils.h" -#include "srsran/support/test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -/// Note: Check if UE ID is valid is done by caller. Injection of invalid ue_index results in assertion. - -class pdu_session_resource_release_test : public pdu_session_resource_routine_test -{ -protected: - void start_procedure(const cu_cp_pdu_session_resource_release_command& msg, - ue_context_outcome_t ue_context_modification_outcome, - bearer_context_outcome_t bearer_context_modification_outcome) - { - f1ap_ue_ctxt_mng.set_ue_context_modification_outcome(ue_context_modification_outcome); - e1ap_bearer_ctxt_mng.set_second_message_outcome(bearer_context_modification_outcome); - - t = routine_mng->start_pdu_session_resource_release_routine( - msg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_task_sched, - ue_mng.find_ue(msg.ue_index)->get_up_resource_manager()); - t_launcher.emplace(t); - } - - bool was_pdu_session_resource_release_successful() const - { - if (not t.ready()) { - return false; - } - - if (t.get().released_pdu_sessions.size() == 0) { - return false; - } - - return true; - } - - bool was_bearer_context_release_command_sent() const - { - return e1ap_bearer_ctxt_mng.last_release_command.ue_index != ue_index_t::invalid; - } - - void setup_pdu_session(ue_index_t ue_index) - { - // Setup single PDU session. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - std::optional> setup_launcher; - - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - - // Expected results - e1ap_bearer_ctxt_mng.set_first_message_outcome(bearer_context_setup_outcome); - f1ap_ue_ctxt_mng.set_ue_context_modification_outcome(ue_context_modification_outcome); - e1ap_bearer_ctxt_mng.set_second_message_outcome(bearer_context_modification_outcome); - rrc_ue_ctrl_notifier.set_rrc_reconfiguration_outcome(true); - - async_task setup_task = - routine_mng->start_pdu_session_resource_setup_routine( - request, - security_cfg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_mng.find_ue(request.ue_index)->get_task_sched(), - ue_mng.find_ue(request.ue_index)->get_up_resource_manager()); - setup_launcher.emplace(setup_task); - } - - async_task t; - std::optional> t_launcher; -}; - -TEST_F(pdu_session_resource_release_test, when_ue_context_modification_failure_received_then_release_succeeds) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); - - // Start PDU SESSION RESOURCE RELEASE routine. - bearer_context_outcome_t bearer_context_modification_outcome{false}; - this->start_procedure(command, {true}, bearer_context_modification_outcome); - - // nothing has failed to be release - ASSERT_TRUE(was_pdu_session_resource_release_successful()); -} - -TEST_F(pdu_session_resource_release_test, when_bearer_context_modification_failure_received_then_release_succeeds) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); - - // Start PDU SESSION RESOURCE RELEASE routine. - bearer_context_outcome_t bearer_context_modification_outcome{true}; - this->start_procedure(command, {true}, bearer_context_modification_outcome); - - // nothing has failed to setup - ASSERT_TRUE(was_pdu_session_resource_release_successful()); -} - -/// Test handling of PDU session release command without any release item. -TEST_F(pdu_session_resource_release_test, when_empty_pdu_session_release_command_received_then_release_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_release_command command = {}; // empty message - command.ue_index = ue_index; - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_modification_outcome{true}; - this->start_procedure(command, {true}, bearer_context_modification_outcome); - - // it should be ready immediately - ASSERT_TRUE(t.ready()); - - // Nothing has been set up or failed - ASSERT_FALSE(was_pdu_session_resource_release_successful()); -} - -TEST_F(pdu_session_resource_release_test, when_all_sub_actions_succeed_then_release_succeeds) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); - - // Start PDU SESSION RESOURCE RELEASE routine. - start_procedure(command, {true}, {true}); - - // All released. - ASSERT_TRUE(was_pdu_session_resource_release_successful()); -} - -TEST_F(pdu_session_resource_release_test, when_only_pdu_session_released_then_bearer_context_release_command_sent) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - setup_pdu_session(ue_index); - - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); - - // Start PDU SESSION RESOURCE RELEASE routine. - start_procedure(command, {true}, {true}); - - ASSERT_TRUE(was_bearer_context_release_command_sent()); - - // All released. - ASSERT_TRUE(was_pdu_session_resource_release_successful()); -} \ No newline at end of file diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_routine_test_helpers.h b/tests/unittests/cu_cp/routines/pdu_session_resource_routine_test_helpers.h deleted file mode 100644 index 2877646928..0000000000 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_routine_test_helpers.h +++ /dev/null @@ -1,92 +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 "../../e1ap/common/test_helpers.h" -#include "../cu_cp_test_helpers.h" -#include "cu_cp_routine_manager_test_helpers.h" -#include "lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h" -#include "lib/f1ap/cu_cp/f1ap_asn1_helpers.h" -#include "srsran/f1ap/common/f1ap_message.h" -#include "srsran/support/test_utils.h" -#include - -namespace srsran { -namespace srs_cu_cp { - -// Helper function to verify that two lists are identical. -template -void VERIFY_EQUAL(const T& result, const T& expected) -{ - ASSERT_EQ(result.size(), expected.size()); - ASSERT_TRUE(std::equal(result.begin(), result.end(), expected.begin())); -} - -class pdu_session_resource_routine_test : public cu_cp_routine_manager_test -{ -protected: - void is_valid_f1ap_message(const f1ap_ue_context_modification_request& request) - { - f1ap_message f1ap_msg; - f1ap_msg.pdu.set_init_msg().load_info_obj(ASN1_F1AP_ID_UE_CONTEXT_MOD); - auto& ctx_mod = f1ap_msg.pdu.init_msg().value.ue_context_mod_request(); - - fill_asn1_ue_context_modification_request(ctx_mod, request); - - ctx_mod->gnb_du_ue_f1ap_id = 0; - ctx_mod->gnb_cu_ue_f1ap_id = 1; - - byte_buffer packed_pdu; - asn1::bit_ref bref(packed_pdu); - ASSERT_EQ(f1ap_msg.pdu.pack(bref), asn1::SRSASN_SUCCESS); - } - - void is_valid_e1ap_message(const e1ap_bearer_context_modification_request& request) - { - e1ap_message e1ap_msg; - e1ap_msg.pdu.set_init_msg(); - e1ap_msg.pdu.init_msg().load_info_obj(ASN1_E1AP_ID_BEARER_CONTEXT_MOD); - - auto& bearer_context_mod_request = e1ap_msg.pdu.init_msg().value.bearer_context_mod_request(); - bearer_context_mod_request->gnb_cu_cp_ue_e1ap_id = - gnb_cu_cp_ue_e1ap_id_to_uint(generate_random_gnb_cu_cp_ue_e1ap_id()); - bearer_context_mod_request->gnb_cu_up_ue_e1ap_id = - gnb_cu_up_ue_e1ap_id_to_uint(generate_random_gnb_cu_up_ue_e1ap_id()); - - fill_asn1_bearer_context_modification_request(bearer_context_mod_request, request); - - byte_buffer packed_pdu; - asn1::bit_ref bref(packed_pdu); - ASSERT_EQ(e1ap_msg.pdu.pack(bref), asn1::SRSASN_SUCCESS); - } - - void is_valid_e1ap_message(const e1ap_bearer_context_setup_request& request) - { - e1ap_message e1ap_msg; - e1ap_msg.pdu.set_init_msg(); - e1ap_msg.pdu.init_msg().load_info_obj(ASN1_E1AP_ID_BEARER_CONTEXT_SETUP); - - auto& bearer_context_setup_request = e1ap_msg.pdu.init_msg().value.bearer_context_setup_request(); - bearer_context_setup_request->gnb_cu_cp_ue_e1ap_id = - gnb_cu_cp_ue_e1ap_id_to_uint(generate_random_gnb_cu_cp_ue_e1ap_id()); - bearer_context_setup_request->gnb_cu_up_ue_e1ap_id = - gnb_cu_up_ue_e1ap_id_to_uint(generate_random_gnb_cu_up_ue_e1ap_id()); - - fill_asn1_bearer_context_setup_request(bearer_context_setup_request, request); - - byte_buffer packed_pdu; - asn1::bit_ref bref(packed_pdu); - ASSERT_EQ(e1ap_msg.pdu.pack(bref), asn1::SRSASN_SUCCESS); - } -}; - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp b/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp deleted file mode 100644 index b061741e6f..0000000000 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp +++ /dev/null @@ -1,516 +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_cp_test_messages.h" -#include "cu_cp_routine_manager_test_helpers.h" -#include "pdu_session_resource_routine_test_helpers.h" -#include "srsran/support/async/async_test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -/// Note: Check if UE ID is valid is done by caller. Injection of invalid ue_index results in assertion. - -class pdu_session_resource_setup_test : public pdu_session_resource_routine_test -{ -protected: - void set_expected_results(const bearer_context_outcome_t& first_e1ap_message_outcome, - const ue_context_outcome_t& ue_context_modification_outcome, - const bearer_context_outcome_t& second_e1ap_message_outcome, - bool rrc_reconfiguration_outcome) - { - e1ap_bearer_ctxt_mng.set_first_message_outcome(first_e1ap_message_outcome); - f1ap_ue_ctxt_mng.set_ue_context_modification_outcome(ue_context_modification_outcome); - e1ap_bearer_ctxt_mng.set_second_message_outcome(second_e1ap_message_outcome); - rrc_ue_ctrl_notifier.set_rrc_reconfiguration_outcome(rrc_reconfiguration_outcome); - } - - void start_procedure(const cu_cp_pdu_session_resource_setup_request& msg) - { - t = routine_mng->start_pdu_session_resource_setup_routine(msg, - security_cfg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_mng.find_ue(msg.ue_index)->get_task_sched(), - ue_mng.find_ue(msg.ue_index)->get_up_resource_manager()); - t_launcher.emplace(t); - } - - bool procedure_ready() const { return t.ready(); } - - // Return SRB IDs that were requested to be added/modified in RRC reconfiguration. - std::list rrc_srbs_to_add_mod_in_reconf() - { - std::list srb_list = {}; - if (not rrc_ue_ctrl_notifier.last_radio_bearer_cfg.has_value()) { - return srb_list; - } - for (const auto& item : rrc_ue_ctrl_notifier.last_radio_bearer_cfg->srb_to_add_mod_list) { - srb_list.push_back(srb_id_to_uint(item.srb_id)); - } - return srb_list; - } - - // Return PDU session IDs that failed to be setup. - std::list pdu_session_res_failed_to_setup() - { - std::list failed_list; - for (const auto& item : t.get().pdu_session_res_failed_to_setup_items) { - failed_list.push_back(pdu_session_id_to_uint(item.pdu_session_id)); - } - return failed_list; - } - - // Return PDU session IDs that succeeded to be setup. - std::list pdu_session_res_setup() - { - std::list setup_list; - for (const auto& item : t.get().pdu_session_res_setup_response_items) { - setup_list.push_back(pdu_session_id_to_uint(item.pdu_session_id)); - } - return setup_list; - } - -private: - async_task t; - std::optional> t_launcher; -}; - -TEST_F(pdu_session_resource_setup_test, when_pdu_session_setup_request_with_unconfigured_fiveqi_received_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - // Tweak 5QI of first QoS flow - request.pdu_session_res_setup_items.begin() - ->qos_flow_setup_request_items.begin() - ->qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi.value() - .five_qi = uint_to_five_qi(99); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{false, {}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{false}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - - // it should be ready immediately - start_procedure(request); - - // nothing has failed to setup - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {1}); - - // SRB2 should not be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); -} - -TEST_F(pdu_session_resource_setup_test, when_bearer_context_setup_failure_received_then_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{false, {}, {}}; - bearer_context_outcome_t bearer_context_modification_outcome{false}; - set_expected_results(bearer_context_setup_outcome, {false}, bearer_context_modification_outcome, false); - - start_procedure(request); - - // PDU session resource setup failed. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {1}); - - // SRB2 should not be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); -} - -TEST_F(pdu_session_resource_setup_test, when_ue_context_modification_failure_received_then_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; - bearer_context_outcome_t bearer_context_modification_outcome{false}; - set_expected_results(bearer_context_setup_outcome, {false}, bearer_context_modification_outcome, false); - start_procedure(request); - - // PDU session resource setup failed. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {1}); - - // SRB2 should not be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); -} - -TEST_F(pdu_session_resource_setup_test, when_bearer_context_modification_failure_received_then_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true, {1}}; - bearer_context_outcome_t bearer_context_modification_outcome{false, {}, {1}}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, false); - start_procedure(request); - - // Verify content of bearer modification request. - ASSERT_TRUE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); - const auto& bearer_ctxt_mod_req = e1ap_bearer_ctxt_mng.second_e1ap_request.value(); - ASSERT_TRUE(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.has_value()); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value().pdu_session_res_to_modify_list.size(), 1); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->pdu_session_id, - uint_to_pdu_session_id(1)); - ASSERT_EQ(bearer_ctxt_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->drb_to_modify_list_ng_ran.size(), - 1); - - // PDU session resource setup failed. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {1}); - - // SRB2 should not be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); -} - -TEST_F(pdu_session_resource_setup_test, when_rrc_reconfiguration_fails_then_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, false); - start_procedure(request); - - // PDU session resource setup failed. - VERIFY_EQUAL(pdu_session_res_setup(), {}); - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {1}); -} - -TEST_F(pdu_session_resource_setup_test, when_rrc_reconfiguration_succeeds_then_setup_succeeds) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - - start_procedure(request); - - // Verify validity of Bearer context setup. - is_valid_e1ap_message(std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - - // Verify content of UE context modification which should include the setup of DRB1. - const auto& ue_ctxt_mod_req = f1ap_ue_ctxt_mng.get_ctxt_mod_request(); - ASSERT_EQ(ue_ctxt_mod_req.drbs_to_be_setup_mod_list.size(), 1); - ASSERT_EQ(ue_ctxt_mod_req.drbs_to_be_setup_mod_list.begin()->drb_id, uint_to_drb_id(1)); - ASSERT_EQ(ue_ctxt_mod_req.drbs_to_be_setup_mod_list.begin()->qos_info.flows_mapped_to_drb_list.size(), 1); - - // Verify generated messages can be packed into valid ASN.1 encoded messages - is_valid_f1ap_message(f1ap_ue_ctxt_mng.get_ctxt_mod_request()); - - // Verify content of Bearer modification request. - ASSERT_TRUE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); - const auto& bearer_context_mod_req = e1ap_bearer_ctxt_mng.second_e1ap_request.value(); - ASSERT_TRUE(bearer_context_mod_req.ng_ran_bearer_context_mod_request.has_value()); - // The second bearer context modification includes a PDU session modification, but no setup. - ASSERT_EQ(bearer_context_mod_req.ng_ran_bearer_context_mod_request.value().pdu_session_res_to_modify_list.size(), 1); - ASSERT_EQ(bearer_context_mod_req.ng_ran_bearer_context_mod_request.value().pdu_session_res_to_setup_mod_list.size(), - 0); - - // nothing has failed to setup - VERIFY_EQUAL(pdu_session_res_setup(), {1}); - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {}); - - // SRB2 should be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {2}); -} - -TEST_F(pdu_session_resource_setup_test, when_pdu_session_setup_for_existing_session_arrives_then_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - start_procedure(request); - - // nothing has failed to setup - VERIFY_EQUAL(pdu_session_res_setup(), {1}); - - // SRB2 should be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {2}); - - // Reset stored SRB information - rrc_ue_ctrl_notifier.reset(); - - // Inject same PDU session resource setup again. - start_procedure(request); - - // 2nd setup attempt failed. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {1}); - - // SRB2 should not be setup now - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); -} - -/// Test handling of PDU session setup request without any setup item. -TEST_F(pdu_session_resource_setup_test, when_empty_pdu_session_setup_request_received_then_setup_fails) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = {}; // empty message - request.ue_index = ue_index; - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {}, {}}; - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - start_procedure(request); - - // it should be ready immediately - ASSERT_TRUE(procedure_ready()); - - // Empy success and fail list. - VERIFY_EQUAL(pdu_session_res_setup(), {}); - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {}); - - // SRB2 should not be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); -} - -/// One PDU session with two QoS flows. -TEST_F(pdu_session_resource_setup_test, when_setup_for_pdu_sessions_with_two_qos_flows_received_setup_succeeds) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 1, 2); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; // first session success, second failed - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - start_procedure(request); - - // it should be ready immediately - ASSERT_TRUE(procedure_ready()); - - // Verify Bearer Context Setup request for two DRBs with one QoS flow each. - ASSERT_TRUE( - std::holds_alternative(e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - const auto& context_setup_req = - std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value()); - ASSERT_EQ(context_setup_req.pdu_session_res_to_setup_list.size(), 1); - ASSERT_EQ(context_setup_req.pdu_session_res_to_setup_list.begin()->drb_to_setup_list_ng_ran.size(), 2); - ASSERT_EQ(context_setup_req.pdu_session_res_to_setup_list.begin() - ->drb_to_setup_list_ng_ran.begin() - ->qos_flow_info_to_be_setup.size(), - 1); - - // Failed list empty. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {}); - - // One PDU session succeeded to be setup. - VERIFY_EQUAL(pdu_session_res_setup(), {1}); - - // One SRB2 should be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {2}); -} - -/// Test with multiple PDU sessions in same request. -TEST_F(pdu_session_resource_setup_test, - when_setup_for_two_pdu_sessions_is_requested_but_only_first_could_be_setup_at_cuup_setup_succeeds_with_fail_list) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 2, 1); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {2}}; // first session success, second failed - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - this->start_procedure(request); - - // it should be ready immediately - ASSERT_TRUE(procedure_ready()); - - // One PDU session succeeded to be setup. - VERIFY_EQUAL(pdu_session_res_setup(), {1}); - - // One PDU session failed to be setup. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {2}); - - // One SRB2 should be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {2}); -} - -TEST_F(pdu_session_resource_setup_test, when_setup_for_two_pdu_sessions_is_requested_and_both_succeed_setup_succeeds) -{ - // Test Preamble. - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 2, 1); - - // Start PDU SESSION RESOURCE SETUP routine. - bearer_context_outcome_t bearer_context_setup_outcome{true, {1, 2}, {}}; // first session success, second failed - ue_context_outcome_t ue_context_modification_outcome{true}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - start_procedure(request); - - // it should be ready immediately - ASSERT_TRUE(procedure_ready()); - - // Two PDU session succeeded to be setup. - VERIFY_EQUAL(pdu_session_res_setup(), {1, 2}); - - // Zero PDU session failed to be setup. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {}); - - // One SRB2 should be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {2}); -} - -/// Test with two consecutive requests. Both with one PDU session. -TEST_F(pdu_session_resource_setup_test, when_two_consecutive_setups_arrive_bearer_setup_and_modification_succeed) -{ - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - - // Initial PDU SESSION RESOURCE SETUP procdure using default executor. - { - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 1); - - bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; // PDU session 1 setup success, no failure - ue_context_outcome_t ue_context_modification_outcome{true, {1}}; - bearer_context_outcome_t bearer_context_modification_outcome{true}; - set_expected_results( - bearer_context_setup_outcome, ue_context_modification_outcome, bearer_context_modification_outcome, true); - - // it should be ready immediately - start_procedure(request); - ASSERT_TRUE(procedure_ready()); - - // Failed list empty. - VERIFY_EQUAL(pdu_session_res_failed_to_setup(), {}); - - // First PDU session setup succeeded. - VERIFY_EQUAL(pdu_session_res_setup(), {1}); - - // One SRB2 should be setup - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {2}); - - // Verify generated messages can be packed into valid ASN.1 encoded messages - is_valid_e1ap_message(std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - is_valid_e1ap_message(e1ap_bearer_ctxt_mng.second_e1ap_request.value()); - } - - // clear stored E1AP requests/RRC reconf for next procedure - e1ap_bearer_ctxt_mng.reset(); - rrc_ue_ctrl_notifier.reset(); - - { - // Generate 2nd request for different PDU session ID (we generate a request for two sessions and delete the first) - // ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - cu_cp_pdu_session_resource_setup_request request2 = generate_pdu_session_resource_setup(ue_index, 2); - request2.pdu_session_res_setup_items.erase(uint_to_pdu_session_id(1)); - - // Modify 5QI such that a new DRB is going to be created. - request2.pdu_session_res_setup_items[uint_to_pdu_session_id(2)] - .qos_flow_setup_request_items.begin() - ->qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi.value() - .five_qi = uint_to_five_qi(7); - - bearer_context_outcome_t first_bearer_context_modification_outcome{ - true, {2}, {}}; // PDU session 2 setup success, no failure - ue_context_outcome_t ue_context_modification_outcome{true, {2}}; - bearer_context_outcome_t second_bearer_context_modification_outcome{true, {2}}; // Modification for DRB2 - - set_expected_results(first_bearer_context_modification_outcome, - ue_context_modification_outcome, - second_bearer_context_modification_outcome, - true); - - start_procedure(request2); - ASSERT_TRUE(procedure_ready()); - - // Verify content of first bearer context modifications which should be the setup of a new PDU session. - ASSERT_TRUE(std::holds_alternative( - e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - const auto& context_mod_req = - std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value()) - .ng_ran_bearer_context_mod_request; - ASSERT_TRUE(context_mod_req.has_value()); - ASSERT_EQ(context_mod_req.value().pdu_session_res_to_setup_mod_list.size(), 1); - ASSERT_EQ(context_mod_req.value().pdu_session_res_to_modify_list.size(), 0); - - // Verify generated messages can be packed into valid ASN.1 encoded messages - is_valid_e1ap_message( - std::get(e1ap_bearer_ctxt_mng.first_e1ap_request.value())); - - // Verify content of UE context modification which should include the setup of DRB2. - const auto& ue_ctxt_mod_req = f1ap_ue_ctxt_mng.get_ctxt_mod_request(); - ASSERT_EQ(ue_ctxt_mod_req.drbs_to_be_setup_mod_list.size(), 1); - ASSERT_EQ(ue_ctxt_mod_req.drbs_to_be_setup_mod_list.begin()->drb_id, uint_to_drb_id(2)); - - // Verify content of second bearer modification request. - ASSERT_TRUE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); - const auto& second_context_mod_req = e1ap_bearer_ctxt_mng.second_e1ap_request.value(); - ASSERT_TRUE(second_context_mod_req.ng_ran_bearer_context_mod_request.has_value()); - // The second bearer context modification includes a PDU session modification again. - ASSERT_EQ(second_context_mod_req.ng_ran_bearer_context_mod_request.value().pdu_session_res_to_modify_list.size(), - 1); - ASSERT_EQ(second_context_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->pdu_session_id, - uint_to_pdu_session_id(2)); - ASSERT_EQ(second_context_mod_req.ng_ran_bearer_context_mod_request.value() - .pdu_session_res_to_modify_list.begin() - ->drb_to_modify_list_ng_ran.size(), - 1); - - // Verify generated messages can be packed into valid ASN.1 encoded messages - is_valid_e1ap_message(e1ap_bearer_ctxt_mng.second_e1ap_request.value()); - - // PDU session setup for ID=2 succeeded. - VERIFY_EQUAL(pdu_session_res_setup(), {2}); - - // SRB2 should not be setup again - VERIFY_EQUAL(rrc_srbs_to_add_mod_in_reconf(), {}); - } -} diff --git a/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp b/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp deleted file mode 100644 index 304b49c18b..0000000000 --- a/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp +++ /dev/null @@ -1,77 +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_cp_test_messages.h" -#include "cu_cp_routine_manager_test_helpers.h" -#include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/support/async/async_test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -class ue_context_release_test : public cu_cp_routine_manager_test -{ -protected: - void start_procedure(const cu_cp_ue_context_release_command& msg, - ue_context_outcome_t ue_context_modification_outcome, - bearer_context_outcome_t bearer_context_modification_outcome) - { - f1ap_ue_ctxt_mng.set_ue_context_modification_outcome(ue_context_modification_outcome); - e1ap_bearer_ctxt_mng.set_second_message_outcome(bearer_context_modification_outcome); - - t = routine_mng->start_ue_context_release_routine(msg, &e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, ue_removal_handler); - t_launcher.emplace(t); - } - - ue_index_t add_ue(pci_t pci, rnti_t c_rnti) - { - ue_index_t ue_index = ue_mng.add_ue(du_index_t::min, int_to_gnb_du_id(0), pci, c_rnti, du_cell_index_t::min); - cu_cp_ue* ue = ue_mng.find_ue(ue_index); - // Set parameters from creation message - ue->set_rrc_ue_notifier(rrc_ue_ctrl_notifier); - ue->set_rrc_ue_srb_notifier(rrc_ue_srb_ctrl_notifier); - - return ue_index; - } - - bool was_ue_context_release_successful() - { - if (not t.ready()) { - return false; - } - - if (t.get().ue_index == ue_index_t::invalid) { - return false; - } - - if (ue_mng.get_nof_ues() != 0) { - return false; - } - - return true; - } - - async_task t; - std::optional> t_launcher; -}; - -TEST_F(ue_context_release_test, when_ue_context_release_command_received_then_release_succeeds) -{ - // Add UE - ue_index_t ue_index = add_ue(MIN_PCI, rnti_t::MIN_CRNTI); - - // Generate UE context release command message - cu_cp_ue_context_release_command ue_context_release_command = generate_ue_context_release_command(ue_index); - this->start_procedure(ue_context_release_command, {true}, {true}); - - // nothing has failed to be released - ASSERT_TRUE(was_ue_context_release_successful()); -} diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index a6adf6cd2a..529ecc3d1d 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -128,8 +128,11 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set return request; } -e1ap_message srsran::srs_cu_cp::generate_bearer_context_setup_response(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id) +e1ap_message srsran::srs_cu_cp::generate_bearer_context_setup_response( + gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::map& pdu_sessions_to_add, + const std::vector& pdu_sessions_to_fail) { e1ap_message bearer_context_setup_response = {}; @@ -145,34 +148,49 @@ e1ap_message srsran::srs_cu_cp::generate_bearer_context_setup_response(gnb_cu_cp auto& ng_ran_bearer_context_setup_resp = bearer_context_setup_resp->sys_bearer_context_setup_resp.ng_ran_bearer_context_setup_resp(); - asn1::e1ap::pdu_session_res_setup_item_s pdu_session_res_setup_item = {}; - pdu_session_res_setup_item.pdu_session_id = 1; - - pdu_session_res_setup_item.ng_dl_up_tnl_info.set_gtp_tunnel(); - auto& gtp_tunnel = pdu_session_res_setup_item.ng_dl_up_tnl_info.gtp_tunnel(); - gtp_tunnel.transport_layer_address.from_number(2887058953); - gtp_tunnel.gtp_teid.from_string("00000283"); - - asn1::e1ap::drb_setup_item_ng_ran_s drb_setup_item_ng_ran = {}; - drb_setup_item_ng_ran.drb_id = 1; - - asn1::e1ap::up_params_item_s up_params_item = {}; - up_params_item.up_tnl_info.set_gtp_tunnel(); - auto& gtp_tunnel2 = up_params_item.up_tnl_info.gtp_tunnel(); - gtp_tunnel2.transport_layer_address.from_number(2887058953); - gtp_tunnel2.gtp_teid.from_string("80000283"); - up_params_item.cell_group_id = 0; - drb_setup_item_ng_ran.ul_up_transport_params.push_back(up_params_item); - - asn1::e1ap::qos_flow_item_s qo_s_flow_item = {}; - qo_s_flow_item.qos_flow_id = 1; - drb_setup_item_ng_ran.flow_setup_list.push_back(qo_s_flow_item); - - pdu_session_res_setup_item.drb_setup_list_ng_ran.push_back(drb_setup_item_ng_ran); - - ng_ran_bearer_context_setup_resp.pdu_session_res_setup_list.push_back(pdu_session_res_setup_item); - - ng_ran_bearer_context_setup_resp.pdu_session_res_failed_list_present = false; + for (const auto& [psi, drb_params] : pdu_sessions_to_add) { + asn1::e1ap::pdu_session_res_setup_item_s pdu_session_res_setup_item = {}; + pdu_session_res_setup_item.pdu_session_id = pdu_session_id_to_uint(psi); + + pdu_session_res_setup_item.ng_dl_up_tnl_info.set_gtp_tunnel(); + auto& gtp_tunnel = pdu_session_res_setup_item.ng_dl_up_tnl_info.gtp_tunnel(); + gtp_tunnel.transport_layer_address.from_number(2887058953); + gtp_tunnel.gtp_teid.from_string("00000283"); + + asn1::e1ap::drb_setup_item_ng_ran_s drb_setup_item_ng_ran = {}; + { + drb_setup_item_ng_ran.drb_id = drb_id_to_uint(drb_params.drb_id); + + asn1::e1ap::up_params_item_s up_params_item = {}; + { + up_params_item.up_tnl_info.set_gtp_tunnel(); + auto& gtp_tunnel2 = up_params_item.up_tnl_info.gtp_tunnel(); + gtp_tunnel2.transport_layer_address.from_number(2887058953); + gtp_tunnel2.gtp_teid.from_string("80000283"); + up_params_item.cell_group_id = 0; + } + drb_setup_item_ng_ran.ul_up_transport_params.push_back(up_params_item); + + asn1::e1ap::qos_flow_item_s qo_s_flow_item = {}; + { + qo_s_flow_item.qos_flow_id = qos_flow_id_to_uint(drb_params.qos_flow_id); + } + drb_setup_item_ng_ran.flow_setup_list.push_back(qo_s_flow_item); + } + pdu_session_res_setup_item.drb_setup_list_ng_ran.push_back(drb_setup_item_ng_ran); + + ng_ran_bearer_context_setup_resp.pdu_session_res_setup_list.push_back(pdu_session_res_setup_item); + } + + ng_ran_bearer_context_setup_resp.pdu_session_res_failed_list_present = !pdu_sessions_to_fail.empty(); + for (const auto& psi : pdu_sessions_to_fail) { + asn1::e1ap::pdu_session_res_failed_item_s pdu_session_res_failed_item = {}; + pdu_session_res_failed_item.pdu_session_id = pdu_session_id_to_uint(psi); + pdu_session_res_failed_item.cause.set_radio_network(); + pdu_session_res_failed_item.cause.radio_network() = asn1::e1ap::cause_radio_network_opts::options::unspecified; + + ng_ran_bearer_context_setup_resp.pdu_session_res_failed_list.push_back(pdu_session_res_failed_item); + } return bearer_context_setup_response; } @@ -204,8 +222,11 @@ srsran::srs_cu_cp::generate_bearer_context_modification_request(ue_index_t ue_in return request; } -e1ap_message srsran::srs_cu_cp::generate_bearer_context_modification_response(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id) +e1ap_message srsran::srs_cu_cp::generate_bearer_context_modification_response( + gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::map& pdu_sessions_to_add, + const std::map& pdu_sessions_to_modify) { e1ap_message bearer_context_modification_response = {}; @@ -221,19 +242,55 @@ e1ap_message srsran::srs_cu_cp::generate_bearer_context_modification_response(gn auto& ng_ran_bearer_context_mod_resp = bearer_context_mod_resp->sys_bearer_context_mod_resp.ng_ran_bearer_context_mod_resp(); - ng_ran_bearer_context_mod_resp.pdu_session_res_modified_list_present = true; - - asn1::e1ap::pdu_session_res_modified_item_s pdu_session_res_modified_item = {}; - asn1::e1ap::drb_modified_item_ng_ran_s drb_modified_item_ng_ran; - drb_modified_item_ng_ran.drb_id = 1; - asn1::e1ap::up_params_item_s up_params_item = {}; - auto& gtp_tunnel = up_params_item.up_tnl_info.set_gtp_tunnel(); - gtp_tunnel.transport_layer_address.from_number(2887058953); - gtp_tunnel.gtp_teid.from_string("80000283"); - up_params_item.cell_group_id = 0; - drb_modified_item_ng_ran.ul_up_transport_params.push_back(up_params_item); - pdu_session_res_modified_item.drb_modified_list_ng_ran.push_back(drb_modified_item_ng_ran); - ng_ran_bearer_context_mod_resp.pdu_session_res_modified_list.push_back(pdu_session_res_modified_item); + + ng_ran_bearer_context_mod_resp.pdu_session_res_setup_mod_list_present = !pdu_sessions_to_add.empty(); + for (const auto& [psi, drb_params] : pdu_sessions_to_add) { + asn1::e1ap::pdu_session_res_setup_mod_item_s pdu_session_res_setup_mod_item = {}; + pdu_session_res_setup_mod_item.pdu_session_id = pdu_session_id_to_uint(psi); + + auto& dl_gtp_tunnel = pdu_session_res_setup_mod_item.ng_dl_up_tnl_info.set_gtp_tunnel(); + dl_gtp_tunnel.transport_layer_address.from_number(2887058953); + dl_gtp_tunnel.gtp_teid.from_string("80000283"); + + asn1::e1ap::drb_setup_mod_item_ng_ran_s drb_setup_mod_item_ng_ran; + { + drb_setup_mod_item_ng_ran.drb_id = drb_id_to_uint(drb_params.drb_id); + + asn1::e1ap::up_params_item_s up_params_item = {}; + { + auto& gtp_tunnel = up_params_item.up_tnl_info.set_gtp_tunnel(); + gtp_tunnel.transport_layer_address.from_number(2887058953); + gtp_tunnel.gtp_teid.from_string("80000283"); + up_params_item.cell_group_id = 0; + } + drb_setup_mod_item_ng_ran.ul_up_transport_params.push_back(up_params_item); + + asn1::e1ap::qos_flow_item_s flow_item = {}; + { + flow_item.qos_flow_id = qos_flow_id_to_uint(drb_params.qos_flow_id); + } + drb_setup_mod_item_ng_ran.flow_setup_list.push_back(flow_item); + } + pdu_session_res_setup_mod_item.drb_setup_mod_list_ng_ran.push_back(drb_setup_mod_item_ng_ran); + + ng_ran_bearer_context_mod_resp.pdu_session_res_setup_mod_list.push_back(pdu_session_res_setup_mod_item); + } + + ng_ran_bearer_context_mod_resp.pdu_session_res_modified_list_present = !pdu_sessions_to_modify.empty(); + for (const auto& [psi, drb_id] : pdu_sessions_to_modify) { + asn1::e1ap::pdu_session_res_modified_item_s pdu_session_res_modified_item = {}; + pdu_session_res_modified_item.pdu_session_id = pdu_session_id_to_uint(psi); + asn1::e1ap::drb_modified_item_ng_ran_s drb_modified_item_ng_ran; + drb_modified_item_ng_ran.drb_id = drb_id_to_uint(drb_id); + asn1::e1ap::up_params_item_s up_params_item = {}; + auto& gtp_tunnel = up_params_item.up_tnl_info.set_gtp_tunnel(); + gtp_tunnel.transport_layer_address.from_number(2887058953); + gtp_tunnel.gtp_teid.from_string("80000283"); + up_params_item.cell_group_id = 0; + drb_modified_item_ng_ran.ul_up_transport_params.push_back(up_params_item); + pdu_session_res_modified_item.drb_modified_list_ng_ran.push_back(drb_modified_item_ng_ran); + ng_ran_bearer_context_mod_resp.pdu_session_res_modified_list.push_back(pdu_session_res_modified_item); + } return bearer_context_modification_response; } diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h index e61774adb5..064208fb7c 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h @@ -13,6 +13,8 @@ #include "srsran/asn1/e1ap/e1ap_pdu_contents.h" #include "srsran/e1ap/common/e1ap_message.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" +#include "srsran/ran/cu_types.h" +#include "srsran/ran/lcid.h" namespace srsran { namespace srs_cu_cp { @@ -40,10 +42,19 @@ e1ap_message generate_cu_up_e1_setup_respose(unsigned transaction_id); /// \return The Bearer Context Setup Request. e1ap_bearer_context_setup_request generate_bearer_context_setup_request(ue_index_t ue_index); +struct drb_test_params { + drb_id_t drb_id; + qos_flow_id_t qos_flow_id; +}; + /// \brief Generate a dummy Bearer Context Setup Response. /// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. -e1ap_message generate_bearer_context_setup_response(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id); +e1ap_message +generate_bearer_context_setup_response(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::map& pdu_sessions_to_add = + {{uint_to_pdu_session_id(1), {drb_id_t::drb1, uint_to_qos_flow_id(1)}}}, + const std::vector& pdu_sessions_to_fail = {}); /// \brief Generate a dummy Bearer Context Setup Failure. /// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. @@ -60,8 +71,11 @@ e1ap_bearer_context_modification_request generate_bearer_context_modification_re /// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. /// \param[in] cu_up_ue_e1ap_id The CU-UP UE E1AP ID. /// \return The Bearer Context Modification Response. -e1ap_message generate_bearer_context_modification_response(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id); +e1ap_message generate_bearer_context_modification_response( + gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::map& pdu_sessions_to_add = {}, + const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}); /// \brief Generate a dummy Bearer Context Modification Failure. /// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 69491c4603..6b5d759051 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -400,9 +400,12 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi return msg; } -f1ap_message srsran::srs_cu_cp::generate_ue_context_modification_response(gnb_cu_ue_f1ap_id_t cu_ue_id, - gnb_du_ue_f1ap_id_t du_ue_id, - rnti_t crnti) +f1ap_message +srsran::srs_cu_cp::generate_ue_context_modification_response(gnb_cu_ue_f1ap_id_t cu_ue_id, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + const std::vector& drbs_setup_mod_list, + const std::vector& drbs_modified_list) { f1ap_message ue_context_modification_response = {}; @@ -410,15 +413,24 @@ f1ap_message srsran::srs_cu_cp::generate_ue_context_modification_response(gnb_cu ue_context_modification_response.pdu.successful_outcome().load_info_obj(ASN1_F1AP_ID_UE_CONTEXT_MOD); auto& ue_context_mod_resp = ue_context_modification_response.pdu.successful_outcome().value.ue_context_mod_resp(); - ue_context_mod_resp->gnb_cu_ue_f1ap_id = (unsigned)cu_ue_id; - ue_context_mod_resp->gnb_du_ue_f1ap_id = (unsigned)du_ue_id; - ue_context_mod_resp->c_rnti_present = true; - ue_context_mod_resp->c_rnti = (unsigned)crnti; - ue_context_mod_resp->drbs_setup_mod_list_present = true; - - ue_context_mod_resp->drbs_setup_mod_list.push_back({}); - ue_context_mod_resp->drbs_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); - ue_context_mod_resp->drbs_setup_mod_list.back().value().drbs_setup_mod_item().drb_id = 1; + ue_context_mod_resp->gnb_cu_ue_f1ap_id = (unsigned)cu_ue_id; + ue_context_mod_resp->gnb_du_ue_f1ap_id = (unsigned)du_ue_id; + ue_context_mod_resp->c_rnti_present = true; + ue_context_mod_resp->c_rnti = (unsigned)crnti; + + ue_context_mod_resp->drbs_setup_mod_list_present = !drbs_setup_mod_list.empty(); + for (const auto& drb : drbs_setup_mod_list) { + ue_context_mod_resp->drbs_setup_mod_list.push_back({}); + ue_context_mod_resp->drbs_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); + ue_context_mod_resp->drbs_setup_mod_list.back().value().drbs_setup_mod_item().drb_id = drb_id_to_uint(drb); + } + + ue_context_mod_resp->drbs_modified_list_present = !drbs_modified_list.empty(); + for (const auto& drb : drbs_modified_list) { + ue_context_mod_resp->drbs_modified_list.push_back({}); + ue_context_mod_resp->drbs_modified_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); + ue_context_mod_resp->drbs_modified_list.back().value().drbs_modified_item().drb_id = drb_id_to_uint(drb); + } return ue_context_modification_response; } diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.h b/tests/unittests/f1ap/common/f1ap_cu_test_messages.h index df379a08bc..7cc8fdda76 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.h +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.h @@ -55,9 +55,12 @@ f1ap_message generate_ue_context_setup_failure(gnb_cu_ue_f1ap_id_t cu_ue_id, gnb f1ap_ue_context_modification_request generate_ue_context_modification_request(ue_index_t ue_index); /// \brief Generates dummy F1AP UE CONTEXT MODIFICATION RESPONSE message. -f1ap_message generate_ue_context_modification_response(gnb_cu_ue_f1ap_id_t cu_ue_id, - gnb_du_ue_f1ap_id_t du_ue_id, - rnti_t crnti = to_rnti(0x4601)); +f1ap_message +generate_ue_context_modification_response(gnb_cu_ue_f1ap_id_t cu_ue_id, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti = to_rnti(0x4601), + const std::vector& drbs_setup_mod_list = {drb_id_t::drb1}, + const std::vector& drbs_modified_list = {}); /// \brief Generates dummy F1AP UE CONTEXT MODIFICATION FAILURE message. f1ap_message generate_ue_context_modification_failure(gnb_cu_ue_f1ap_id_t cu_ue_id, gnb_du_ue_f1ap_id_t du_ue_id); diff --git a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp index 83d0af41f7..a08b30574a 100644 --- a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp @@ -136,7 +136,7 @@ TEST_F(ngap_pdu_session_resource_setup_procedure_test, auto& ue = test_ues.at(ue_index); ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( - ue.amf_ue_id.value(), ue.ran_ue_id.value(), pdu_session_id); + ue.amf_ue_id.value(), ue.ran_ue_id.value(), {{pdu_session_id, {{uint_to_qos_flow_id(1), 9}}}}); ngap->handle_message(pdu_session_resource_setup_request); // Check conversion in adapter @@ -176,7 +176,7 @@ TEST_F(ngap_pdu_session_resource_setup_procedure_test, when_security_not_enabled pdu_session_id_to_uint(pdu_session_id_t::min), pdu_session_id_to_uint(pdu_session_id_t::max))); ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( - ue.amf_ue_id.value(), ue.ran_ue_id.value(), pdu_session_id); + ue.amf_ue_id.value(), ue.ran_ue_id.value(), {{pdu_session_id, {{uint_to_qos_flow_id(1), 9}}}}); ngap->handle_message(pdu_session_resource_setup_request); // Check that Error Indication has been sent to AMF diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index 25b47c27e2..0a0bdab173 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -133,7 +133,7 @@ void ngap_test::run_pdu_session_resource_setup(ue_index_t ue_index, pdu_session_ auto& ue = test_ues.at(ue_index); ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( - ue.amf_ue_id.value(), ue.ran_ue_id.value(), pdu_session_id); + ue.amf_ue_id.value(), ue.ran_ue_id.value(), {{pdu_session_id, {{uint_to_qos_flow_id(1), 9}}}}); ngap->handle_message(pdu_session_resource_setup_request); } diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index 7426e97aeb..bf734cb8fb 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -17,6 +17,7 @@ #include "srsran/ngap/ngap_message.h" #include "srsran/ngap/ngap_types.h" #include "srsran/ran/cu_types.h" +#include using namespace srsran; using namespace srs_cu_cp; @@ -393,36 +394,75 @@ ngap_message srsran::srs_cu_cp::generate_pdu_session_resource_setup_request_base return ngap_msg; } -ngap_message -srsran::srs_cu_cp::generate_valid_pdu_session_resource_setup_request_message(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - pdu_session_id_t pdu_session_id) +ngap_message srsran::srs_cu_cp::generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id_t amf_ue_id, + ran_ue_id_t ran_ue_id, + const std::map>& pdu_sessions) { ngap_message ngap_msg = generate_pdu_session_resource_setup_request_base(amf_ue_id, ran_ue_id); auto& pdu_session_res_setup_req = ngap_msg.pdu.init_msg().value.pdu_session_res_setup_request(); - pdu_session_res_setup_item_su_req_s pdu_session_res_item; + for (const auto& [pdu_session_id, qos_flows] : pdu_sessions) { + pdu_session_res_setup_item_su_req_s pdu_session_res_item; - pdu_session_res_item.pdu_session_id = pdu_session_id_to_uint(pdu_session_id); + pdu_session_res_item.pdu_session_id = pdu_session_id_to_uint(pdu_session_id); - // Add PDU Session NAS PDU - pdu_session_res_item.pdu_session_nas_pdu.from_string("7e02e9b0a23c027e006801006e2e0115c211000901000631310101ff08060" - "6014a06014a2905010c02010c2204010027db79000608204101" - "01087b002080802110030000108106ac1503648306ac150364000d04ac150" - "364001002054e251c036f61690469707634066d6e6330393906" - "6d636332303804677072731201"); + // Add PDU Session NAS PDU + pdu_session_res_item.pdu_session_nas_pdu.from_string("7e02e9b0a23c027e006801006e2e0115c211000901000631310101ff08060" + "6014a06014a2905010c02010c2204010027db79000608204101" + "01087b002080802110030000108106ac1503648306ac150364000d04ac150" + "364001002054e251c036f61690469707634066d6e6330393906" + "6d636332303804677072731201"); - // Add S-NSSAI - pdu_session_res_item.s_nssai.sst.from_number(1); - pdu_session_res_item.s_nssai.sd_present = true; - pdu_session_res_item.s_nssai.sd.from_string("0027db"); + // Add S-NSSAI + pdu_session_res_item.s_nssai.sst.from_number(1); + pdu_session_res_item.s_nssai.sd_present = true; + pdu_session_res_item.s_nssai.sd.from_string("0027db"); - // Add PDU Session Resource Setup Request Transfer - pdu_session_res_item.pdu_session_res_setup_request_transfer.from_string( - "0000040082000a0c400000003040000000008b000a01f00a321302000028d600860001000088000700010000091c00"); + // Add PDU Session Resource Setup Request Transfer + asn1::ngap::pdu_session_res_setup_request_transfer_s asn1_setup_req_transfer; + { + // Add PDU Session Aggregate Maximum Bit Rate + asn1_setup_req_transfer->pdu_session_aggr_max_bit_rate_present = true; + asn1_setup_req_transfer->pdu_session_aggr_max_bit_rate.pdu_session_aggr_max_bit_rate_dl = 1000000000U; + asn1_setup_req_transfer->pdu_session_aggr_max_bit_rate.pdu_session_aggr_max_bit_rate_ul = 1000000000U; + + // Add UL NGU UP TNL Info + asn1_setup_req_transfer->ul_ngu_up_tnl_info.set_gtp_tunnel(); + auto addr = transport_layer_address::create_from_string("127.0.0.1"); + asn1_setup_req_transfer->ul_ngu_up_tnl_info.gtp_tunnel().transport_layer_address.from_string(addr.to_bitstring()); + asn1_setup_req_transfer->ul_ngu_up_tnl_info.gtp_tunnel().gtp_teid.from_number(0x00005e6c); + + // Add PDU Session Type + asn1_setup_req_transfer->pdu_session_type = asn1::ngap::pdu_session_type_opts::ipv4; + + // Add QoS Flow Setup Request List + for (const auto& qos_flow_test_item : qos_flows) { + { + qos_flow_setup_request_item_s qos_flow_setup_req_item; + qos_flow_setup_req_item.qos_flow_id = qos_flow_id_to_uint(qos_flow_test_item.qos_flow_id); + + // Add QoS Characteristics + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics.set_non_dyn5qi(); + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi = + qos_flow_test_item.five_qi; + + // Add Allocation and Retention Priority + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = 8; + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = + pre_emption_cap_opts::shall_not_trigger_pre_emption; + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = + pre_emption_vulnerability_opts::not_pre_emptable; + + asn1_setup_req_transfer->qos_flow_setup_request_list.push_back(qos_flow_setup_req_item); + } + } + } + pdu_session_res_item.pdu_session_res_setup_request_transfer = pack_into_pdu(asn1_setup_req_transfer); - pdu_session_res_setup_req->pdu_session_res_setup_list_su_req.push_back(pdu_session_res_item); + pdu_session_res_setup_req->pdu_session_res_setup_list_su_req.push_back(pdu_session_res_item); + } return ngap_msg; } @@ -558,11 +598,12 @@ ngap_message srsran::srs_cu_cp::generate_pdu_session_resource_modify_request_bas return ngap_msg; } -ngap_message -srsran::srs_cu_cp::generate_valid_pdu_session_resource_modify_request_message(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - pdu_session_id_t pdu_session_id, - qos_flow_id_t qos_flow_id) +ngap_message srsran::srs_cu_cp::generate_valid_pdu_session_resource_modify_request_message( + amf_ue_id_t amf_ue_id, + ran_ue_id_t ran_ue_id, + pdu_session_id_t pdu_session_id, + const std::vector& qos_flow_add_or_modify_list, + const std::vector& qos_flow_to_release_list) { ngap_message ngap_msg = generate_pdu_session_resource_modify_request_base(amf_ue_id, ran_ue_id); @@ -573,16 +614,49 @@ srsran::srs_cu_cp::generate_valid_pdu_session_resource_modify_request_message(am pdu_session_res_item.pdu_session_id = pdu_session_id_to_uint(pdu_session_id); // Add PDU Session Resource Modify Request Transfer - pdu_session_res_modify_request_transfer_s pdu_session_res_modify_request_transfer; + asn1::ngap::pdu_session_res_modify_request_transfer_s pdu_session_res_modify_request_transfer; + { + // Add QoS flow add or modify + pdu_session_res_modify_request_transfer->qos_flow_add_or_modify_request_list_present = + !qos_flow_add_or_modify_list.empty(); + for (const auto& qos_flow_id : qos_flow_add_or_modify_list) { + // Add QoS Flow Modify Request List + + asn1::ngap::qos_flow_add_or_modify_request_item_s qos_flow_add_item; + + // qosFlowIdentifier + qos_flow_add_item.qos_flow_id = qos_flow_id_to_uint(qos_flow_id); + + // Add QoS Characteristics + qos_flow_add_item.qos_flow_level_qos_params_present = true; + qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics.set_non_dyn5qi(); + qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi = 9; + + // Add Allocation and Retention Priority + qos_flow_add_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = 8; + qos_flow_add_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = + asn1::ngap::pre_emption_cap_opts::shall_not_trigger_pre_emption; + qos_flow_add_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = + asn1::ngap::pre_emption_vulnerability_opts::not_pre_emptable; + + pdu_session_res_modify_request_transfer->qos_flow_add_or_modify_request_list.push_back(qos_flow_add_item); + } - // Add qos flow add or modify request item - pdu_session_res_modify_request_transfer->qos_flow_add_or_modify_request_list_present = true; - qos_flow_add_or_modify_request_item_s qos_flow_add_item; + // Add QoS flow to release + pdu_session_res_modify_request_transfer->qos_flow_to_release_list_present = !qos_flow_to_release_list.empty(); + for (const auto& qos_flow_id : qos_flow_to_release_list) { + asn1::ngap::qos_flow_with_cause_item_s qos_flow_release_item; - // qosFlowIdentifier - qos_flow_add_item.qos_flow_id = qos_flow_id_to_uint(qos_flow_id); + // qosFlowIdentifier + qos_flow_release_item.qos_flow_id = qos_flow_id_to_uint(qos_flow_id); - pdu_session_res_modify_request_transfer->qos_flow_add_or_modify_request_list.push_back(qos_flow_add_item); + // cause + qos_flow_release_item.cause.set_radio_network(); + qos_flow_release_item.cause.radio_network() = asn1::ngap::cause_radio_network_opts::options::unspecified; + + pdu_session_res_modify_request_transfer->qos_flow_to_release_list.push_back(qos_flow_release_item); + } + } pdu_session_res_item.pdu_session_res_modify_request_transfer = pack_into_pdu(pdu_session_res_modify_request_transfer); diff --git a/tests/unittests/ngap/ngap_test_messages.h b/tests/unittests/ngap/ngap_test_messages.h index 34a2208cac..59a077a37b 100644 --- a/tests/unittests/ngap/ngap_test_messages.h +++ b/tests/unittests/ngap/ngap_test_messages.h @@ -142,10 +142,16 @@ ngap_message generate_valid_ue_context_release_command_with_ue_ngap_id_pair(amf_ /// \brief Generate a dummy PDU Session Resource Setup Request base. ngap_message generate_pdu_session_resource_setup_request_base(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); +struct qos_flow_test_params { + qos_flow_id_t qos_flow_id; + uint16_t five_qi; +}; + /// \brief Generate a valid dummy PDU Session Resource Setup Request Message. -ngap_message generate_valid_pdu_session_resource_setup_request_message(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - pdu_session_id_t pdu_session_id); +ngap_message generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id_t amf_ue_id, + ran_ue_id_t ran_ue_id, + const std::map>& pdu_sessions); /// \brief Generate an invalid dummy PDU Session Resource Setup Request Message. ngap_message generate_invalid_pdu_session_resource_setup_request_message(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); @@ -173,11 +179,12 @@ generate_cu_cp_pdu_session_resource_release_response(pdu_session_id_t pdu_sessio ngap_message generate_pdu_session_resource_modify_request_base(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); /// \brief Generate a valid dummy PDU Session Resource Modify Request Message. -ngap_message -generate_valid_pdu_session_resource_modify_request_message(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - pdu_session_id_t pdu_session_id, - qos_flow_id_t qos_flow_id = uint_to_qos_flow_id(1)); +ngap_message generate_valid_pdu_session_resource_modify_request_message( + amf_ue_id_t amf_ue_id, + ran_ue_id_t ran_ue_id, + pdu_session_id_t pdu_session_id, + const std::vector& qos_flow_add_or_modify_list = {uint_to_qos_flow_id(1)}, + const std::vector& qos_flow_to_release_list = {}); /// \brief Generate an invalid dummy PDU Session Resource Modify Request Message. ngap_message generate_invalid_pdu_session_resource_modify_request_message(amf_ue_id_t amf_ue_id, diff --git a/tests/unittests/ngap/ngap_validators_test.cpp b/tests/unittests/ngap/ngap_validators_test.cpp index f04008dbf2..78d0823a38 100644 --- a/tests/unittests/ngap/ngap_validators_test.cpp +++ b/tests/unittests/ngap/ngap_validators_test.cpp @@ -70,7 +70,8 @@ class ngap_validator_test : public ngap_test ran_ue_id_t ran_ue_id) { pdu_session_id_t setup_psi = uint_to_pdu_session_id(1); - ngap_message ngap_msg = generate_valid_pdu_session_resource_setup_request_message(amf_ue_id, ran_ue_id, setup_psi); + ngap_message ngap_msg = generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id, ran_ue_id, {{setup_psi, {{uint_to_qos_flow_id(1), 9}}}}); auto& pdu_session_res_setup_req = ngap_msg.pdu.init_msg().value.pdu_session_res_setup_request(); @@ -87,7 +88,8 @@ class ngap_validator_test : public ngap_test ran_ue_id_t ran_ue_id, pdu_session_id_t psi) { - ngap_message ngap_msg = generate_valid_pdu_session_resource_setup_request_message(amf_ue_id, ran_ue_id, psi); + ngap_message ngap_msg = generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id, ran_ue_id, {{psi, {{uint_to_qos_flow_id(1), 9}}}}); auto& asn1_request = ngap_msg.pdu.init_msg().value.pdu_session_res_setup_request(); asn1_request->ue_aggr_max_bit_rate_present = false; @@ -183,8 +185,8 @@ TEST_F(ngap_validator_test, when_valid_request_received_then_pdu_session_setup_s amf_ue_id_t amf_ue_id = uint_to_amf_ue_id(0); ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - ngap_message ngap_msg = - generate_valid_pdu_session_resource_setup_request_message(amf_ue_id, ran_ue_id, uint_to_pdu_session_id(1)); + ngap_message ngap_msg = generate_valid_pdu_session_resource_setup_request_message( + amf_ue_id, ran_ue_id, {{uint_to_pdu_session_id(1), {{uint_to_qos_flow_id(1), 9}}}}); auto& asn1_request = ngap_msg.pdu.init_msg().value.pdu_session_res_setup_request(); From 0c2ed09bab4bc453c040136ecd27675858260157 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 31 Jul 2024 11:05:35 +0200 Subject: [PATCH 006/407] cu_cp,ngap: move helper functions --- .../ngap/ngap_test_message_validators.cpp | 65 ++++++++++++++ .../ngap/ngap_test_message_validators.h | 7 ++ .../cu_cp_initial_context_setup_test.cpp | 8 +- ...cu_cp_pdu_session_resource_modify_test.cpp | 21 +++-- ...u_cp_pdu_session_resource_release_test.cpp | 16 ++-- .../cu_cp_pdu_session_resource_setup_test.cpp | 12 +-- .../cu_cp/cu_cp_test_environment.cpp | 88 +------------------ .../unittests/cu_cp/cu_cp_test_environment.h | 7 -- tests/unittests/cu_cp/test_helpers.cpp | 24 +++++ tests/unittests/cu_cp/test_helpers.h | 3 + 10 files changed, 124 insertions(+), 127 deletions(-) diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.cpp b/tests/test_doubles/ngap/ngap_test_message_validators.cpp index 638302b5b5..b378bc2d8d 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.cpp +++ b/tests/test_doubles/ngap/ngap_test_message_validators.cpp @@ -10,6 +10,7 @@ #include "ngap_test_message_validators.h" #include "srsran/asn1/ngap/common.h" +#include "srsran/asn1/ngap/ngap_pdu_contents.h" #include "srsran/ngap/ngap_message.h" using namespace srsran; @@ -82,3 +83,67 @@ bool srsran::test_helpers::is_valid_pdu_session_resource_modify_response(const s TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_NGAP_ID_PDU_SESSION_RES_MODIFY); return true; } + +bool srsran::test_helpers::is_expected_pdu_session_resource_setup_response( + const ngap_message& ngap_pdu, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup) +{ + // Check failed PDU sessions + if (expected_pdu_sessions_failed_to_setup.empty() && ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res_present) { + return false; + } + + if (!expected_pdu_sessions_failed_to_setup.empty() && !ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res_present) { + return false; + } + + if (expected_pdu_sessions_failed_to_setup.size() != ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res.size()) { + return false; + } + + for (const auto& asn1_failed_item : ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_failed_to_setup_list_su_res) { + if (std::find(expected_pdu_sessions_failed_to_setup.begin(), + expected_pdu_sessions_failed_to_setup.end(), + uint_to_pdu_session_id(asn1_failed_item.pdu_session_id)) == + expected_pdu_sessions_failed_to_setup.end()) { + return false; + } + } + + // Check successful PDU sessions + if (expected_pdu_sessions_to_setup.empty() && + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res_present) { + return false; + } + + if (!expected_pdu_sessions_to_setup.empty() && !ngap_pdu.pdu.successful_outcome() + .value.pdu_session_res_setup_resp() + ->pdu_session_res_setup_list_su_res_present) { + return false; + } + + if (expected_pdu_sessions_to_setup.size() != + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res.size()) { + return false; + } + + for (const auto& asn1_setup_item : + ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res) { + if (std::find(expected_pdu_sessions_to_setup.begin(), + expected_pdu_sessions_to_setup.end(), + uint_to_pdu_session_id(asn1_setup_item.pdu_session_id)) == expected_pdu_sessions_to_setup.end()) { + return false; + } + } + + return true; +} diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.h b/tests/test_doubles/ngap/ngap_test_message_validators.h index 9434f453ae..a5970d87e7 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.h +++ b/tests/test_doubles/ngap/ngap_test_message_validators.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/ran/cu_types.h" namespace srsran { namespace srs_cu_cp { @@ -38,5 +39,11 @@ bool is_valid_pdu_session_resource_release_response(const srs_cu_cp::ngap_messag bool is_valid_pdu_session_resource_modify_response(const srs_cu_cp::ngap_message& msg); +// Check if the NGAP PDU contains the expected PDU session setup response. +bool is_expected_pdu_session_resource_setup_response( + const srs_cu_cp::ngap_message& ngap_pdu, + const std::vector& expected_pdu_sessions_to_setup, + const std::vector& expected_pdu_sessions_failed_to_setup); + } // namespace test_helpers } // namespace srsran \ No newline at end of file diff --git a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp index 51d34d9ca0..1e955c5930 100644 --- a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp @@ -13,6 +13,7 @@ #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" @@ -186,11 +187,8 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : void send_rrc_reconfiguration_complete_and_await_initial_context_setup_response() { // Inject UL RRC Message Transfer (containing RRC Reconfiguration Complete) - f1ap_message ul_rrc_msg_transfer = - generate_ul_rrc_message_transfer(ue_ctx->cu_ue_id.value(), - du_ue_id, - srb_id_t::srb1, - cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(3, 5)); + f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( + ue_ctx->cu_ue_id.value(), du_ue_id, srb_id_t::srb1, generate_rrc_reconfiguration_complete_pdu(3, 5)); get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); // Wait for Initial Context Setup Response diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp index 5441c7da27..12fb470cb7 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp @@ -14,6 +14,7 @@ #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" @@ -422,7 +423,7 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( - cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(1, 9)); + generate_rrc_reconfiguration_complete_pdu(1, 9)); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_many_qos_flows_are_added_pdu_session_modification_succeeds) @@ -431,11 +432,10 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, when_many_qos_flows_are_added_pdu unsigned transaction_id = 0; unsigned count = 8; for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow( - psi, - uint_to_drb_id(i), - uint_to_qos_flow_id(i), - cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); + modify_pdu_session_and_add_qos_flow(psi, + uint_to_drb_id(i), + uint_to_qos_flow_id(i), + generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); count++; transaction_id++; if (transaction_id == 4) { @@ -450,11 +450,10 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, when_one_to_many_qos_flows_are_ad unsigned transaction_id = 0; unsigned count = 8; for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow( - psi, - uint_to_drb_id(i), - uint_to_qos_flow_id(i), - cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); + modify_pdu_session_and_add_qos_flow(psi, + uint_to_drb_id(i), + uint_to_qos_flow_id(i), + generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); count++; transaction_id++; if (transaction_id == 4) { diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp index 7a312d13f7..6fd903d7e1 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp @@ -14,6 +14,7 @@ #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" @@ -123,17 +124,13 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( - du_ue_id, - ue_ctx->cu_ue_id.value(), - srb_id_t::srb1, - cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(0, 8))); + du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, generate_rrc_reconfiguration_complete_pdu(0, 8))); result = this->wait_for_ngap_tx_pdu(ngap_pdu); report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not( - cu_cp_test_environment::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi2}, {}), - "Unsuccessful PDU Session Resource Setup Response"); + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi2}, {}), + "Unsuccessful PDU Session Resource Setup Response"); } void send_pdu_session_release_command_and_await_bearer_context_modification_request() @@ -240,10 +237,7 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for PDU Session Resource Release // Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( - du_ue_id, - ue_ctx->cu_ue_id.value(), - srb_id_t::srb1, - cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(3, 7))); + du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, generate_rrc_reconfiguration_complete_pdu(3, 7))); bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Release Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_release_response(ngap_pdu), diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp index c5c431ef9d..c0a2614ad8 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp @@ -99,7 +99,7 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); } @@ -127,7 +127,7 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); } @@ -153,7 +153,7 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); } @@ -173,7 +173,7 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); } @@ -202,7 +202,7 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); } @@ -414,7 +414,7 @@ TEST_F( report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi}, {psi2}), + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi}, {psi2}), "Unsuccessful PDU Session Resource Setup Response"); } diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index 7852e434e9..bcec5f8563 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -648,92 +648,6 @@ bool cu_cp_test_environment::send_bearer_context_modification_response_and_await return true; } -bool cu_cp_test_environment::is_expected_pdu_session_resource_setup_response( - const ngap_message& ngap_pdu, - const std::vector& expected_pdu_sessions_to_setup, - const std::vector& expected_pdu_sessions_failed_to_setup) -{ - // Check failed PDU sessions - if (expected_pdu_sessions_failed_to_setup.empty() && ngap_pdu.pdu.successful_outcome() - .value.pdu_session_res_setup_resp() - ->pdu_session_res_failed_to_setup_list_su_res_present) { - return false; - } - - if (!expected_pdu_sessions_failed_to_setup.empty() && !ngap_pdu.pdu.successful_outcome() - .value.pdu_session_res_setup_resp() - ->pdu_session_res_failed_to_setup_list_su_res_present) { - return false; - } - - if (expected_pdu_sessions_failed_to_setup.size() != ngap_pdu.pdu.successful_outcome() - .value.pdu_session_res_setup_resp() - ->pdu_session_res_failed_to_setup_list_su_res.size()) { - return false; - } - - for (const auto& asn1_failed_item : ngap_pdu.pdu.successful_outcome() - .value.pdu_session_res_setup_resp() - ->pdu_session_res_failed_to_setup_list_su_res) { - if (std::find(expected_pdu_sessions_failed_to_setup.begin(), - expected_pdu_sessions_failed_to_setup.end(), - uint_to_pdu_session_id(asn1_failed_item.pdu_session_id)) == - expected_pdu_sessions_failed_to_setup.end()) { - return false; - } - } - - // Check successful PDU sessions - if (expected_pdu_sessions_to_setup.empty() && - ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res_present) { - return false; - } - - if (!expected_pdu_sessions_to_setup.empty() && !ngap_pdu.pdu.successful_outcome() - .value.pdu_session_res_setup_resp() - ->pdu_session_res_setup_list_su_res_present) { - return false; - } - - if (expected_pdu_sessions_to_setup.size() != - ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res.size()) { - return false; - } - - for (const auto& asn1_setup_item : - ngap_pdu.pdu.successful_outcome().value.pdu_session_res_setup_resp()->pdu_session_res_setup_list_su_res) { - if (std::find(expected_pdu_sessions_to_setup.begin(), - expected_pdu_sessions_to_setup.end(), - uint_to_pdu_session_id(asn1_setup_item.pdu_session_id)) == expected_pdu_sessions_to_setup.end()) { - return false; - } - } - - return true; -} - -byte_buffer cu_cp_test_environment::generate_rrc_reconfiguration_complete_pdu(unsigned transaction_id, uint8_t count) -{ - byte_buffer pdu_with_count = byte_buffer::create({0x00, count}).value(); - if (!pdu_with_count.append(pack_ul_dcch_msg(create_rrc_reconfiguration_complete(transaction_id)))) { - return {}; - } - - security::sec_mac mac_exp = {}; - auto k_128_int = std::array{ - 0xf3, 0xd5, 0x99, 0x4a, 0x3b, 0x29, 0x06, 0xfb, 0x27, 0x00, 0x4a, 0x44, 0x90, 0x6c, 0x6b, 0xd1}; - byte_buffer_view buf = pdu_with_count; - - security::security_nia2( - mac_exp, k_128_int, count, srb_id_to_uint(srb_id_t::srb1) - 1, security::security_direction::uplink, buf); - - if (!pdu_with_count.append(mac_exp)) { - return {}; - } - - return pdu_with_count; -} - bool cu_cp_test_environment::send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, @@ -753,7 +667,7 @@ bool cu_cp_test_environment::send_rrc_reconfiguration_complete_and_await_pdu_ses report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_setup_response( + report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response( ngap_pdu, expected_pdu_sessions_to_setup, expected_pdu_sessions_failed_to_setup), "Unsuccessful PDU Session Resource Setup Response"); diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index f3230d579d..a3600c2b4d 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -182,13 +182,6 @@ class cu_cp_test_environment const std::vector& expected_pdu_sessions_to_setup, const std::vector& expected_pdu_sessions_failed_to_setup); - bool is_expected_pdu_session_resource_setup_response( - const ngap_message& ngap_pdu, - const std::vector& expected_pdu_sessions_to_setup, - const std::vector& expected_pdu_sessions_failed_to_setup); - - byte_buffer generate_rrc_reconfiguration_complete_pdu(unsigned transaction_id, uint8_t count); - private: class worker_manager; diff --git a/tests/unittests/cu_cp/test_helpers.cpp b/tests/unittests/cu_cp/test_helpers.cpp index 9d3d9f0190..2921b2bbbb 100644 --- a/tests/unittests/cu_cp/test_helpers.cpp +++ b/tests/unittests/cu_cp/test_helpers.cpp @@ -10,6 +10,8 @@ #include "test_helpers.h" #include "../rrc/rrc_ue_test_helpers.h" +#include "tests/test_doubles/rrc/rrc_test_messages.h" +#include "srsran/security/integrity.h" using namespace srsran; using namespace srs_cu_cp; @@ -33,3 +35,25 @@ byte_buffer srsran::srs_cu_cp::generate_rrc_setup_complete() "018010174000090530101000000000"); return octet_str.to_byte_buffer(); } + +byte_buffer srsran::srs_cu_cp::generate_rrc_reconfiguration_complete_pdu(unsigned transaction_id, uint8_t count) +{ + byte_buffer pdu_with_count = byte_buffer::create({0x00, count}).value(); + if (!pdu_with_count.append(pack_ul_dcch_msg(create_rrc_reconfiguration_complete(transaction_id)))) { + return {}; + } + + security::sec_mac mac_exp = {}; + auto k_128_int = std::array{ + 0xf3, 0xd5, 0x99, 0x4a, 0x3b, 0x29, 0x06, 0xfb, 0x27, 0x00, 0x4a, 0x44, 0x90, 0x6c, 0x6b, 0xd1}; + byte_buffer_view buf = pdu_with_count; + + security::security_nia2( + mac_exp, k_128_int, count, srb_id_to_uint(srb_id_t::srb1) - 1, security::security_direction::uplink, buf); + + if (!pdu_with_count.append(mac_exp)) { + return {}; + } + + return pdu_with_count; +} diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index 6c470a83ec..51374324c5 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -32,6 +32,9 @@ byte_buffer generate_container_with_cell_group_config(); /// \brief Generate RRC Container with RRC Setup Complete message. byte_buffer generate_rrc_setup_complete(); +// Generate RRC Reconfiguration Complete PDU. +byte_buffer generate_rrc_reconfiguration_complete_pdu(unsigned transaction_id, uint8_t count); + struct dummy_du_processor_cu_cp_notifier : public du_processor_cu_cp_notifier { public: explicit dummy_du_processor_cu_cp_notifier(ue_manager* ue_mng_ = nullptr) : ue_mng(ue_mng_) {} From 23d6a51cda3077f67b27e0b678f29c485faad295 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 31 Jul 2024 11:05:49 +0200 Subject: [PATCH 007/407] cu_cp: add nodiscard to test functions --- .../cu_cp/cu_cp_test_environment.cpp | 12 ++- .../unittests/cu_cp/cu_cp_test_environment.h | 100 +++++++++--------- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index bcec5f8563..15b780c7c0 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -700,8 +700,10 @@ bool cu_cp_test_environment::setup_pdu_session(unsigned du_idx, if (is_initial_session) { // Inject PDU Session Resource Setup Request and wait for Bearer Context Setup Request. - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( - pdu_session_resource_setup_request, du_idx, cu_up_idx, du_ue_id); + if (not send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + pdu_session_resource_setup_request, du_idx, cu_up_idx, du_ue_id)) { + return false; + } // Inject Bearer Context Setup Response and wait for F1AP UE Context Modification Request. if (not send_bearer_context_setup_response_and_await_ue_context_modification_request( @@ -710,8 +712,10 @@ bool cu_cp_test_environment::setup_pdu_session(unsigned du_idx, } } else { // Inject PDU Session Resource Setup Request and wait for Bearer Context Modification Request. - send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( - pdu_session_resource_setup_request, du_idx); + if (not send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + pdu_session_resource_setup_request, du_idx)) { + return false; + } // Inject Bearer Context Modification Response and wait for F1AP UE Context Modification Request. if (not send_bearer_context_modification_response_and_await_ue_context_modification_request( diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index a3600c2b4d..35416da6c1 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -71,45 +71,47 @@ class cu_cp_test_environment bool run_e1_setup(unsigned cu_up_idx); /// Connect a new UE to CU-CP through a provided DU. It runs the full RRC setup procedure. - bool connect_new_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, rnti_t crnti); + [[nodiscard]] bool connect_new_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, rnti_t crnti); /// Runs the NAS Authentication for a given UE. - bool authenticate_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, amf_ue_id_t amf_ue_id); + [[nodiscard]] bool authenticate_ue(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, amf_ue_id_t amf_ue_id); /// Runs the Security Mode procedure for a given UE. - bool setup_ue_security(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id); + [[nodiscard]] bool setup_ue_security(unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id); /// Finishes the registration for a given UE. - bool finish_ue_registration(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); + [[nodiscard]] bool finish_ue_registration(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); /// Requests PDU Session Resource Setup - bool request_pdu_session_resource_setup(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); + [[nodiscard]] bool + request_pdu_session_resource_setup(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); /// Runs PDU Session Resource Setup for a given UE. - bool setup_pdu_session(unsigned du_idx, - unsigned cu_up_idx, - gnb_du_ue_f1ap_id_t du_ue_id, - rnti_t crnti, - gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, - pdu_session_id_t psi = pdu_session_id_t::min, - drb_id_t drb_id = drb_id_t::drb1, - qos_flow_id_t qfi = qos_flow_id_t::min, - byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), - bool is_initial_session = true); + [[nodiscard]] bool + setup_pdu_session(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi = pdu_session_id_t::min, + drb_id_t drb_id = drb_id_t::drb1, + qos_flow_id_t qfi = qos_flow_id_t::min, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), + bool is_initial_session = true); /// Runs RRC setup, authentication, security, RRC Reconfiguration, PDU session setup for a given UE. - bool attach_ue(unsigned du_idx, - unsigned cu_up_idx, - gnb_du_ue_f1ap_id_t du_ue_id, - rnti_t crnti, - amf_ue_id_t amf_ue_id, - gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, - pdu_session_id_t psi = pdu_session_id_t::min, - drb_id_t drb_id = drb_id_t::drb1, - qos_flow_id_t qfi = qos_flow_id_t::min, - byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value()); + [[nodiscard]] bool attach_ue(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti, + amf_ue_id_t amf_ue_id, + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id, + pdu_session_id_t psi = pdu_session_id_t::min, + drb_id_t drb_id = drb_id_t::drb1, + qos_flow_id_t qfi = qos_flow_id_t::min, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value()); /// Reestablishes a UE connection, including RRC Reestablishment and RRC Reconfiguration procedures. /// \return True if the reestablishment was successful, false if RRC Setup/Reject was performed instead. - bool reestablish_ue(unsigned du_idx, - unsigned cu_up_idx, - gnb_du_ue_f1ap_id_t new_du_ue_id, - rnti_t new_crnti, - rnti_t old_crnti, - pci_t old_pci); + [[nodiscard]] bool reestablish_ue(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t new_du_ue_id, + rnti_t new_crnti, + rnti_t old_crnti, + pci_t old_pci); /// Tick the CU-CP clock. void tick(); @@ -136,17 +138,17 @@ class cu_cp_test_environment const cu_cp_configuration& get_cu_cp_cfg() const { return cu_cp_cfg; } // Helper functions - bool send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + [[nodiscard]] bool send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( const ngap_message& pdu_session_resource_setup_request, unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id); - bool send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + [[nodiscard]] bool send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( const ngap_message& pdu_session_resource_setup_request, unsigned cu_up_idx); - bool + [[nodiscard]] bool send_bearer_context_setup_response_and_await_ue_context_modification_request(unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id, @@ -154,19 +156,21 @@ class cu_cp_test_environment pdu_session_id_t psi, qos_flow_id_t qfi); - bool send_bearer_context_modification_response_and_await_ue_context_modification_request(unsigned du_idx, - unsigned cu_up_idx, - gnb_du_ue_f1ap_id_t du_ue_id, - pdu_session_id_t psi, - drb_id_t drb_id, - qos_flow_id_t qfi); - - bool send_ue_context_modification_response_and_await_bearer_context_modification_request(unsigned du_idx, - unsigned cu_up_idx, - gnb_du_ue_f1ap_id_t du_ue_id, - rnti_t crnti); - - bool send_bearer_context_modification_response_and_await_rrc_reconfiguration( + [[nodiscard]] bool + send_bearer_context_modification_response_and_await_ue_context_modification_request(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + pdu_session_id_t psi, + drb_id_t drb_id, + qos_flow_id_t qfi); + + [[nodiscard]] bool + send_ue_context_modification_response_and_await_bearer_context_modification_request(unsigned du_idx, + unsigned cu_up_idx, + gnb_du_ue_f1ap_id_t du_ue_id, + rnti_t crnti); + + [[nodiscard]] bool send_bearer_context_modification_response_and_await_rrc_reconfiguration( unsigned du_idx, unsigned cu_up_idx, gnb_du_ue_f1ap_id_t du_ue_id, @@ -175,7 +179,7 @@ class cu_cp_test_environment const std::optional>& expected_srbs_to_add_mod = std::nullopt, const std::optional>& expected_drbs_to_add_mod = std::nullopt); - bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + [[nodiscard]] bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( unsigned du_idx, gnb_du_ue_f1ap_id_t du_ue_id, byte_buffer rrc_reconfiguration_complete, From 3760e5f24808f5f8c1aa847a6f2c5842a2a44d09 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Wed, 31 Jul 2024 11:00:18 +0000 Subject: [PATCH 008/407] srsvec,compression: improve simd in bf16 conversion, optimize AVX implementations of decompressors --- include/srsran/srsvec/prod.h | 1 + include/srsran/srsvec/sc_prod.h | 1 + .../compression/iq_compression_bfp_avx2.cpp | 32 +++++++++------ .../compression/iq_compression_bfp_avx512.cpp | 32 +++++++++------ .../compression/iq_compression_bfp_neon.cpp | 1 + .../compression/iq_compression_none_avx2.cpp | 24 ++++++------ .../iq_compression_none_avx512.cpp | 23 +++++------ .../compression/iq_compression_none_neon.cpp | 17 ++++---- lib/srsvec/conversion.cpp | 33 +++++++++++++++- lib/srsvec/prod.cpp | 39 +++++++++++++++++++ lib/srsvec/sc_prod.cpp | 37 ++++++++++++++++++ lib/srsvec/simd.h | 34 +++++++++++++--- 12 files changed, 216 insertions(+), 58 deletions(-) diff --git a/include/srsran/srsvec/prod.h b/include/srsran/srsvec/prod.h index 1f69b2b7d8..15691be6bd 100644 --- a/include/srsran/srsvec/prod.h +++ b/include/srsran/srsvec/prod.h @@ -19,6 +19,7 @@ void prod(span x, span y, span z); void prod(span x, span y, span z); void prod(span x, span y, span z); void prod(span x, span y, span z); +void prod(span x, span y, span z); void prod_conj(span x, span y, span z); diff --git a/include/srsran/srsvec/sc_prod.h b/include/srsran/srsvec/sc_prod.h index 4c0f26dd19..18c675d0db 100644 --- a/include/srsran/srsvec/sc_prod.h +++ b/include/srsran/srsvec/sc_prod.h @@ -19,6 +19,7 @@ void sc_prod(span x, cf_t h, span z); void sc_prod(span x, cf_t h, span z); void sc_prod(span x, float h, span z); void sc_prod(span x, float h, span z); +void sc_prod(span x, int16_t h, span z); } // namespace srsvec } // namespace srsran diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.cpp b/lib/ofh/compression/iq_compression_bfp_avx2.cpp index de4a2de91d..56bfb3b3a8 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx2.cpp @@ -12,6 +12,7 @@ #include "avx2_helpers.h" #include "packing_utils_avx2.h" #include "quantizer.h" +#include "srsran/srsvec/prod.h" using namespace srsran; using namespace ofh; @@ -93,24 +94,33 @@ void iq_compression_bfp_avx2::decompress(span output, quantizer q_out(Q_BIT_WIDTH); - unsigned out_idx = 0; + // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. + constexpr size_t avx2_size_iqs = 16; + constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; + + alignas(64) std::array unpacked_iq_data; + alignas(64) std::array unpacked_iq_scaling; + + unsigned idx = 0; for (const auto& c_prb : input) { // Compute scaling factor. uint8_t exponent = c_prb.get_compression_param(); int16_t scaler = 1 << exponent; - // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. - constexpr size_t avx2_size_iqs = 16; - constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; - alignas(64) std::array unpacked_iq_data; // Unpack resource block. - mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); + mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); + // Save scaling factor. + std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler); - // Convert to complex samples. - q_out.to_brain_float(output_span, unpacked_span, scaler); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); + // Scale unpacked IQ samples using saved exponents. + srsvec::prod(unpacked_iq_int16_span, unpacked_iq_scaling_span, unpacked_iq_int16_span); + // Convert to complex samples. + q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.cpp b/lib/ofh/compression/iq_compression_bfp_avx512.cpp index 98b4ed782d..f2760557fe 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx512.cpp @@ -12,6 +12,7 @@ #include "avx512_helpers.h" #include "packing_utils_avx512.h" #include "quantizer.h" +#include "srsran/srsvec/prod.h" using namespace srsran; using namespace ofh; @@ -135,24 +136,33 @@ void iq_compression_bfp_avx512::decompress(span output, quantizer q_out(Q_BIT_WIDTH); - unsigned out_idx = 0; + // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. + constexpr size_t avx512_size_iqs = 32; + constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx512_size_iqs) * avx512_size_iqs; + + alignas(64) std::array unpacked_iq_data; + alignas(64) std::array unpacked_iq_scaling; + + unsigned idx = 0; for (const auto& c_prb : input) { // Compute scaling factor. uint8_t exponent = c_prb.get_compression_param(); int16_t scaler = 1 << exponent; - // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. - constexpr size_t avx512_size_iqs = 32; - constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx512_size_iqs) * avx512_size_iqs; - alignas(64) std::array unpacked_iq_data; // Unpack resource block. - mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); + mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); + // Save scaling factor. + std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler); - // Convert to complex samples. - q_out.to_brain_float(output_span, unpacked_span, scaler); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); + // Scale unpacked IQ samples using saved exponents. + srsvec::prod(unpacked_iq_int16_span, unpacked_iq_scaling_span, unpacked_iq_int16_span); + // Convert to complex samples. + q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_bfp_neon.cpp b/lib/ofh/compression/iq_compression_bfp_neon.cpp index 004ae68a17..35533c9a33 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.cpp +++ b/lib/ofh/compression/iq_compression_bfp_neon.cpp @@ -209,6 +209,7 @@ void iq_compression_bfp_neon::decompress(span output, constexpr size_t neon_size_iqs = 8; constexpr size_t arr_size = divide_ceil(NOF_SAMPLES_PER_PRB, neon_size_iqs) * neon_size_iqs; alignas(64) std::array unpacked_iq_data; + // Unpack resource block. neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); diff --git a/lib/ofh/compression/iq_compression_none_avx2.cpp b/lib/ofh/compression/iq_compression_none_avx2.cpp index 8abec79574..f818d6685b 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.cpp +++ b/lib/ofh/compression/iq_compression_none_avx2.cpp @@ -86,20 +86,20 @@ void iq_compression_none_avx2::decompress(span output, // Quantizer object. quantizer q(params.data_width); - unsigned out_idx = 0; - for (const auto& c_prb : input) { - constexpr size_t avx2_size_iqs = 16; - constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; - alignas(64) std::array unpacked_iq_data; + constexpr size_t avx2_size_iqs = 16; + constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; + alignas(64) std::array unpacked_iq_data; + unsigned idx = 0; + for (const auto& c_prb : input) { // Unpack resource block. - mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); + mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); - - // Convert to complex samples. - q.to_brain_float(output_span, unpacked_span, 1); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + // Convert to complex brain float samples. + q.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_avx512.cpp b/lib/ofh/compression/iq_compression_none_avx512.cpp index 00bdd83246..dac64caa52 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.cpp +++ b/lib/ofh/compression/iq_compression_none_avx512.cpp @@ -70,19 +70,20 @@ void iq_compression_none_avx512::decompress(span output, } // Quantizer object. - quantizer q(params.data_width); + quantizer q_out(params.data_width); - unsigned out_idx = 0; - for (const auto& c_prb : input) { - std::array unpacked_iq_data; - // Unpack resource block. - mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + std::array unpacked_iq_data; - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); + unsigned idx = 0; + for (const compressed_prb& c_prb : input) { + // Unpack resource block. + span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); + mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - // Convert to complex samples. - q.to_brain_float(output_span, unpacked_span, 1); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + // Convert to complex brain float samples. + q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_neon.cpp b/lib/ofh/compression/iq_compression_none_neon.cpp index d2925ab929..38182270c1 100644 --- a/lib/ofh/compression/iq_compression_none_neon.cpp +++ b/lib/ofh/compression/iq_compression_none_neon.cpp @@ -107,15 +107,18 @@ void iq_compression_none_neon::decompress(span output, quantizer q_out(params.data_width); - unsigned out_idx = 0; + std::array unpacked_iq_data; + + unsigned idx = 0; for (const compressed_prb& c_prb : input) { // Unpack resource block. - std::array unpacked_iq_data; - neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); + neon::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - // Convert to complex samples. - q_out.to_brain_float(output_span, unpacked_iq_data, 1); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + // Convert to complex brain float samples. + q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index d1897e8493..d59378b171 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -107,7 +107,7 @@ static void convert_if_simd(float* z, const int16_t* x, float scale, unsigned le __m256 float_vec = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(input_vec)); float_vec = _mm256_mul_ps(float_vec, scale256); - // Store the result back to memory + // Store the result back to memory. _mm256_storeu_ps(z + i, float_vec); } #endif // defined(__AVX__) && defined(__AVX2__) @@ -136,6 +136,17 @@ static void convert_bf16_to_f_simd(float* out, const bf16_t* in, unsigned len) { unsigned i = 0; +#if defined(__ARM_NEON) && defined(__ARM_FEATURE_BF16_VECTOR_ARITHMETIC) + for (unsigned i_end = (len / 4) * 4; i != i_end; i += 4) { + // Load 4 bf16 elements into a 64-bit vector register. + bfloat16x4_t input_vec = vld1_bf16(reinterpret_cast(in + i)); + // Convert bf16 to single-precision floating point. + float32x4_t output_vec = vcvt_f32_bf16(input_vec); + // Store the result back to memory. + srsran_simd_f_storeu(out + i, output_vec); + } +#else // __ARM_FEATURE_BF16 + #if SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE for (unsigned end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != end; i += SRSRAN_SIMD_S_SIZE) { simd_f_t even, odd; @@ -145,6 +156,7 @@ static void convert_bf16_to_f_simd(float* out, const bf16_t* in, unsigned len) srsran_simd_f_storeu_interleaved(out + i, even, odd); } #endif // SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE +#endif // __ARM_FEATURE_BF16 for (; i != len; ++i) { out[i] = to_float(in[i]); @@ -303,6 +315,25 @@ static void convert_int16_to_bf16_simd(bf16_t* out, const int16_t* in, float sca #endif // defined(__AVX__) && defined(__AVX2__) #endif // defined(__AVX__) && defined(__AVX512F__) +#if defined(__ARM_NEON) + // Load the scale factor into a vector register. + float32x4_t scale_f32 = vdupq_n_f32(gain); + + // Process 8 elements at a time (128 bits / 16 bits per brain float = 8 floats). + for (unsigned i_end = (len / 8) * 8; i != i_end; i += 8) { + // Load 8 int16_t elements into a 128-bit vector register. + int16x8_t input_vec = vld1q_s16(in + i); + + // Convert the int16_t elements to float and scale them. + float32x4_t float_vec_1 = vcvtq_f32_s32(vmovl_s16(vget_low_s16(input_vec))); + float32x4_t float_vec_2 = vcvtq_f32_s32(vmovl_high_s16(input_vec)); + float_vec_1 = vmulq_f32(float_vec_1, scale_f32); + float_vec_2 = vmulq_f32(float_vec_2, scale_f32); + + // Convert float to brain float and store the result back to memory. + srsran_simd_bf16_storeu(out + i, float_vec_1, float_vec_2); + } +#endif // defined(__ARM_NEON) for (; i != len; ++i) { out[i] = to_bf16(static_cast(in[i]) * gain); } diff --git a/lib/srsvec/prod.cpp b/lib/srsvec/prod.cpp index 54ac141cb8..b3527552b6 100644 --- a/lib/srsvec/prod.cpp +++ b/lib/srsvec/prod.cpp @@ -46,6 +46,37 @@ static void prod_fff_simd(const float* x, const float* y, float* z, std::size_t } } +static void prod_sss_simd(const int16_t* x, const int16_t* y, int16_t* z, std::size_t len) +{ + std::size_t i = 0; + +#if SRSRAN_SIMD_S_SIZE + if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { + for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_load(x + i); + simd_s_t b = srsran_simd_s_load(y + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_store(z + i, r); + } + } else { + for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_loadu(x + i); + simd_s_t b = srsran_simd_s_loadu(y + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_storeu(z + i, r); + } + } +#endif + + for (; i != len; ++i) { + z[i] = x[i] * y[i]; + } +} + static void prod_ccc_simd(const cf_t* x, const cf_t* y, cf_t* z, std::size_t len) { std::size_t i = 0; @@ -124,6 +155,14 @@ void srsran::srsvec::prod(span x, span y, span prod_fff_simd(x.data(), y.data(), z.data(), x.size()); } +void srsran::srsvec::prod(span x, span y, span z) +{ + srsran_srsvec_assert_size(x, y); + srsran_srsvec_assert_size(x, z); + + prod_sss_simd(x.data(), y.data(), z.data(), x.size()); +} + void srsran::srsvec::prod_conj(span x, span y, span z) { srsran_srsvec_assert_size(x, y); diff --git a/lib/srsvec/sc_prod.cpp b/lib/srsvec/sc_prod.cpp index 1f0f40b50d..44ed3f72a4 100644 --- a/lib/srsvec/sc_prod.cpp +++ b/lib/srsvec/sc_prod.cpp @@ -94,6 +94,36 @@ static void sc_prod_ccc_simd(const cbf16_t* x, cf_t h, cbf16_t* z, std::size_t l } } +static void sc_prod_sss_simd(const int16_t* x, int16_t h, int16_t* z, std::size_t len) +{ + std::size_t i = 0; + +#if SRSRAN_SIMD_S_SIZE + simd_s_t b = srsran_simd_s_set1(h); + if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(z)) { + for (unsigned i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_load(x + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_store(z + i, r); + } + } else { + for (unsigned i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_loadu(x + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_storeu(z + i, r); + } + } +#endif + + for (; i != len; ++i) { + z[i] = x[i] * h; + } +} + void srsran::srsvec::sc_prod(span x, cf_t h, span z) { srsran_srsvec_assert_size(x, z); @@ -121,3 +151,10 @@ void srsran::srsvec::sc_prod(span x, cf_t h, span z) sc_prod_ccc_simd(x.data(), h, z.data(), x.size()); } + +void srsran::srsvec::sc_prod(span x, int16_t h, span z) +{ + srsran_srsvec_assert_size(x, z); + + sc_prod_sss_simd(x.data(), h, z.data(), x.size()); +} diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index 600137901e..afbe05f9ab 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -1803,6 +1803,25 @@ inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) #endif /* __AVX512F__ */ } +inline simd_s_t srsran_simd_s_set1(int16_t x) +{ +#ifdef __AVX512F__ + return _mm512_set1_epi16(x); +#else /* __AVX512F__ */ +#ifdef __AVX2__ + return _mm256_set1_epi16(x); +#else /* __AVX2__ */ +#ifdef __SSE4_1__ + return _mm_set1_epi16(x); +#else /* __SSE4_1__ */ +#ifdef __ARM_NEON + return vdupq_n_s16(x); +#endif /* __ARM_NEON */ +#endif /* __SSE4_1__ */ +#endif /* __AVX2__ */ +#endif /* __AVX512F__ */ +} + #endif /* SRSRAN_SIMD_S_SIZE */ #if SRSRAN_SIMD_C16_SIZE @@ -2207,7 +2226,7 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) 0x3b0039, 0x3f003d), b_i32); -#else // __AVX512BW__ +#else // __AVX512BW__ const __m512i mask = _mm512_set1_epi32(0xffff0000); // Input: a0 xx | a1 xx | a2 xx | a3 xx | a4 xx | a5 xx | a6 xx | a7 xx | ... | a15 xx | // Transformations: @@ -2244,9 +2263,8 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) a_packed, _mm512_setr_epi32(0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e), b_packed); -#endif - -#else /* __AVX512F__ */ +#endif // __AVX512BW__ +#else /* __AVX512F__ */ #ifdef __AVX2__ const __m256i bias = _mm256_set1_epi32(0x7fff); const __m256i one = _mm256_set1_epi32(0x1); @@ -2311,6 +2329,11 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) ret = _mm_blend_epi16(a_packed, b_packed, 0xf0); #else /* __ARM_NEON */ #ifdef __ARM_NEON +#ifdef __ARM_FEATURE_BF16_VECTOR_ARITHMETIC + bfloat16x4_t tmp1 = vcvt_bf16_f32(a); + bfloat16x4_t tmp2 = vcvt_bf16_f32(b); + ret = vreinterpretq_s16_bf16(vcombine_bf16(tmp1, tmp2)); +#else // __ARM_FEATURE_BF16_VECTOR_ARITHMETIC const uint32x4_t bias = vdupq_n_u32(0x7fff); const uint32x4_t one = vdupq_n_u32(0x1); @@ -2330,7 +2353,8 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) uint16x8_t tmp_b_2 = vextq_u16(tmp_b_1, tmp_b_1, 1); uint32x4_t b_packed = vreinterpretq_u32_u16(vorrq_u16(tmp_b_1, tmp_b_2)); - ret = vreinterpretq_s16_u32(vuzpq_u32(a_packed, b_packed).val[0]); + ret = vreinterpretq_s16_u32(vuzpq_u32(a_packed, b_packed).val[0]); +#endif /* __ARM_FEATURE_BF16_VECTOR_ARITHMETIC */ #endif /* __ARM_NEON */ #endif /* __SSE4_1__ */ #endif /* __AVX2__ */ From 2672fe958e0e958b50b9c1e2f3afbc3e2f39633f Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 14:59:34 +0200 Subject: [PATCH 009/407] cu_cp: pass common task sched to cu-cp controller --- .../cu_cp_controller/amf_connection_manager.cpp | 7 +++---- lib/cu_cp/cu_cp_controller/amf_connection_manager.h | 5 +++-- lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp | 13 ++++++------- lib/cu_cp/cu_cp_controller/cu_cp_controller.h | 5 ++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/cu_cp/cu_cp_controller/amf_connection_manager.cpp b/lib/cu_cp/cu_cp_controller/amf_connection_manager.cpp index fa9b7d1969..c04fb65549 100644 --- a/lib/cu_cp/cu_cp_controller/amf_connection_manager.cpp +++ b/lib/cu_cp/cu_cp_controller/amf_connection_manager.cpp @@ -10,24 +10,23 @@ #include "amf_connection_manager.h" #include "../cu_cp_impl_interface.h" -#include "../routine_managers/cu_cp_routine_manager.h" #include "../routines/amf_connection_setup_routine.h" #include "srsran/cu_cp/cu_cp_configuration.h" using namespace srsran; using namespace srs_cu_cp; -amf_connection_manager::amf_connection_manager(cu_cp_routine_manager& routine_manager_, +amf_connection_manager::amf_connection_manager(common_task_scheduler& common_task_sched_, const cu_cp_configuration& cu_cp_cfg_, ngap_connection_manager& ngap_conn_mng_) : - routine_manager(routine_manager_), cu_cp_cfg(cu_cp_cfg_), ngap_conn_mng(ngap_conn_mng_) + common_task_sched(common_task_sched_), cu_cp_cfg(cu_cp_cfg_), ngap_conn_mng(ngap_conn_mng_) { } void amf_connection_manager::connect_to_amf(std::promise* completion_signal) { // Schedules setup routine to be executed in sequence with other CU-CP procedures. - routine_manager.schedule_async_task( + common_task_sched.schedule_async_task( launch_async([this, p = completion_signal](coro_context>& ctx) mutable { CORO_BEGIN(ctx); diff --git a/lib/cu_cp/cu_cp_controller/amf_connection_manager.h b/lib/cu_cp/cu_cp_controller/amf_connection_manager.h index 03d4c2fdf6..00b9d4662c 100644 --- a/lib/cu_cp/cu_cp_controller/amf_connection_manager.h +++ b/lib/cu_cp/cu_cp_controller/amf_connection_manager.h @@ -10,6 +10,7 @@ #pragma once +#include "common_task_scheduler.h" #include "srsran/cu_cp/cu_cp.h" #include @@ -22,7 +23,7 @@ struct cu_cp_configuration; class amf_connection_manager { public: - amf_connection_manager(cu_cp_routine_manager& routine_manager_, + amf_connection_manager(common_task_scheduler& common_task_sched_, const cu_cp_configuration& cu_cp_cfg_, ngap_connection_manager& ngap_conn_mng_); @@ -40,7 +41,7 @@ class amf_connection_manager private: void handle_connection_setup_result(bool success); - cu_cp_routine_manager& routine_manager; + common_task_scheduler& common_task_sched; const cu_cp_configuration& cu_cp_cfg; ngap_connection_manager& ngap_conn_mng; diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp index 93d2134750..54f12fe1c5 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp @@ -11,14 +11,13 @@ #include "cu_cp_controller.h" #include "../cu_up_processor/cu_up_processor_repository.h" #include "../du_processor/du_processor_repository.h" -#include "../routine_managers/cu_cp_routine_manager.h" #include using namespace srsran; using namespace srs_cu_cp; cu_cp_controller::cu_cp_controller(const cu_cp_configuration& config_, - cu_cp_routine_manager& routine_manager_, + common_task_scheduler& common_task_sched_, ue_manager& ue_mng_, ngap_connection_manager& ngap_conn_mng_, cu_up_processor_repository& cu_ups_, @@ -26,12 +25,12 @@ cu_cp_controller::cu_cp_controller(const cu_cp_configuration& config_, task_executor& ctrl_exec_) : cfg(config_), ue_mng(ue_mng_), - routine_mng(routine_manager_), + common_task_sched(common_task_sched_), ctrl_exec(ctrl_exec_), logger(srslog::fetch_basic_logger("CU-CP")), - amf_mng(routine_manager_, cfg, ngap_conn_mng_), - du_mng(cfg.admission.max_nof_dus, dus_, ctrl_exec, routine_manager_), - cu_up_mng(cfg.admission.max_nof_cu_ups, cu_ups_, ctrl_exec, routine_manager_) + amf_mng(common_task_sched_, cfg, ngap_conn_mng_), + du_mng(cfg.admission.max_nof_dus, dus_, ctrl_exec, common_task_sched_), + cu_up_mng(cfg.admission.max_nof_cu_ups, cu_ups_, ctrl_exec, common_task_sched_) { (void)ue_mng; } @@ -65,7 +64,7 @@ void cu_cp_controller::stop() void cu_cp_controller::stop_impl() { - routine_mng.schedule_async_task(launch_async([this](coro_context>& ctx) { + common_task_sched.schedule_async_task(launch_async([this](coro_context>& ctx) { CORO_BEGIN(ctx); // Stop AMF connection. diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h index 9f5799e26e..418ea45405 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h @@ -16,7 +16,6 @@ #include "du_connection_manager.h" #include "node_connection_notifier.h" #include "srsran/cu_cp/cu_cp_configuration.h" -#include "srsran/cu_cp/cu_cp_e1_handler.h" namespace srsran { namespace srs_cu_cp { @@ -36,7 +35,7 @@ class cu_cp_controller : public cu_cp_ue_admission_controller { public: cu_cp_controller(const cu_cp_configuration& config_, - cu_cp_routine_manager& routine_manager_, + common_task_scheduler& common_task_sched_, ue_manager& ue_mng_, ngap_connection_manager& ngap_conn_mng_, cu_up_processor_repository& cu_ups_, @@ -60,7 +59,7 @@ class cu_cp_controller : public cu_cp_ue_admission_controller const cu_cp_configuration& cfg; ue_manager& ue_mng; - cu_cp_routine_manager& routine_mng; + common_task_scheduler& common_task_sched; task_executor& ctrl_exec; srslog::basic_logger& logger; From 00e5f19d4bcf1e82971400fbd8f9ef120c8ed4c4 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 15:00:54 +0200 Subject: [PATCH 010/407] cu_cp: remove routine manager --- lib/cu_cp/CMakeLists.txt | 1 - lib/cu_cp/cu_cp_impl.cpp | 72 ++++--- lib/cu_cp/cu_cp_impl.h | 16 +- .../cu_cp_routine_manager.cpp | 184 ------------------ .../routine_managers/cu_cp_routine_manager.h | 111 ----------- 5 files changed, 59 insertions(+), 325 deletions(-) delete mode 100644 lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp delete mode 100644 lib/cu_cp/routine_managers/cu_cp_routine_manager.h diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index f3dbf461be..095d04470c 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -26,7 +26,6 @@ set(SOURCES du_processor/du_processor_factory.cpp du_processor/du_processor_repository.cpp metrics_handler/metrics_handler_impl.cpp - routine_managers/cu_cp_routine_manager.cpp routines/amf_connection_setup_routine.cpp routines/initial_context_setup_routine.cpp routines/pdu_session_routine_helpers.cpp diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 6361952bf0..0c8cdff1a7 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -12,11 +12,18 @@ #include "du_processor/du_processor_repository.h" #include "metrics_handler/metrics_handler_impl.h" #include "mobility_manager/mobility_manager_factory.h" +#include "routines/initial_context_setup_routine.h" +#include "routines/mobility/inter_cu_handover_target_routine.h" +#include "routines/mobility/inter_du_handover_routine.h" +#include "routines/pdu_session_resource_modification_routine.h" +#include "routines/pdu_session_resource_release_routine.h" +#include "routines/pdu_session_resource_setup_routine.h" +#include "routines/reestablishment_context_modification_routine.h" #include "routines/ue_amf_context_release_request_routine.h" +#include "routines/ue_context_release_routine.h" #include "routines/ue_removal_routine.h" #include "routines/ue_transaction_info_release_routine.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/security_manager_config.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/ngap/ngap_factory.h" #include "srsran/rrc/rrc_du.h" @@ -52,14 +59,13 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : cfg(config_), ue_mng(cfg), cell_meas_mng(cfg.mobility.meas_manager_config, cell_meas_ev_notifier, ue_mng), - routine_mng(ue_mng, cfg.security.default_security_indication, logger), du_db(du_repository_config{cfg, *this, get_cu_cp_ue_removal_handler(), get_cu_cp_ue_context_handler(), rrc_ue_ngap_notifier, rrc_ue_ngap_notifier, - routine_mng, + common_task_sched, ue_mng, rrc_du_cu_cp_notifier, conn_notifier, @@ -88,7 +94,7 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : ngap_entity->get_ngap_control_message_handler()); controller = std::make_unique(cfg, - routine_mng, + common_task_sched, ue_mng, ngap_entity->get_ngap_connection_manager(), cu_up_db, @@ -230,7 +236,7 @@ async_task cu_cp_impl::handle_rrc_reestablishment_context_modification_req "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); - return routine_mng.start_reestablishment_context_modification_routine( + return launch_async( ue_index, ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), @@ -238,7 +244,8 @@ async_task cu_cp_impl::handle_rrc_reestablishment_context_modification_req ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), - ue->get_up_resource_manager()); + ue->get_up_resource_manager(), + logger); } void cu_cp_impl::handle_rrc_reestablishment_failure(const cu_cp_ue_context_release_request& request) @@ -394,12 +401,13 @@ cu_cp_impl::handle_new_initial_context_setup_request(const ngap_init_context_set rrc_ue_interface* rrc_ue = rrc_du_adapters.at(ue->get_du_index()).find_rrc_ue(request.ue_index); srsran_assert(rrc_ue != nullptr, "ue={}: Could not find RRC UE", request.ue_index); - return routine_mng.start_initial_context_setup_routine(request, - *rrc_ue, - ngap_entity->get_ngap_ue_radio_cap_management_handler(), - ue->get_security_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), - get_cu_cp_ngap_handler()); + return launch_async(request, + *rrc_ue, + ngap_entity->get_ngap_ue_radio_cap_management_handler(), + ue->get_security_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), + get_cu_cp_ngap_handler(), + logger); } async_task @@ -411,15 +419,18 @@ cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_reso "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); - return routine_mng.start_pdu_session_resource_setup_routine( + return launch_async( request, + ue_mng.get_ue_config(), ue->get_security_manager().get_up_as_config(), + cfg.security.default_security_indication, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), - ue->get_up_resource_manager()); + ue->get_up_resource_manager(), + logger); } async_task @@ -431,14 +442,15 @@ cu_cp_impl::handle_new_pdu_session_resource_modify_request(const cu_cp_pdu_sessi "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); - return routine_mng.start_pdu_session_resource_modification_routine( + return launch_async( request, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), - ue->get_up_resource_manager()); + ue->get_up_resource_manager(), + logger); } async_task @@ -450,14 +462,15 @@ cu_cp_impl::handle_new_pdu_session_resource_release_command(const cu_cp_pdu_sess "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); - return routine_mng.start_pdu_session_resource_release_routine( + return launch_async( command, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), - ue->get_up_resource_manager()); + ue->get_up_resource_manager(), + logger); } async_task @@ -471,10 +484,12 @@ cu_cp_impl::handle_ue_context_release_command(const cu_cp_ue_context_release_com e1ap_bearer_ctxt_mng = &cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(); } - return routine_mng.start_ue_context_release_routine(command, - e1ap_bearer_ctxt_mng, - du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), - get_cu_cp_ue_removal_handler()); + return launch_async(command, + e1ap_bearer_ctxt_mng, + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), + get_cu_cp_ue_removal_handler(), + ue_mng, + logger); } async_task @@ -486,11 +501,14 @@ cu_cp_impl::handle_ngap_handover_request(const ngap_handover_request& request) "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); - return routine_mng.start_inter_cu_handover_target_routine( + return launch_async( request, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), - get_cu_cp_ue_removal_handler()); + get_cu_cp_ue_removal_handler(), + ue_mng, + cfg.security.default_security_indication, + logger); } async_task cu_cp_impl::handle_new_handover_command(ue_index_t ue_index, byte_buffer command) @@ -572,7 +590,7 @@ cu_cp_impl::handle_inter_du_handover_request(const cu_cp_inter_du_handover_reque byte_buffer sib1 = du_db.get_du_processor(target_du_index).get_mobility_handler().get_packed_sib1(request.cgi); - return routine_mng.start_inter_du_handover_routine( + return launch_async( request, std::move(sib1), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), @@ -580,7 +598,9 @@ cu_cp_impl::handle_inter_du_handover_request(const cu_cp_inter_du_handover_reque du_db.get_du_processor(target_du_index).get_f1ap_handler(), *this, get_cu_cp_ue_removal_handler(), - *this); + *this, + ue_mng, + logger); } async_task cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 2d2f7b30ee..c1a89d9daa 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -22,8 +22,6 @@ #include "cu_cp_impl_interface.h" #include "cu_up_processor/cu_up_processor_repository.h" #include "du_processor/du_processor_repository.h" -#include "paging/paging_message_handler.h" -#include "routine_managers/cu_cp_routine_manager.h" #include "ue_manager/ue_manager_impl.h" #include "srsran/cu_cp/cu_cp_configuration.h" #include "srsran/cu_cp/cu_cp_types.h" @@ -34,6 +32,18 @@ namespace srsran { namespace srs_cu_cp { +class cu_cp_common_task_scheduler : public common_task_scheduler +{ +public: + cu_cp_common_task_scheduler() : main_ctrl_loop(128) {} + + bool schedule_async_task(async_task task) override { return main_ctrl_loop.schedule(std::move(task)); } + +private: + // cu-cp task event loop + fifo_async_task_scheduler main_ctrl_loop; +}; + class cu_cp_impl final : public cu_cp, public cu_cp_impl_interface, public cu_cp_ng_handler, @@ -161,7 +171,7 @@ class cu_cp_impl final : public cu_cp, cell_meas_manager cell_meas_mng; // cell measurement manager - cu_cp_routine_manager routine_mng; + cu_cp_common_task_scheduler common_task_sched; // CU-CP to RRC DU adapters std::map rrc_du_adapters; diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp b/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp deleted file mode 100644 index d8cb064551..0000000000 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp +++ /dev/null @@ -1,184 +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_cp_routine_manager.h" -#include "../routines/initial_context_setup_routine.h" -#include "../routines/mobility/inter_cu_handover_target_routine.h" -#include "../routines/mobility/inter_du_handover_routine.h" -#include "../routines/pdu_session_resource_modification_routine.h" -#include "../routines/pdu_session_resource_release_routine.h" -#include "../routines/pdu_session_resource_setup_routine.h" -#include "../routines/reestablishment_context_modification_routine.h" -#include "../routines/ue_context_release_routine.h" -#include "srsran/support/async/coroutine.h" - -using namespace srsran; -using namespace srs_cu_cp; - -cu_cp_routine_manager::cu_cp_routine_manager(ue_manager& ue_mng_, - const security_indication_t& default_security_indication_, - srslog::basic_logger& logger_) : - - ue_mng(ue_mng_), - default_security_indication(default_security_indication_), - logger(logger_), - - main_ctrl_loop(128) -{ -} - -bool cu_cp_routine_manager::schedule_async_task(async_task task) -{ - return main_ctrl_loop.schedule(std::move(task)); -} - -async_task> -cu_cp_routine_manager::start_initial_context_setup_routine( - const ngap_init_context_setup_request& request, - rrc_ue_interface& rrc_ue, - ngap_ue_radio_capability_management_handler& ngap_ue_radio_cap_handler, - ue_security_manager& security_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - cu_cp_ngap_handler& pdu_session_setup_handler) -{ - return launch_async( - request, rrc_ue, ngap_ue_radio_cap_handler, security_mng, f1ap_ue_ctxt_mng, pdu_session_setup_handler, logger); -} - -async_task cu_cp_routine_manager::start_pdu_session_resource_setup_routine( - const cu_cp_pdu_session_resource_setup_request& setup_msg, - const srsran::security::sec_as_config& security_cfg, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& up_resource_mng) -{ - return launch_async(setup_msg, - ue_mng.get_ue_config(), - security_cfg, - default_security_indication, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_task_sched, - up_resource_mng, - logger); -} - -async_task -cu_cp_routine_manager::start_pdu_session_resource_modification_routine( - const cu_cp_pdu_session_resource_modify_request& modify_msg, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& up_resource_mng) -{ - return launch_async(modify_msg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_task_sched, - up_resource_mng, - logger); -} - -async_task -cu_cp_routine_manager::start_pdu_session_resource_release_routine( - const cu_cp_pdu_session_resource_release_command& release_cmd, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& up_resource_mng) -{ - return launch_async(release_cmd, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_task_sched, - up_resource_mng, - logger); -} - -async_task -cu_cp_routine_manager::start_ue_context_release_routine(const cu_cp_ue_context_release_command& command, - e1ap_bearer_context_manager* e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - cu_cp_ue_removal_handler& ue_removal_handler) -{ - return launch_async( - command, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, ue_removal_handler, ue_mng, logger); -} - -async_task cu_cp_routine_manager::start_reestablishment_context_modification_routine( - ue_index_t ue_index, - const security::sec_as_config& up_sec, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& ue_up_resource_manager) -{ - return launch_async(ue_index, - up_sec, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - cu_cp_notifier, - ue_task_sched, - ue_up_resource_manager, - logger); -} - -async_task -cu_cp_routine_manager::start_inter_du_handover_routine(const cu_cp_inter_du_handover_request& request, - const byte_buffer& target_cell_sib1, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& source_f1ap_ue_ctxt_mng, - f1ap_ue_context_manager& target_f1ap_ue_ctxt_mng, - cu_cp_ue_context_release_handler& ue_context_release_handler, - cu_cp_ue_removal_handler& ue_removal_handler, - cu_cp_ue_context_manipulation_handler& cu_cp_handler) -{ - return launch_async(request, - target_cell_sib1, - e1ap_bearer_ctxt_mng, - source_f1ap_ue_ctxt_mng, - target_f1ap_ue_ctxt_mng, - ue_context_release_handler, - ue_removal_handler, - cu_cp_handler, - ue_mng, - logger); -} - -async_task -cu_cp_routine_manager::start_inter_cu_handover_target_routine(const ngap_handover_request& request_, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - cu_cp_ue_removal_handler& ue_removal_handler) -{ - return launch_async(request_, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - ue_removal_handler, - ue_mng, - default_security_indication, - logger); -} diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h deleted file mode 100644 index f9769a500d..0000000000 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h +++ /dev/null @@ -1,111 +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 "../cu_cp_controller/common_task_scheduler.h" -#include "../ue_manager/ue_manager_impl.h" -#include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/support/async/fifo_async_task_scheduler.h" -#include - -namespace srsran { -namespace srs_cu_cp { - -/// \brief Service provided by CU-CP to handle routines. -class cu_cp_routine_manager : public common_task_scheduler -{ -public: - explicit cu_cp_routine_manager(ue_manager& ue_mng_, - const security_indication_t& default_security_indication_, - srslog::basic_logger& logger_); - ~cu_cp_routine_manager() = default; - - bool schedule_async_task(async_task task) override; - - async_task> - start_initial_context_setup_routine(const ngap_init_context_setup_request& request, - rrc_ue_interface& rrc_ue, - ngap_ue_radio_capability_management_handler& ngap_ue_radio_cap_handler, - ue_security_manager& security_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - cu_cp_ngap_handler& pdu_session_setup_handler); - - async_task - start_pdu_session_resource_setup_routine(const cu_cp_pdu_session_resource_setup_request& setup_msg, - const srsran::security::sec_as_config& security_cfg, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& up_resource_mng); - - async_task - start_pdu_session_resource_release_routine(const cu_cp_pdu_session_resource_release_command& release_cmd, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& up_resource_mng); - - async_task - start_pdu_session_resource_modification_routine(const cu_cp_pdu_session_resource_modify_request& modify_msg, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& up_resource_mng); - - async_task - start_ue_context_release_routine(const cu_cp_ue_context_release_command& command, - e1ap_bearer_context_manager* e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - cu_cp_ue_removal_handler& ue_removal_handler); - - async_task - start_reestablishment_context_modification_routine(ue_index_t ue_index, - const srsran::security::sec_as_config& up_security_cfg, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - cu_cp_rrc_ue_interface& cu_cp_notifier, - ue_task_scheduler& ue_task_sched, - up_resource_manager& ue_up_resource_manager); - - async_task - start_inter_du_handover_routine(const cu_cp_inter_du_handover_request& request, - const byte_buffer& target_cell_sib1, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& source_f1ap_ue_ctxt_mng, - f1ap_ue_context_manager& target_f1ap_ue_ctxt_mng, - cu_cp_ue_context_release_handler& ue_context_release_handler, - cu_cp_ue_removal_handler& ue_removal_handler, - cu_cp_ue_context_manipulation_handler& cu_cp_handler); - - async_task - start_inter_cu_handover_target_routine(const ngap_handover_request& request_, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng, - cu_cp_ue_removal_handler& ue_removal_handler); - -private: - ue_manager& ue_mng; - const security_indication_t& default_security_indication; - srslog::basic_logger& logger; - - // cu-cp task event loop - fifo_async_task_scheduler main_ctrl_loop; -}; - -} // namespace srs_cu_cp -} // namespace srsran From 73551bd29ad24e77f6a02f807739855e2bbe522e Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 31 Jul 2024 09:35:01 +0200 Subject: [PATCH 011/407] cu_cp: remove unused ue manager from cu-cp controller --- lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp | 3 --- lib/cu_cp/cu_cp_controller/cu_cp_controller.h | 2 -- lib/cu_cp/cu_cp_impl.cpp | 1 - 3 files changed, 6 deletions(-) diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp index 54f12fe1c5..b038bd4bfc 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp @@ -18,13 +18,11 @@ using namespace srs_cu_cp; cu_cp_controller::cu_cp_controller(const cu_cp_configuration& config_, common_task_scheduler& common_task_sched_, - ue_manager& ue_mng_, ngap_connection_manager& ngap_conn_mng_, cu_up_processor_repository& cu_ups_, du_processor_repository& dus_, task_executor& ctrl_exec_) : cfg(config_), - ue_mng(ue_mng_), common_task_sched(common_task_sched_), ctrl_exec(ctrl_exec_), logger(srslog::fetch_basic_logger("CU-CP")), @@ -32,7 +30,6 @@ cu_cp_controller::cu_cp_controller(const cu_cp_configuration& config_, du_mng(cfg.admission.max_nof_dus, dus_, ctrl_exec, common_task_sched_), cu_up_mng(cfg.admission.max_nof_cu_ups, cu_ups_, ctrl_exec, common_task_sched_) { - (void)ue_mng; } void cu_cp_controller::stop() diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h index 418ea45405..3ea4eda6dd 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h @@ -36,7 +36,6 @@ class cu_cp_controller : public cu_cp_ue_admission_controller public: cu_cp_controller(const cu_cp_configuration& config_, common_task_scheduler& common_task_sched_, - ue_manager& ue_mng_, ngap_connection_manager& ngap_conn_mng_, cu_up_processor_repository& cu_ups_, du_processor_repository& dus_, @@ -58,7 +57,6 @@ class cu_cp_controller : public cu_cp_ue_admission_controller void stop_impl(); const cu_cp_configuration& cfg; - ue_manager& ue_mng; common_task_scheduler& common_task_sched; task_executor& ctrl_exec; srslog::basic_logger& logger; diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 0c8cdff1a7..119ed783ce 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -95,7 +95,6 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : controller = std::make_unique(cfg, common_task_sched, - ue_mng, ngap_entity->get_ngap_connection_manager(), cu_up_db, du_db, From 713d753886a8168e9c07bcc3eafa2dd777b5f972 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 26 Jul 2024 16:58:16 +0100 Subject: [PATCH 012/407] pdcp,gw: fix rx benchmakarks Fix race condition on termination of the io broker. Also fix running out of buffers in the RX benchmark of the PDCP and failing the PDU generation stage by not having transmit notifications. --- tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp | 2 ++ .../gateways/udp_network_gateway_rx_benchmark.cpp | 2 ++ tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp | 6 +++++- tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp b/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp index 0e18c0f386..e54fec1300 100644 --- a/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp +++ b/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp @@ -133,6 +133,8 @@ int main(int argc, char** argv) fmt::print("Tx done\n\n"); std::this_thread::sleep_for(std::chrono::milliseconds(750)); + gw1.reset(); + gw2.reset(); uint64_t tx_duration_us = duration.count(); uint64_t rx_duration_us = gw2_dn.get_t_rx().count(); diff --git a/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp b/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp index 2ff1216581..a8951b285d 100644 --- a/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp +++ b/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp @@ -114,6 +114,8 @@ int main(int argc, char** argv) std::this_thread::sleep_for(std::chrono::milliseconds(750)); + gw.reset(); + uint64_t rx_duration_us = gw_dn.get_t_rx().count(); uint64_t rx_bytes = gw_dn.get_rx_bytes(); uint64_t rx_bits = rx_bytes * 8; diff --git a/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp b/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp index 3370d3ea35..56aa9b7bc5 100644 --- a/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp +++ b/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp @@ -123,11 +123,13 @@ std::vector gen_pdu_list(bench_params params // Set TX config pdcp_tx_config config = {}; config.rb_type = pdcp_rb_type::drb; - config.rlc_mode = pdcp_rlc_mode::am; + config.rlc_mode = pdcp_rlc_mode::um; config.sn_size = pdcp_sn_size::size18bits; config.direction = pdcp_security_direction::uplink; config.discard_timer = pdcp_discard_timer::ms10; config.status_report_required = false; + config.custom.rlc_sdu_queue = params.nof_repetitions; + config.custom.test_mode = true; // imediatly notify transmit notification to avoid buffering security::sec_128_as_config sec_cfg = {}; @@ -252,6 +254,8 @@ int run_benchmark(bench_params params, int algo) security::integrity_algorithm int_algo = static_cast(algo); security::ciphering_algorithm ciph_algo = static_cast(algo); + init_byte_buffer_segment_pool(1048576, byte_buffer_segment_pool_default_segment_size()); + if (algo == 0) { benchmark_pdcp_rx(params, security::integrity_enabled::off, diff --git a/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp b/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp index aa69ef574d..315aee54d2 100644 --- a/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp +++ b/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp @@ -174,6 +174,8 @@ int run_benchmark(bench_params params, int algo) auto int_algo = static_cast(algo); auto ciph_algo = static_cast(algo); + init_byte_buffer_segment_pool(1048576, byte_buffer_segment_pool_default_segment_size()); + if (algo == 0) { benchmark_pdcp_tx(params, security::integrity_enabled::off, From 9b2ff7679c7607381e9f583d79675617adbecd3f Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 26 Jul 2024 13:54:23 +0200 Subject: [PATCH 013/407] sched: make one metrics handler object per cell to ensure thread-safety --- lib/scheduler/config/sched_config_manager.cpp | 28 +++++++++---------- lib/scheduler/config/sched_config_manager.h | 21 +++++++------- .../logging/scheduler_metric_handler.cpp | 19 +++++++++++++ .../logging/scheduler_metrics_handler.h | 17 +++++++++++ lib/scheduler/scheduler_impl.cpp | 13 ++++++--- lib/scheduler/scheduler_impl.h | 2 +- .../test_utils/config_generators.cpp | 4 +-- .../ue_scheduling/fallback_scheduler_test.cpp | 4 +-- .../ue_scheduling/ue_grid_allocator_test.cpp | 5 ++-- 9 files changed, 77 insertions(+), 36 deletions(-) diff --git a/lib/scheduler/config/sched_config_manager.cpp b/lib/scheduler/config/sched_config_manager.cpp index 0d4fc22413..d4c6fb03e7 100644 --- a/lib/scheduler/config/sched_config_manager.cpp +++ b/lib/scheduler/config/sched_config_manager.cpp @@ -55,17 +55,16 @@ void ue_config_delete_event::reset() } } -sched_config_manager::sched_config_manager(const scheduler_config& sched_cfg, - sched_metrics_ue_configurator& metrics_handler_) : +sched_config_manager::sched_config_manager(const scheduler_config& sched_cfg) : expert_params(sched_cfg.expert_params), config_notifier(sched_cfg.config_notifier), - metrics_handler(metrics_handler_), logger(srslog::fetch_basic_logger("SCHED")) { std::fill(ue_to_cell_group_index.begin(), ue_to_cell_group_index.end(), INVALID_DU_CELL_GROUP_INDEX); } -const cell_configuration* sched_config_manager::add_cell(const sched_cell_configuration_request_message& msg) +const cell_configuration* sched_config_manager::add_cell(const sched_cell_configuration_request_message& msg, + sched_metrics_ue_configurator& metrics_handler_) { srsran_assert(msg.cell_index < MAX_NOF_DU_CELLS, "cell index={} is not valid", msg.cell_index); srsran_assert(not added_cells.contains(msg.cell_index), "cell={} already exists", msg.cell_index); @@ -75,11 +74,9 @@ const cell_configuration* sched_config_manager::add_cell(const sched_cell_config srsran_assert(ret.has_value(), "Invalid cell configuration request message. Cause: {}", ret.error().c_str()); added_cells.emplace(msg.cell_index, std::make_unique(expert_params, msg)); + cell_metrics.emplace(msg.cell_index, &metrics_handler_); - // Update DU cell index to group lookup. - du_cell_to_cell_group_index.emplace(msg.cell_index, msg.cell_group_index); - - return &*added_cells[msg.cell_index]; + return added_cells[msg.cell_index].get(); } ue_config_update_event sched_config_manager::add_ue(const sched_ue_creation_request_message& cfg_req) @@ -192,11 +189,12 @@ void sched_config_manager::handle_ue_config_complete(du_ue_index_t ue_index, std if (ue_cfg_list[ue_index] == nullptr) { // UE creation case. - metrics_handler.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); + cell_metrics[next_cfg->pcell_common_cfg().cell_index]->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); } // Stores new UE config and deletes old config. @@ -218,11 +216,13 @@ void sched_config_manager::handle_ue_config_complete(du_ue_index_t ue_index, std void sched_config_manager::handle_ue_delete_complete(du_ue_index_t ue_index) { + du_cell_index_t pcell_idx = ue_cfg_list[ue_index]->pcell_common_cfg().cell_index; + // Deletes UE config. ue_cfg_list[ue_index].reset(); // Remove UE from metrics. - metrics_handler.handle_ue_deletion(ue_index); + cell_metrics[pcell_idx]->handle_ue_deletion(ue_index); // Mark the UE as released. ue_to_cell_group_index[ue_index].store(INVALID_DU_CELL_GROUP_INDEX, std::memory_order_release); diff --git a/lib/scheduler/config/sched_config_manager.h b/lib/scheduler/config/sched_config_manager.h index 721a1ea07c..2c7ada9166 100644 --- a/lib/scheduler/config/sched_config_manager.h +++ b/lib/scheduler/config/sched_config_manager.h @@ -98,9 +98,10 @@ class sched_ue_configuration_handler class sched_config_manager { public: - sched_config_manager(const scheduler_config& sched_cfg_, sched_metrics_ue_configurator& metrics_handler_); + sched_config_manager(const scheduler_config& sched_cfg_); - const cell_configuration* add_cell(const sched_cell_configuration_request_message& msg); + const cell_configuration* add_cell(const sched_cell_configuration_request_message& msg, + sched_metrics_ue_configurator& metrics_handler_); ue_config_update_event add_ue(const sched_ue_creation_request_message& cfg_req); @@ -112,8 +113,7 @@ class sched_config_manager du_cell_group_index_t get_cell_group_index(du_cell_index_t cell_index) const { - return du_cell_to_cell_group_index.contains(cell_index) ? du_cell_to_cell_group_index[cell_index] - : INVALID_DU_CELL_GROUP_INDEX; + return added_cells.contains(cell_index) ? added_cells[cell_index]->cell_group_index : INVALID_DU_CELL_GROUP_INDEX; } du_cell_group_index_t get_cell_group_index(du_ue_index_t ue_index) const @@ -131,18 +131,17 @@ class sched_config_manager void handle_ue_config_complete(du_ue_index_t ue_index, std::unique_ptr next_cfg); void handle_ue_delete_complete(du_ue_index_t ue_index); - const scheduler_expert_config expert_params; - sched_configuration_notifier& config_notifier; - sched_metrics_ue_configurator& metrics_handler; - srslog::basic_logger& logger; + const scheduler_expert_config expert_params; + sched_configuration_notifier& config_notifier; + srslog::basic_logger& logger; // List of common configs for the scheduler cells. cell_common_configuration_list added_cells; - std::array, MAX_NOF_DU_UES> ue_cfg_list; + // List of metrics handlers for each cell. + slotted_id_table cell_metrics; - /// Mapping of DU cells to DU Cell Groups. - slotted_id_table du_cell_to_cell_group_index; + std::array, MAX_NOF_DU_UES> ue_cfg_list; /// Mapping of UEs to DU Cell Groups. std::array, MAX_NOF_DU_UES> ue_to_cell_group_index; diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 09fc59c6f9..cb7fc97fc1 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -9,6 +9,7 @@ */ #include "scheduler_metrics_handler.h" +#include "srsran/srslog/srslog.h" using namespace srsran; @@ -328,3 +329,21 @@ void scheduler_metrics_handler::ue_metric_context::reset() // Note: for BSR and CQI we just keep the last without resetting the value at every slot. data = {}; } + +main_scheduler_metrics_handler::main_scheduler_metrics_handler(msecs metrics_report_period, + scheduler_metrics_notifier& notifier_) : + notifier(notifier_), report_period(metrics_report_period) +{ +} + +scheduler_metrics_handler* main_scheduler_metrics_handler::add_cell(du_cell_index_t cell_idx) +{ + if (cells.contains(cell_idx)) { + srslog::fetch_basic_logger("SCHED").warning("Cell={} already exists", cell_idx); + return nullptr; + } + + cells.emplace(cell_idx, report_period, notifier); + + return &cells[cell_idx]; +} diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index d54d7c029e..3f446d667f 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -143,4 +143,21 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche void handle_slot_result(const sched_result& slot_result, std::chrono::microseconds slot_decision_latency); }; +class main_scheduler_metrics_handler +{ + using msecs = std::chrono::milliseconds; + +public: + /// \brief Creates a scheduler metrics handler. In case the metrics_report_period is zero, no metrics are reported. + explicit main_scheduler_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); + + scheduler_metrics_handler* add_cell(du_cell_index_t cell_idx); + +private: + scheduler_metrics_notifier& notifier; + const std::chrono::milliseconds report_period; + + slotted_array cells; +}; + } // namespace srsran diff --git a/lib/scheduler/scheduler_impl.cpp b/lib/scheduler/scheduler_impl.cpp index fa72b55892..afa0a31c2e 100644 --- a/lib/scheduler/scheduler_impl.cpp +++ b/lib/scheduler/scheduler_impl.cpp @@ -20,13 +20,18 @@ scheduler_impl::scheduler_impl(const scheduler_config& sched_cfg_) : config_notifier(sched_cfg_.config_notifier), logger(srslog::fetch_basic_logger("SCHED")), metrics(expert_params.metrics_report_period, sched_cfg_.metrics_notifier), - cfg_mng(sched_cfg_, metrics) + cfg_mng(sched_cfg_) { } bool scheduler_impl::handle_cell_configuration_request(const sched_cell_configuration_request_message& msg) { - const cell_configuration* cell_cfg = cfg_mng.add_cell(msg); + scheduler_metrics_handler* cell_metrics = metrics.add_cell(msg.cell_index); + if (cell_metrics == nullptr) { + return false; + } + + const cell_configuration* cell_cfg = cfg_mng.add_cell(msg, *cell_metrics); if (cell_cfg == nullptr) { return false; } @@ -35,13 +40,13 @@ bool scheduler_impl::handle_cell_configuration_request(const sched_cell_configur if (not groups.contains(msg.cell_group_index)) { // If it is a new group, create a new instance. groups.emplace(msg.cell_group_index, - std::make_unique(expert_params.ue, config_notifier, metrics)); + std::make_unique(expert_params.ue, config_notifier, *cell_metrics)); } // Create a new cell scheduler instance. cells.emplace( msg.cell_index, - std::make_unique(expert_params, msg, *cell_cfg, *groups[msg.cell_group_index], metrics)); + std::make_unique(expert_params, msg, *cell_cfg, *groups[msg.cell_group_index], *cell_metrics)); return true; } diff --git a/lib/scheduler/scheduler_impl.h b/lib/scheduler/scheduler_impl.h index 2390050a0c..34b2746c63 100644 --- a/lib/scheduler/scheduler_impl.h +++ b/lib/scheduler/scheduler_impl.h @@ -61,7 +61,7 @@ class scheduler_impl final : public mac_scheduler srslog::basic_logger& logger; // Slot metrics sink. - scheduler_metrics_handler metrics; + main_scheduler_metrics_handler metrics; // Manager of configurations forwarded to the scheduler. sched_config_manager cfg_mng; diff --git a/tests/unittests/scheduler/test_utils/config_generators.cpp b/tests/unittests/scheduler/test_utils/config_generators.cpp index c1fb73d106..c65c224c0b 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.cpp +++ b/tests/unittests/scheduler/test_utils/config_generators.cpp @@ -51,7 +51,7 @@ test_sched_config_manager::test_sched_config_manager(const cell_config_builder_p cfg_notifier(std::make_unique()), metric_notifier(std::make_unique()), ue_metrics_configurator(std::make_unique()), - cfg_mng(scheduler_config{expert_cfg, *cfg_notifier, *metric_notifier}, *ue_metrics_configurator) + cfg_mng(scheduler_config{expert_cfg, *cfg_notifier, *metric_notifier}) { default_cell_req = test_helpers::make_default_sched_cell_configuration_request(builder_params); default_ue_req = test_helpers::create_default_sched_ue_creation_request(builder_params, {lcid_t::LCID_MIN_DRB}); @@ -61,7 +61,7 @@ test_sched_config_manager::~test_sched_config_manager() {} const cell_configuration* test_sched_config_manager::add_cell(const sched_cell_configuration_request_message& msg) { - return cfg_mng.add_cell(msg); + return cfg_mng.add_cell(msg, *ue_metrics_configurator); } const ue_configuration* test_sched_config_manager::add_ue(const sched_ue_creation_request_message& cfg_req) diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index ac215e27ce..de23b4a69c 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -81,7 +81,7 @@ struct test_bench { scheduler_ue_metrics_dummy_configurator metrics_ue_handler; cell_config_builder_params builder_params; - sched_config_manager cfg_mng{scheduler_config{sched_cfg, dummy_notif, metrics_notif}, metrics_ue_handler}; + sched_config_manager cfg_mng{scheduler_config{sched_cfg, dummy_notif, metrics_notif}}; const cell_configuration& cell_cfg; cell_resource_allocator res_grid{cell_cfg}; @@ -98,7 +98,7 @@ struct test_bench { const sched_cell_configuration_request_message& cell_req) : sched_cfg{sched_cfg_}, builder_params{builder_params_}, - cell_cfg{*[&]() { return cfg_mng.add_cell(cell_req); }()}, + cell_cfg{*[&]() { return cfg_mng.add_cell(cell_req, metrics_ue_handler); }()}, ue_alloc(expert_cfg, ue_db, srslog::fetch_basic_logger("SCHED", true)), fallback_sched(expert_cfg, cell_cfg, pdcch_sch, pucch_alloc, ue_db), csi_rs_sched(cell_cfg) diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 9d61caa05a..5a64d9a98a 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -37,7 +37,8 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam GetParam() == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; cfg_builder_params.band = band_helper::get_band_from_dl_arfcn(cfg_builder_params.dl_arfcn); cfg_builder_params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; - auto* cfg = cfg_mng.add_cell(test_helpers::make_default_sched_cell_configuration_request(cfg_builder_params)); + auto* cfg = cfg_mng.add_cell(test_helpers::make_default_sched_cell_configuration_request(cfg_builder_params), + metrics_ue_handler); srsran_assert(cfg != nullptr, "Cell configuration failed"); return cfg; }()), @@ -110,7 +111,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam scheduler_harq_timeout_dummy_handler harq_timeout_handler; cell_config_builder_params cfg_builder_params; - sched_config_manager cfg_mng{scheduler_config{sched_cfg, mac_notif, metrics_notif}, metrics_ue_handler}; + sched_config_manager cfg_mng{scheduler_config{sched_cfg, mac_notif, metrics_notif}}; const cell_configuration& cell_cfg; cell_resource_allocator res_grid{cell_cfg}; From ae8cc40739c3314a4e78e876e61be420bb57b3c0 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 26 Jul 2024 14:04:48 +0200 Subject: [PATCH 014/407] sched: rename metric handler classes --- lib/scheduler/cell_scheduler.cpp | 2 +- lib/scheduler/cell_scheduler.h | 12 ++-- .../logging/scheduler_metric_handler.cpp | 59 +++++++++---------- .../logging/scheduler_metrics_handler.h | 18 +++--- lib/scheduler/scheduler_impl.cpp | 2 +- lib/scheduler/scheduler_impl.h | 2 +- .../ue_scheduling/ue_event_manager.cpp | 2 +- .../ue_scheduling/ue_event_manager.h | 10 ++-- .../ue_scheduling/ue_scheduler_impl.cpp | 2 +- .../ue_scheduling/ue_scheduler_impl.h | 2 +- .../scheduler_metrics_handler_test.cpp | 2 +- 11 files changed, 57 insertions(+), 56 deletions(-) diff --git a/lib/scheduler/cell_scheduler.cpp b/lib/scheduler/cell_scheduler.cpp index e8106b1085..8d2e3efc5f 100644 --- a/lib/scheduler/cell_scheduler.cpp +++ b/lib/scheduler/cell_scheduler.cpp @@ -18,7 +18,7 @@ cell_scheduler::cell_scheduler(const scheduler_expert_config& s const sched_cell_configuration_request_message& msg, const cell_configuration& cell_cfg_, ue_scheduler& ue_sched_, - scheduler_metrics_handler& metrics_handler) : + cell_metrics_handler& metrics_handler) : cell_cfg(cell_cfg_), ue_sched(ue_sched_), res_grid(cell_cfg), diff --git a/lib/scheduler/cell_scheduler.h b/lib/scheduler/cell_scheduler.h index 8a04ba8cc0..fb7e55bb04 100644 --- a/lib/scheduler/cell_scheduler.h +++ b/lib/scheduler/cell_scheduler.h @@ -30,7 +30,7 @@ namespace srsran { -class scheduler_metrics_handler; +class cell_metrics_handler; /// \brief This class holds all the resources that are specific to a cell. /// This includes the SIB and RA scheduler objects, PDCCH scheduler object, the cell resource grid, etc. @@ -41,7 +41,7 @@ class cell_scheduler const sched_cell_configuration_request_message& msg, const cell_configuration& cell_cfg, ue_scheduler& ue_sched, - scheduler_metrics_handler& metrics); + cell_metrics_handler& metrics); void run_slot(slot_point sl_tx); @@ -63,10 +63,10 @@ class cell_scheduler cell_resource_allocator res_grid; /// Logger of cell events and scheduling results. - scheduler_event_logger event_logger; - scheduler_metrics_handler& metrics; - scheduler_result_logger result_logger; - srslog::basic_logger& logger; + scheduler_event_logger event_logger; + cell_metrics_handler& metrics; + scheduler_result_logger result_logger; + srslog::basic_logger& logger; ssb_scheduler ssb_sch; pdcch_resource_allocator_impl pdcch_sch; diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index cb7fc97fc1..26f32de14a 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -13,17 +13,16 @@ using namespace srsran; -scheduler_metrics_handler::scheduler_metrics_handler(msecs metrics_report_period, - scheduler_metrics_notifier& notifier_) : +cell_metrics_handler::cell_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier_) : notifier(notifier_), report_period(metrics_report_period) { } -void scheduler_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, + unsigned num_slots_per_frame) { ues.emplace(ue_index); ues[ue_index].rnti = rnti; @@ -34,7 +33,7 @@ void scheduler_metrics_handler::handle_ue_creation(du_ue_index_t ue_index, rnti_to_ue_index_lookup.emplace(rnti, ue_index); } -void scheduler_metrics_handler::handle_ue_deletion(du_ue_index_t ue_index) +void cell_metrics_handler::handle_ue_deletion(du_ue_index_t ue_index) { if (ues.contains(ue_index)) { rnti_to_ue_index_lookup.erase(ues[ue_index].rnti); @@ -42,7 +41,7 @@ void scheduler_metrics_handler::handle_ue_deletion(du_ue_index_t ue_index) } } -void scheduler_metrics_handler::handle_crc_indication(const ul_crc_pdu_indication& crc_pdu, units::bytes tbs) +void cell_metrics_handler::handle_crc_indication(const ul_crc_pdu_indication& crc_pdu, units::bytes tbs) { if (ues.contains(crc_pdu.ue_index)) { auto& u = ues[crc_pdu.ue_index]; @@ -65,13 +64,13 @@ void scheduler_metrics_handler::handle_crc_indication(const ul_crc_pdu_indicatio } } -void scheduler_metrics_handler::handle_pucch_sinr(ue_metric_context& u, float sinr) +void cell_metrics_handler::handle_pucch_sinr(ue_metric_context& u, float sinr) { u.data.nof_pucch_snr_reports++; u.data.sum_pucch_snrs += sinr; } -void scheduler_metrics_handler::handle_csi_report(ue_metric_context& u, const csi_report_data& csi) +void cell_metrics_handler::handle_csi_report(ue_metric_context& u, const csi_report_data& csi) { // Add new CQI and RI observations if they are available in the CSI report. if (csi.first_tb_wideband_cqi.has_value()) { @@ -82,7 +81,7 @@ void scheduler_metrics_handler::handle_csi_report(ue_metric_context& u, const cs } } -void scheduler_metrics_handler::handle_dl_harq_ack(du_ue_index_t ue_index, bool ack, units::bytes tbs) +void cell_metrics_handler::handle_dl_harq_ack(du_ue_index_t ue_index, bool ack, units::bytes tbs) { if (ues.contains(ue_index)) { auto& u = ues[ue_index]; @@ -94,7 +93,7 @@ void scheduler_metrics_handler::handle_dl_harq_ack(du_ue_index_t ue_index, bool } } -void scheduler_metrics_handler::handle_harq_timeout(du_ue_index_t ue_index, bool is_dl) +void cell_metrics_handler::handle_harq_timeout(du_ue_index_t ue_index, bool is_dl) { if (ues.contains(ue_index)) { auto& u = ues[ue_index]; @@ -106,7 +105,7 @@ void scheduler_metrics_handler::handle_harq_timeout(du_ue_index_t ue_index, bool } } -void scheduler_metrics_handler::handle_uci_pdu_indication(const uci_indication::uci_pdu& pdu) +void cell_metrics_handler::handle_uci_pdu_indication(const uci_indication::uci_pdu& pdu) { if (ues.contains(pdu.ue_index)) { auto& u = ues[pdu.ue_index]; @@ -142,7 +141,7 @@ void scheduler_metrics_handler::handle_uci_pdu_indication(const uci_indication:: } } -void scheduler_metrics_handler::handle_ul_bsr_indication(const ul_bsr_indication_message& bsr) +void cell_metrics_handler::handle_ul_bsr_indication(const ul_bsr_indication_message& bsr) { if (ues.contains(bsr.ue_index)) { auto& u = ues[bsr.ue_index]; @@ -156,7 +155,7 @@ void scheduler_metrics_handler::handle_ul_bsr_indication(const ul_bsr_indication } } -void scheduler_metrics_handler::handle_ul_phr_indication(const ul_phr_indication_message& phr_ind) +void cell_metrics_handler::handle_ul_phr_indication(const ul_phr_indication_message& phr_ind) { if (ues.contains(phr_ind.ue_index)) { auto& u = ues[phr_ind.ue_index]; @@ -170,7 +169,7 @@ void scheduler_metrics_handler::handle_ul_phr_indication(const ul_phr_indication } } -void scheduler_metrics_handler::handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& dl_bs) +void cell_metrics_handler::handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& dl_bs) { if (ues.contains(dl_bs.ue_index)) { auto& u = ues[dl_bs.ue_index]; @@ -180,12 +179,12 @@ void scheduler_metrics_handler::handle_dl_buffer_state_indication(const dl_buffe } } -void scheduler_metrics_handler::handle_error_indication() +void cell_metrics_handler::handle_error_indication() { error_indication_counter++; } -void scheduler_metrics_handler::report_metrics() +void cell_metrics_handler::report_metrics() { next_report.ue_metrics.clear(); @@ -207,8 +206,8 @@ void scheduler_metrics_handler::report_metrics() notifier.report_metrics(next_report); } -void scheduler_metrics_handler::handle_slot_result(const sched_result& slot_result, - std::chrono::microseconds slot_decision_latency) +void cell_metrics_handler::handle_slot_result(const sched_result& slot_result, + std::chrono::microseconds slot_decision_latency) { for (const dl_msg_alloc& dl_grant : slot_result.dl.ue_grants) { auto it = rnti_to_ue_index_lookup.find(dl_grant.pdsch_cfg.rnti); @@ -256,16 +255,16 @@ void scheduler_metrics_handler::handle_slot_result(const sched_result& slo decision_latency_hist[bin_idx]++; } -void scheduler_metrics_handler::handle_ul_delay(du_ue_index_t ue_index, double delay) +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)); } } -void scheduler_metrics_handler::push_result(slot_point sl_tx, - const sched_result& slot_result, - std::chrono::microseconds slot_decision_latency) +void cell_metrics_handler::push_result(slot_point sl_tx, + const sched_result& slot_result, + std::chrono::microseconds slot_decision_latency) { if (report_period_slots == 0) { // The SCS common is now known. @@ -283,7 +282,7 @@ void scheduler_metrics_handler::push_result(slot_point sl_tx, } scheduler_ue_metrics -scheduler_metrics_handler::ue_metric_context::compute_report(std::chrono::milliseconds metric_report_period) +cell_metrics_handler::ue_metric_context::compute_report(std::chrono::milliseconds metric_report_period) { scheduler_ue_metrics ret{}; ret.pci = pci; @@ -324,19 +323,19 @@ scheduler_metrics_handler::ue_metric_context::compute_report(std::chrono::millis return ret; } -void scheduler_metrics_handler::ue_metric_context::reset() +void cell_metrics_handler::ue_metric_context::reset() { // Note: for BSR and CQI we just keep the last without resetting the value at every slot. data = {}; } -main_scheduler_metrics_handler::main_scheduler_metrics_handler(msecs metrics_report_period, - scheduler_metrics_notifier& notifier_) : +scheduler_metrics_handler::scheduler_metrics_handler(msecs metrics_report_period, + scheduler_metrics_notifier& notifier_) : notifier(notifier_), report_period(metrics_report_period) { } -scheduler_metrics_handler* main_scheduler_metrics_handler::add_cell(du_cell_index_t cell_idx) +cell_metrics_handler* scheduler_metrics_handler::add_cell(du_cell_index_t cell_idx) { if (cells.contains(cell_idx)) { srslog::fetch_basic_logger("SCHED").warning("Cell={} already exists", cell_idx); diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index 3f446d667f..8e622fd4e3 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -20,8 +20,8 @@ namespace srsran { -///\brief Handler of scheduler slot metrics. -class scheduler_metrics_handler final : public harq_timeout_handler, public sched_metrics_ue_configurator +///\brief Handler of scheduler slot metrics for a given cell. +class cell_metrics_handler final : public harq_timeout_handler, public sched_metrics_ue_configurator { using msecs = std::chrono::milliseconds; using usecs = std::chrono::microseconds; @@ -91,8 +91,9 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche scheduler_cell_metrics next_report; public: - /// \brief Creates a scheduler UE metrics handler. In case the metrics_report_period is zero, no metrics are reported. - explicit scheduler_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); + /// \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); /// \brief Register creation of a UE. void handle_ue_creation(du_ue_index_t ue_index, @@ -143,21 +144,22 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche void handle_slot_result(const sched_result& slot_result, std::chrono::microseconds slot_decision_latency); }; -class main_scheduler_metrics_handler +/// Handler of metrics for all the UEs and cells of the scheduler. +class scheduler_metrics_handler { using msecs = std::chrono::milliseconds; public: /// \brief Creates a scheduler metrics handler. In case the metrics_report_period is zero, no metrics are reported. - explicit main_scheduler_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); + explicit scheduler_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); - scheduler_metrics_handler* add_cell(du_cell_index_t cell_idx); + cell_metrics_handler* add_cell(du_cell_index_t cell_idx); private: scheduler_metrics_notifier& notifier; const std::chrono::milliseconds report_period; - slotted_array cells; + slotted_array cells; }; } // namespace srsran diff --git a/lib/scheduler/scheduler_impl.cpp b/lib/scheduler/scheduler_impl.cpp index afa0a31c2e..35bb4c7d91 100644 --- a/lib/scheduler/scheduler_impl.cpp +++ b/lib/scheduler/scheduler_impl.cpp @@ -26,7 +26,7 @@ scheduler_impl::scheduler_impl(const scheduler_config& sched_cfg_) : bool scheduler_impl::handle_cell_configuration_request(const sched_cell_configuration_request_message& msg) { - scheduler_metrics_handler* cell_metrics = metrics.add_cell(msg.cell_index); + cell_metrics_handler* cell_metrics = metrics.add_cell(msg.cell_index); if (cell_metrics == nullptr) { return false; } diff --git a/lib/scheduler/scheduler_impl.h b/lib/scheduler/scheduler_impl.h index 34b2746c63..2390050a0c 100644 --- a/lib/scheduler/scheduler_impl.h +++ b/lib/scheduler/scheduler_impl.h @@ -61,7 +61,7 @@ class scheduler_impl final : public mac_scheduler srslog::basic_logger& logger; // Slot metrics sink. - main_scheduler_metrics_handler metrics; + scheduler_metrics_handler metrics; // Manager of configurations forwarded to the scheduler. sched_config_manager cfg_mng; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index b0eb161b6d..7e0a72fb00 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -106,7 +106,7 @@ class ue_event_manager::ue_dl_buffer_occupancy_manager final : public scheduler_ static constexpr size_t INITIAL_COMMON_EVENT_LIST_SIZE = MAX_NOF_DU_UES; static constexpr size_t INITIAL_CELL_EVENT_LIST_SIZE = MAX_NOF_DU_UES; -ue_event_manager::ue_event_manager(ue_repository& ue_db_, scheduler_metrics_handler& metrics_handler_) : +ue_event_manager::ue_event_manager(ue_repository& ue_db_, cell_metrics_handler& metrics_handler_) : ue_db(ue_db_), metrics_handler(metrics_handler_), logger(srslog::fetch_basic_logger("SCHED")), diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.h b/lib/scheduler/ue_scheduling/ue_event_manager.h index ba5003d5a1..5872174f52 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.h +++ b/lib/scheduler/ue_scheduling/ue_event_manager.h @@ -20,7 +20,7 @@ namespace srsran { -class scheduler_metrics_handler; +class cell_metrics_handler; class scheduler_event_logger; class uci_scheduler_impl; @@ -32,7 +32,7 @@ class ue_event_manager final : public sched_ue_configuration_handler, public scheduler_dl_buffer_state_indication_handler { public: - ue_event_manager(ue_repository& ue_db, scheduler_metrics_handler& metrics_handler); + ue_event_manager(ue_repository& ue_db, cell_metrics_handler& metrics_handler); ~ue_event_manager(); void add_cell(cell_resource_allocator& cell_res_grid, @@ -105,9 +105,9 @@ class ue_event_manager final : public sched_ue_configuration_handler, std::optional pucch_snr); void handle_csi(ue_cell& ue_cc, const csi_report_data& csi_rep); - ue_repository& ue_db; - scheduler_metrics_handler& metrics_handler; - srslog::basic_logger& logger; + ue_repository& ue_db; + cell_metrics_handler& metrics_handler; + srslog::basic_logger& logger; /// List of added and configured cells. struct du_cell { diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index dbc19a2302..51dcae3a53 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -15,7 +15,7 @@ using namespace srsran; ue_scheduler_impl::ue_scheduler_impl(const scheduler_ue_expert_config& expert_cfg_, sched_configuration_notifier& mac_notif, - scheduler_metrics_handler& metric_handler) : + cell_metrics_handler& metric_handler) : expert_cfg(expert_cfg_), ue_alloc(expert_cfg, ue_db, srslog::fetch_basic_logger("SCHED")), event_mng(ue_db, metric_handler), diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h index 60e2107191..a7e72b521e 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h @@ -32,7 +32,7 @@ class ue_scheduler_impl final : public ue_scheduler public: explicit ue_scheduler_impl(const scheduler_ue_expert_config& expert_cfg_, sched_configuration_notifier& mac_notif, - scheduler_metrics_handler& metric_handler); + cell_metrics_handler& metric_handler); void add_cell(const ue_scheduler_cell_params& params) override; diff --git a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp index e7bccdd76a..5f30ee0076 100644 --- a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp +++ b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp @@ -50,7 +50,7 @@ class scheduler_metrics_handler_tester : public ::testing::Test std::chrono::milliseconds report_period; test_scheduler_ue_metrics_notifier metrics_notif; - scheduler_metrics_handler metrics; + 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)}; From 1ba050b76de05c24f6abacc44ac7606675dfe152 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 10:34:04 +0200 Subject: [PATCH 015/407] cu_cp: refactor cu-cp paging test --- .../f1ap/f1ap_test_message_validators.cpp | 9 + .../f1ap/f1ap_test_message_validators.h | 2 + tests/unittests/cu_cp/CMakeLists.txt | 1 + tests/unittests/cu_cp/cu_cp_paging_test.cpp | 263 ++++++++++++++++++ tests/unittests/cu_cp/cu_cp_test.cpp | 175 ------------ tests/unittests/cu_cp/cu_cp_test_helpers.cpp | 88 ------ 6 files changed, 275 insertions(+), 263 deletions(-) create mode 100644 tests/unittests/cu_cp/cu_cp_paging_test.cpp diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp index 610b15482c..150272954a 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp @@ -142,3 +142,12 @@ bool srsran::test_helpers::is_valid_ue_context_release_command(const f1ap_messag return true; } + +bool srsran::test_helpers::is_valid_paging(const f1ap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::f1ap::f1ap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_F1AP_ID_PAGING); + TRUE_OR_RETURN(is_packable(msg)); + + return true; +} diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index 602d26ff25..ad8e8346ac 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -44,5 +44,7 @@ bool is_valid_ue_context_modification_request(const f1ap_message& msg); bool is_valid_ue_context_release_command(const f1ap_message& msg); +bool is_valid_paging(const f1ap_message& msg); + } // namespace test_helpers } // namespace srsran diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index 1143064073..1e65b713ed 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(cu_cp_test cu_cp_pdu_session_resource_setup_test.cpp cu_cp_pdu_session_resource_release_test.cpp cu_cp_pdu_session_resource_modify_test.cpp + cu_cp_paging_test.cpp ) set_target_properties(cu_cp_test PROPERTIES UNITY_BUILD ON) target_link_libraries(cu_cp_test diff --git a/tests/unittests/cu_cp/cu_cp_paging_test.cpp b/tests/unittests/cu_cp/cu_cp_paging_test.cpp new file mode 100644 index 0000000000..1a61efa5b6 --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_paging_test.cpp @@ -0,0 +1,263 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/asn1/f1ap/f1ap_pdu_contents.h" +#include "srsran/asn1/ngap/ngap_pdu_contents.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_paging_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_paging_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + } + + unsigned connect_du() + { + // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + return ret.value(); + } + + unsigned setup_du(const f1ap_message& f1_setup_request) + { + // Setup DU + unsigned tmp_du_idx = connect_du(); + + get_du(tmp_du_idx).push_ul_pdu(f1_setup_request); + EXPECT_TRUE(this->wait_for_f1ap_tx_pdu(tmp_du_idx, f1ap_pdu)); + return tmp_du_idx; + } + + void send_ngap_paging(unsigned du_idx_, const ngap_message& paging_msg) + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx_).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + + get_amf().push_tx_pdu(paging_msg); + } + + void send_minimal_ngap_paging_and_await_f1ap_paging(unsigned du_idx_) + { + // Inject NGAP Paging and wait for F1AP Paging + send_ngap_paging(du_idx_, generate_valid_minimal_paging_message()); + bool result = this->wait_for_f1ap_tx_pdu(du_idx_, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP Paging"); + report_fatal_error_if_not(test_helpers::is_valid_paging(f1ap_pdu), "Invalid F1AP Paging"); + report_fatal_error_if_not(is_valid_minimal_paging_result(f1ap_pdu), "Invalid minimal F1AP Paging"); + } + + void send_ngap_paging_and_await_f1ap_paging(unsigned du_idx_) + { + // Inject NGAP Paging and wait for F1AP Paging + send_ngap_paging(du_idx_, generate_valid_paging_message()); + bool result = this->wait_for_f1ap_tx_pdu(du_idx_, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive F1AP Paging"); + report_fatal_error_if_not(test_helpers::is_valid_paging(f1ap_pdu), "Invalid F1AP Paging"); + report_fatal_error_if_not(is_valid_paging_result(f1ap_pdu), "Invalid F1AP Paging"); + } + + bool is_valid_minimal_paging_result(const f1ap_message& msg) + { + const auto& paging_msg = msg.pdu.init_msg().value.paging(); + + // check ue id idx value + if (paging_msg->ue_id_idx_value.idx_len10().to_number() != (279089024671 % 1024)) { + test_logger.error("UE ID idx value mismatch {} != {}", + paging_msg->ue_id_idx_value.idx_len10().to_number(), + (279089024671 % 1024)); + return false; + } + + // check paging id + if (paging_msg->paging_id.cn_ue_paging_id().five_g_s_tmsi().to_number() != 279089024671) { + test_logger.error("Paging ID mismatch {} != {}", + paging_msg->paging_id.cn_ue_paging_id().five_g_s_tmsi().to_number(), + 279089024671); + return false; + } + + // check paging cell list + if (paging_msg->paging_cell_list.size() != 1) { + test_logger.error("Paging cell list size mismatch {} != {}", paging_msg->paging_cell_list.size(), 1); + return false; + } + + const auto& paging_cell_item = paging_msg->paging_cell_list[0].value().paging_cell_item(); + nr_cell_identity nci = nr_cell_identity::create(gnb_id_t{411, 22}, 0).value(); + if (paging_cell_item.nr_cgi.nr_cell_id.to_number() != nci.value()) { + test_logger.error("NR CGI NCI mismatch {} != {}", paging_cell_item.nr_cgi.nr_cell_id.to_number(), nci); + return false; + } + if (paging_cell_item.nr_cgi.plmn_id.to_string() != "00f110") { + test_logger.error("NR CGI PLMN mismatch {} != 00f110", paging_cell_item.nr_cgi.plmn_id.to_string()); + return false; + } + + return true; + } + + bool is_valid_paging_result(const f1ap_message& msg) + { + if (!is_valid_minimal_paging_result(msg)) { + return false; + } + + const auto& paging_msg = msg.pdu.init_msg().value.paging(); + + // check paging drx + if (!paging_msg->paging_drx_present) { + return false; + } + if (paging_msg->paging_drx.to_number() != 64) { + test_logger.error("Paging DRX mismatch {} != {}", paging_msg->paging_drx.to_number(), 64); + return false; + } + + // check paging prio + if (!paging_msg->paging_prio_present) { + return false; + } + if (paging_msg->paging_prio.to_number() != 5) { + test_logger.error("Paging prio mismatch {} != {}", paging_msg->paging_prio.to_number(), 5); + return false; + } + + // check paging origin + if (!paging_msg->paging_origin_present) { + return false; + } + if ((std::string)paging_msg->paging_origin.to_string() != "non-3gpp") { + test_logger.error("Paging origin mismatch {} != non-3gpp", paging_msg->paging_origin.to_string()); + return false; + } + + return true; + } + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; +}; + +TEST_F(cu_cp_paging_test, when_du_connection_not_finished_then_paging_is_not_sent_to_du) +{ + // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) + unsigned du_idx = connect_du(); + + // Inject NGAP Paging with only mandatory values + send_ngap_paging(du_idx, generate_valid_minimal_paging_message()); + + // Make sure that no paging was sent to the DU + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "Paging was sent to DU before F1Setup"); +} + +TEST_F(cu_cp_paging_test, when_no_du_for_tac_exists_then_paging_is_not_sent_to_du) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Inject NGAP Paging with unknown TAC + ngap_message paging_msg = generate_valid_minimal_paging_message(); + paging_msg.pdu.init_msg().value.paging()->tai_list_for_paging[0].tai.tac.from_number(8); + send_ngap_paging(du_idx, paging_msg); + + // Make sure that no paging was sent to the DU + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "Paging with unknown TAC was sent to DU"); +} + +TEST_F(cu_cp_paging_test, when_assist_data_for_paging_for_unknown_tac_is_included_then_paging_is_not_sent_to_du) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Inject NGAP Paging with unknown TAC but assist data for paging + ngap_message paging_msg = generate_valid_paging_message(); + paging_msg.pdu.init_msg().value.paging()->tai_list_for_paging[0].tai.tac.from_number(8); + send_ngap_paging(du_idx, paging_msg); + + // Make sure that no paging was sent to the DU + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "Paging with unknown TAC but assist data was sent to DU"); +} + +TEST_F(cu_cp_paging_test, when_invalid_paging_message_received_then_paging_is_not_sent_to_du) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Inject invalid NGAP Paging + send_ngap_paging(du_idx, generate_invalid_paging_message()); + + // Make sure that no paging was sent to the DU + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "Invalid Paging was sent to DU"); +} + +TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_sent_to_du) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Inject NGAP Paging with only mandatory values and await F1AP Paging + send_minimal_ngap_paging_and_await_f1ap_paging(du_idx); +} + +TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_only_sent_to_du_with_matching_tac) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Connect second DU and run F1Setup + unsigned du_idx2 = setup_du( + test_helpers::generate_f1_setup_request(int_to_gnb_du_id(0x12), nr_cell_identity::create(6577).value(), 1, 8)); + + // Inject NGAP Paging with only mandatory values and await F1AP Paging + send_minimal_ngap_paging_and_await_f1ap_paging(du_idx); + + // Make sure that no paging was sent to the second DU + srsran_assert(not this->get_du(du_idx2).try_pop_dl_pdu(f1ap_pdu), "Paging was sent to DU with different TAC"); +} + +TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_only_sent_to_du_with_matching_nci) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Connect second DU and run F1Setup + unsigned du_idx2 = setup_du( + test_helpers::generate_f1_setup_request(int_to_gnb_du_id(0x12), nr_cell_identity::create(6577).value(), 1, 7)); + + // Inject NGAP Paging with only mandatory values and await F1AP Paging + send_minimal_ngap_paging_and_await_f1ap_paging(du_idx); + + // Make sure that no paging was sent to the second DU + srsran_assert(not this->get_du(du_idx2).try_pop_dl_pdu(f1ap_pdu), "Paging was sent to DU with different TAC"); +} + +TEST_F(cu_cp_paging_test, when_valid_paging_message_with_optional_values_received_then_paging_is_sent_to_du) +{ + // Connect DU and run F1Setup + unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); + + // Inject NGAP Paging with optional values and await F1AP Paging + send_ngap_paging_and_await_f1ap_paging(du_idx); +} diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index da17b0b50c..161091071b 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -21,181 +21,6 @@ using namespace srsran; using namespace srs_cu_cp; using namespace asn1::f1ap; -////////////////////////////////////////////////////////////////////////////////////// -/* Paging handling */ -////////////////////////////////////////////////////////////////////////////////////// - -/// Test the handling of an paging message when a DU is not connected -TEST_F(cu_cp_test, when_du_connection_not_finished_then_paging_is_not_sent_to_du) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - this->f1c_gw.request_new_du_connection(); - - // Generate Paging - ngap_message paging_msg = generate_valid_minimal_paging_message(); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_FALSE(check_minimal_paging_result()); -} - -/// Test the handling of a valid Paging message with only mandatory values set -TEST_F(cu_cp_test, when_valid_paging_message_received_then_paging_is_sent_to_du) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif->on_new_message(f1setup_msg); - - // Generate Paging - ngap_message paging_msg = generate_valid_minimal_paging_message(); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_TRUE(check_minimal_paging_result()); -} - -/// Test the handling of a valid Paging message for multiple DUs with only mandatory values set -TEST_F(cu_cp_test, when_valid_paging_message_received_then_paging_is_only_sent_to_du_with_matching_tac) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif1 = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif1->on_new_message(f1setup_msg); - - // Connect second DU - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif2 = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg2 = - test_helpers::generate_f1_setup_request(int_to_gnb_du_id(0x12), nr_cell_identity::create(6577).value(), 1, 8); - - // Pass message to CU-CP - f1c_rx_pdu_notif2->on_new_message(f1setup_msg2); - - // Generate Paging - ngap_message paging_msg = generate_valid_minimal_paging_message(); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_TRUE(check_minimal_paging_result()); -} - -/// Test the handling of a valid Paging message for multiple DUs with only mandatory values set -TEST_F(cu_cp_test, when_valid_paging_message_received_then_paging_is_only_sent_to_du_with_matching_nci) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif1 = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif1->on_new_message(f1setup_msg); - - // Connect second DU - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif2 = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg2 = - test_helpers::generate_f1_setup_request(int_to_gnb_du_id(0x12), nr_cell_identity::create(6577).value(), 1, 7); - - // Pass message to CU-CP - f1c_rx_pdu_notif2->on_new_message(f1setup_msg2); - - // Generate Paging - ngap_message paging_msg = generate_valid_minimal_paging_message(); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_TRUE(check_minimal_paging_result()); -} - -/// Test the handling of a valid Paging message with optional values set -TEST_F(cu_cp_test, when_valid_paging_message_with_optional_values_received_then_paging_is_sent_to_du) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif->on_new_message(f1setup_msg); - - // Generate Paging - ngap_message paging_msg = generate_valid_paging_message(); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_TRUE(check_paging_result()); -} - -/// Test the handling of an invalid Paging message -TEST_F(cu_cp_test, when_no_du_for_tac_exists_then_paging_is_not_sent_to_du) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif->on_new_message(f1setup_msg); - - // Generate Paging with unknown tac - ngap_message paging_msg = generate_valid_minimal_paging_message(); - paging_msg.pdu.init_msg().value.paging()->tai_list_for_paging[0].tai.tac.from_number(8); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_FALSE(check_minimal_paging_result()); -} - -/// Test the handling of an invalid Paging message -TEST_F(cu_cp_test, when_assist_data_for_paging_for_unknown_tac_is_included_then_paging_is_not_sent_to_du) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif->on_new_message(f1setup_msg); - - // Generate Paging with unknown tac but assist data for paging - ngap_message paging_msg = generate_valid_paging_message(); - paging_msg.pdu.init_msg().value.paging()->tai_list_for_paging[0].tai.tac.from_number(8); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_FALSE(check_paging_result()); -} - -/// Test the handling of an invalid Paging message -TEST_F(cu_cp_test, when_invalid_paging_message_received_then_paging_is_not_sent_to_du) -{ - // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) - f1ap_message_notifier* f1c_rx_pdu_notif = this->f1c_gw.request_new_du_connection(); - - // Generate F1SetupRequest - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(); - // Pass message to CU-CP - f1c_rx_pdu_notif->on_new_message(f1setup_msg); - - // Generate Paging - ngap_message paging_msg = generate_invalid_paging_message(); - - cu_cp_obj->get_ngap_message_handler().handle_message(paging_msg); - - ASSERT_FALSE(check_paging_result()); -} - ////////////////////////////////////////////////////////////////////////////////////// /* Inactivity Notification */ ////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp index 4ee06c688f..4e26ca47d3 100644 --- a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp @@ -435,94 +435,6 @@ void cu_cp_test::test_preamble_ue_full_attach(du_index_t du_i std::move(psis_to_setup), du_index, du_ue_id, cu_ue_id, amf_ue_id, ran_ue_id, cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); } -bool cu_cp_test::check_minimal_paging_result() -{ - span last_f1ap_msgs = f1c_gw.last_tx_pdus(0); - if (last_f1ap_msgs.empty() or last_f1ap_msgs.back().pdu.type() != asn1::f1ap::f1ap_pdu_c::types::init_msg || - last_f1ap_msgs.back().pdu.init_msg().value.type() != asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types::paging) { - return false; - } - - auto& paging_msg = last_f1ap_msgs.back().pdu.init_msg().value.paging(); - - // check ue id idx value - if (paging_msg->ue_id_idx_value.idx_len10().to_number() != (279089024671 % 1024)) { - test_logger.error("UE ID idx value mismatch {} != {}", - paging_msg->ue_id_idx_value.idx_len10().to_number(), - (279089024671 % 1024)); - return false; - } - - // check paging id - if (paging_msg->paging_id.cn_ue_paging_id().five_g_s_tmsi().to_number() != 279089024671) { - test_logger.error("Paging ID mismatch {} != {}", - paging_msg->paging_id.cn_ue_paging_id().five_g_s_tmsi().to_number(), - 279089024671); - return false; - } - - // check paging cell list - if (paging_msg->paging_cell_list.size() != 1) { - test_logger.error("Paging cell list size mismatch {} != {}", paging_msg->paging_cell_list.size(), 1); - return false; - } - auto& paging_cell_item = paging_msg->paging_cell_list[0].value().paging_cell_item(); - nr_cell_identity nci = nr_cell_identity::create(gnb_id_t{411, 22}, 0).value(); - if (paging_cell_item.nr_cgi.nr_cell_id.to_number() != nci.value()) { - test_logger.error("NR CGI NCI mismatch {} != {}", paging_cell_item.nr_cgi.nr_cell_id.to_number(), nci); - return false; - } - if (paging_cell_item.nr_cgi.plmn_id.to_string() != "00f110") { - test_logger.error("NR CGI PLMN mismatch {} != 00f110", paging_cell_item.nr_cgi.plmn_id.to_string()); - return false; - } - - return true; -} - -bool cu_cp_test::check_paging_result() -{ - if (!check_minimal_paging_result()) { - return false; - } - - span last_f1ap_msgs = f1c_gw.last_tx_pdus(0); - if (last_f1ap_msgs.empty()) { - test_logger.error("No F1AP messages sent"); - return false; - } - auto& paging_msg = last_f1ap_msgs.back().pdu.init_msg().value.paging(); - - // check paging drx - if (!paging_msg->paging_drx_present) { - return false; - } - if (paging_msg->paging_drx.to_number() != 64) { - test_logger.error("Paging DRX mismatch {} != {}", paging_msg->paging_drx.to_number(), 64); - return false; - } - - // check paging prio - if (!paging_msg->paging_prio_present) { - return false; - } - if (paging_msg->paging_prio.to_number() != 5) { - test_logger.error("Paging prio mismatch {} != {}", paging_msg->paging_prio.to_number(), 5); - return false; - } - - // check paging origin - if (!paging_msg->paging_origin_present) { - return false; - } - if ((std::string)paging_msg->paging_origin.to_string() != "non-3gpp") { - test_logger.error("Paging origin mismatch {} != non-3gpp", paging_msg->paging_origin.to_string()); - return false; - } - - return true; -} - void cu_cp_test::start_auto_tick(const std::future& stop_signal) { do { From 5c617a1b264089c07caf8f02bf96927369aeaa4c Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 11:01:07 +0200 Subject: [PATCH 016/407] cu_cp: refactor inactivity notification test --- lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp | 10 + tests/unittests/cu_cp/CMakeLists.txt | 1 + .../cu_cp_inactivity_notification_test.cpp | 176 ++++++++++++++++++ tests/unittests/cu_cp/cu_cp_test.cpp | 63 ------- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 66 +++++++ .../e1ap/common/e1ap_cu_cp_test_messages.h | 23 +++ 6 files changed, 276 insertions(+), 63 deletions(-) create mode 100644 tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp index 6eedad3947..3bc9adb71c 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp @@ -244,6 +244,11 @@ void e1ap_cu_cp_impl::handle_bearer_context_inactivity_notification( inactivity_notification.inactive_drbs.emplace_back(uint_to_drb_id(drb.drb_id)); } } + // if no drbs are inactive, return + if (inactivity_notification.inactive_drbs.empty()) { + return; + } + // if all drbs are inactive, release ue if (inactivity_notification.inactive_drbs.size() == msg->activity_info.drb_activity_list().size()) { inactivity_notification.ue_inactive = true; @@ -258,6 +263,11 @@ void e1ap_cu_cp_impl::handle_bearer_context_inactivity_notification( uint_to_pdu_session_id(pdu_session.pdu_session_id)); } } + // if no pdu sessions are inactive, return + if (inactivity_notification.inactive_pdu_sessions.empty()) { + return; + } + // if all pdu sessions are inactive, release ue if (inactivity_notification.inactive_pdu_sessions.size() == msg->activity_info.pdu_session_res_activity_list().size()) { diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index 1e65b713ed..373da53e8d 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable(cu_cp_test cu_cp_pdu_session_resource_release_test.cpp cu_cp_pdu_session_resource_modify_test.cpp cu_cp_paging_test.cpp + cu_cp_inactivity_notification_test.cpp ) set_target_properties(cu_cp_test PROPERTIES UNITY_BUILD ON) target_link_libraries(cu_cp_test diff --git a/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp b/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp new file mode 100644 index 0000000000..b843f51f6e --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp @@ -0,0 +1,176 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "srsran/e1ap/common/e1ap_message.h" +#include "srsran/ngap/ngap_message.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_inactivity_notification_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_inactivity_notification_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(du_idx)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + + // Connect UE 0x4601. + EXPECT_TRUE(attach_ue(du_idx, cu_up_idx, du_ue_id, crnti, amf_ue_id, cu_up_e1ap_id, psi, drb_id_t::drb1, qfi)); + ue_ctx = this->find_ue_context(du_idx, du_ue_id); + EXPECT_NE(ue_ctx, nullptr); + } + + void setup_pdu_session(pdu_session_id_t psi_, + drb_id_t drb_id_, + qos_flow_id_t qfi_, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), + bool is_initial_session_ = true) + { + EXPECT_TRUE(cu_cp_test_environment::setup_pdu_session(du_idx, + cu_up_idx, + du_ue_id, + crnti, + cu_up_e1ap_id, + psi_, + drb_id_, + qfi_, + std::move(rrc_reconfiguration_complete), + is_initial_session_)); + } + + void send_bearer_context_inactivity_notification(const e1ap_message& inactivity_notification) + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject inactivity notification + get_cu_up(cu_up_idx).push_tx_pdu(inactivity_notification); + } + + void send_ue_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject inactivity notification and wait for UE Context Release Request + send_bearer_context_inactivity_notification( + generate_bearer_context_inactivity_notification_with_ue_level(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), + "Invalid UE Context Release Request"); + } + + void send_drb_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject inactivity notification and wait for UE Context Release Request + send_bearer_context_inactivity_notification(generate_bearer_context_inactivity_notification_with_drb_level( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {drb_id_t::drb1})); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), + "Invalid UE Context Release Request"); + } + + void send_pdu_session_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject inactivity notification and wait for UE Context Release Request + send_bearer_context_inactivity_notification(generate_bearer_context_inactivity_notification_with_pdu_session_level( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {psi})); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), + "Invalid UE Context Release Request"); + } + + unsigned du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = amf_ue_id_t::min; + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + + const ue_context* ue_ctx = nullptr; + + pdu_session_id_t psi = uint_to_pdu_session_id(1); + pdu_session_id_t psi2 = uint_to_pdu_session_id(2); + qos_flow_id_t qfi = uint_to_qos_flow_id(1); + qos_flow_id_t qfi2 = uint_to_qos_flow_id(2); + + ngap_message ngap_pdu; + e1ap_message e1ap_pdu; +}; + +TEST_F(cu_cp_inactivity_notification_test, + when_unsupported_inactivity_message_received_then_ue_context_release_request_is_not_sent) +{ + // Setup second PDU session + setup_pdu_session(psi2, drb_id_t::drb2, qfi2, generate_rrc_reconfiguration_complete_pdu(0, 8), false); + + // Inject unsupported Inactivity Notification + e1ap_message inactivity_notification = generate_bearer_context_inactivity_notification_with_drb_level( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {drb_id_t::drb1}, {drb_id_t::drb2}); + send_bearer_context_inactivity_notification(inactivity_notification); + + // check that the UE Context Release Request was not sent to the AMF + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "UE Context Release for unsupported inactivity message was sent to AMF"); +} + +TEST_F(cu_cp_inactivity_notification_test, + when_ue_level_inactivity_message_received_then_ue_context_release_request_is_sent) +{ + // Inject Inactivity Notification and await UE Context Release Request + send_ue_level_bearer_context_inactivity_notification_and_await_ue_context_release_request(); +} + +TEST_F(cu_cp_inactivity_notification_test, + when_drb_level_inactivity_message_with_inactivity_for_all_drbs_received_then_ue_context_release_request_is_sent) +{ + // Inject Inactivity Notification and await UE Context Release Request + send_drb_level_bearer_context_inactivity_notification_and_await_ue_context_release_request(); +} + +TEST_F( + cu_cp_inactivity_notification_test, + when_pdu_session_level_inactivity_message_with_inactivity_for_all_drbs_received_then_ue_context_release_request_is_sent) +{ + // Inject Inactivity Notification and await UE Context Release Request + send_pdu_session_level_bearer_context_inactivity_notification_and_await_ue_context_release_request(); +} diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index 161091071b..adf5eabaeb 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -21,69 +21,6 @@ using namespace srsran; using namespace srs_cu_cp; using namespace asn1::f1ap; -////////////////////////////////////////////////////////////////////////////////////// -/* Inactivity Notification */ -////////////////////////////////////////////////////////////////////////////////////// - -/// Test the handling of a ue level inactivity notification -TEST_F(cu_cp_test, when_ue_level_inactivity_message_received_then_ue_context_release_request_is_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - pci_t pci = 0; - rnti_t crnti = to_rnti(0x4601); - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_creation(du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id); - - cu_cp_inactivity_notification inactivity_notification; - inactivity_notification.ue_index = uint_to_ue_index(0); - inactivity_notification.ue_inactive = true; - - cu_cp_obj->handle_bearer_context_inactivity_notification(inactivity_notification); - - // check that the UE Context Release Request was sent to the AMF - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_request); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.ue_context_release_request()->cause.type(), - asn1::ngap::cause_c::types::radio_network); -} - -/// Test the handling of an inactivity notification with unsupported activity level -TEST_F(cu_cp_test, when_unsupported_inactivity_message_received_then_ue_context_release_request_is_not_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 0; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_creation(du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id); - - cu_cp_inactivity_notification inactivity_notification; - inactivity_notification.ue_index = uint_to_ue_index(0); - inactivity_notification.ue_inactive = false; - - cu_cp_obj->handle_bearer_context_inactivity_notification(inactivity_notification); - - // check that the UE Context Release Request was not sent to the AMF - ASSERT_NE(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_request); -} - ////////////////////////////////////////////////////////////////////////////////////// /* AMF initiated PDU Session Release */ ////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 529ecc3d1d..91614b05e7 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -357,6 +357,72 @@ e1ap_message srsran::srs_cu_cp::generate_bearer_context_inactivity_notification_ return inactivity_notification; } +e1ap_message srsran::srs_cu_cp::generate_bearer_context_inactivity_notification_with_drb_level( + gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::vector& active_drbs, + const std::vector& inactive_drbs) +{ + e1ap_message e1ap_msg = {}; + + e1ap_msg.pdu.set_init_msg(); + e1ap_msg.pdu.init_msg().load_info_obj(ASN1_E1AP_ID_BEARER_CONTEXT_INACTIVITY_NOTIF); + + auto& inactivity_notification = e1ap_msg.pdu.init_msg().value.bearer_context_inactivity_notif(); + inactivity_notification->gnb_cu_cp_ue_e1ap_id = gnb_cu_cp_ue_e1ap_id_to_uint(cu_cp_ue_e1ap_id); + inactivity_notification->gnb_cu_up_ue_e1ap_id = gnb_cu_up_ue_e1ap_id_to_uint(cu_up_ue_e1ap_id); + + inactivity_notification->activity_info.set_drb_activity_list(); + for (const auto& drb : active_drbs) { + asn1::e1ap::drb_activity_item_s drb_activity_item; + drb_activity_item.drb_id = drb_id_to_uint(drb); + drb_activity_item.drb_activity = asn1::e1ap::drb_activity_opts::options::active; + inactivity_notification->activity_info.drb_activity_list().push_back(drb_activity_item); + } + + for (const auto& drb : inactive_drbs) { + asn1::e1ap::drb_activity_item_s drb_activity_item; + drb_activity_item.drb_id = drb_id_to_uint(drb); + drb_activity_item.drb_activity = asn1::e1ap::drb_activity_opts::options::not_active; + inactivity_notification->activity_info.drb_activity_list().push_back(drb_activity_item); + } + + return e1ap_msg; +} + +e1ap_message srsran::srs_cu_cp::generate_bearer_context_inactivity_notification_with_pdu_session_level( + gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::vector& active_pdu_sessions, + const std::vector& inactive_pdu_sessions) +{ + e1ap_message e1ap_msg = {}; + + e1ap_msg.pdu.set_init_msg(); + e1ap_msg.pdu.init_msg().load_info_obj(ASN1_E1AP_ID_BEARER_CONTEXT_INACTIVITY_NOTIF); + + auto& inactivity_notification = e1ap_msg.pdu.init_msg().value.bearer_context_inactivity_notif(); + inactivity_notification->gnb_cu_cp_ue_e1ap_id = gnb_cu_cp_ue_e1ap_id_to_uint(cu_cp_ue_e1ap_id); + inactivity_notification->gnb_cu_up_ue_e1ap_id = gnb_cu_up_ue_e1ap_id_to_uint(cu_up_ue_e1ap_id); + + inactivity_notification->activity_info.set_pdu_session_res_activity_list(); + for (const auto& pdu_session : active_pdu_sessions) { + asn1::e1ap::pdu_session_res_activity_item_s pdu_session_activity_item; + pdu_session_activity_item.pdu_session_id = pdu_session_id_to_uint(pdu_session); + pdu_session_activity_item.pdu_session_res_activity = asn1::e1ap::pdu_session_res_activity_opts::options::active; + inactivity_notification->activity_info.set_pdu_session_res_activity_list().push_back(pdu_session_activity_item); + } + + for (const auto& pdu_session : inactive_pdu_sessions) { + asn1::e1ap::pdu_session_res_activity_item_s pdu_session_activity_item; + pdu_session_activity_item.pdu_session_id = pdu_session_id_to_uint(pdu_session); + pdu_session_activity_item.pdu_session_res_activity = asn1::e1ap::pdu_session_res_activity_opts::options::not_active; + inactivity_notification->activity_info.set_pdu_session_res_activity_list().push_back(pdu_session_activity_item); + } + + return e1ap_msg; +} + e1ap_message srsran::srs_cu_cp::generate_invalid_bearer_context_inactivity_notification(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id) diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h index 064208fb7c..7c10c63a3b 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h @@ -102,6 +102,29 @@ e1ap_message generate_bearer_context_release_complete(gnb_cu_cp_ue_e1ap_id_t cu_ e1ap_message generate_bearer_context_inactivity_notification_with_ue_level(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id); +/// \brief Generate a dummy Bearer Context Inactivity Notification with DRB activity level. +/// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. +/// \param[in] cu_up_ue_e1ap_id The CU-UP UE E1AP ID. +/// \param[in] active_drbs The active DRBs. +/// \param[in] inactive_drbs The inactive DRBs. +/// \return The Bearer Context Inactivity Notification. +e1ap_message generate_bearer_context_inactivity_notification_with_drb_level(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::vector& active_drbs, + const std::vector& inactive_drbs); + +/// \brief Generate a dummy Bearer Context Inactivity Notification with PDU session activity level. +/// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. +/// \param[in] cu_up_ue_e1ap_id The CU-UP UE E1AP ID. +/// \param[in] active_pdu_sessions The active PDU sessions. +/// \param[in] inactive_pdu_sessions The inactive PDU sessions. +/// \return The Bearer Context Inactivity Notification. +e1ap_message generate_bearer_context_inactivity_notification_with_pdu_session_level( + gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, + gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, + const std::vector& active_pdu_sessions, + const std::vector& inactive_pdu_sessions); + /// \brief Generate an invalid dummy Bearer Context Inactivity Notification with UE activity level. /// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. /// \param[in] cu_up_ue_e1ap_id The CU-UP UE E1AP ID. From c71aacaaa16bd0f0f2878055c088ed3c3f0e313d Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 11:03:14 +0200 Subject: [PATCH 017/407] cu_cp: remove duplicate unittests --- tests/unittests/cu_cp/cu_cp_test.cpp | 71 ---------------------------- 1 file changed, 71 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index adf5eabaeb..ec766f1a5c 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -21,77 +21,6 @@ using namespace srsran; using namespace srs_cu_cp; using namespace asn1::f1ap; -////////////////////////////////////////////////////////////////////////////////////// -/* AMF initiated PDU Session Release */ -////////////////////////////////////////////////////////////////////////////////////// - -// When multiple PDU sessions exist and not all of them are released, a BearerContextModification is sent to the CU-UP -TEST_F(cu_cp_test, when_pdu_session_resource_release_command_received_then_modification_request_is_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 1; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - std::vector psis = {uint_to_pdu_session_id(1), uint_to_pdu_session_id(2)}; - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(0); - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id = int_to_gnb_cu_up_ue_e1ap_id(0); - - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_full_attach( - du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id, psis, cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - - // Inject PduSessionResourceReleaseCommand - cu_cp_obj->get_ngap_message_handler().handle_message( - generate_valid_pdu_session_resource_release_command(amf_ue_id, ran_ue_id, uint_to_pdu_session_id(1))); - - // Check that the Bearer Context Modification was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_mod_request); -} - -// When all active PDU sessions are released a BearerContextReleaseCommand is sent to the CU-UP -TEST_F(cu_cp_test, when_all_pdu_sessions_get_released_then_bearer_context_release_command_is_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 1; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - std::vector psis = {uint_to_pdu_session_id(1)}; - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(0); - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id = int_to_gnb_cu_up_ue_e1ap_id(0); - - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_full_attach( - du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id, psis, cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - - // Inject PduSessionResourceReleaseCommand - cu_cp_obj->get_ngap_message_handler().handle_message( - generate_valid_pdu_session_resource_release_command(amf_ue_id, ran_ue_id, uint_to_pdu_session_id(1))); - - // Check that the Bearer Context Release was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_release_cmd); - - // Check that no UE Context Release Request was sent to the AMF - ASSERT_NE(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::init_msg); -} - ////////////////////////////////////////////////////////////////////////////////////// /* AMF initiated UE Context Release */ ////////////////////////////////////////////////////////////////////////////////////// From 662d30161812e670a2f68cf9db7de9b735af1250 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 12:04:25 +0200 Subject: [PATCH 018/407] cu_cp: refactor ue context release test --- .../ngap/ngap_test_message_validators.cpp | 7 + .../ngap/ngap_test_message_validators.h | 4 +- tests/unittests/cu_cp/cu_cp_test.cpp | 150 ------------------ .../cu_cp/cu_cp_ue_context_release_test.cpp | 142 ++++++++++++++++- 4 files changed, 150 insertions(+), 153 deletions(-) diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.cpp b/tests/test_doubles/ngap/ngap_test_message_validators.cpp index b378bc2d8d..cf8b6bdabd 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.cpp +++ b/tests/test_doubles/ngap/ngap_test_message_validators.cpp @@ -84,6 +84,13 @@ bool srsran::test_helpers::is_valid_pdu_session_resource_modify_response(const s return true; } +bool srsran::test_helpers::is_valid_error_indication(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_NGAP_ID_ERROR_IND); + return true; +} + bool srsran::test_helpers::is_expected_pdu_session_resource_setup_response( const ngap_message& ngap_pdu, const std::vector& expected_pdu_sessions_to_setup, diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.h b/tests/test_doubles/ngap/ngap_test_message_validators.h index a5970d87e7..58d4f48aca 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.h +++ b/tests/test_doubles/ngap/ngap_test_message_validators.h @@ -39,6 +39,8 @@ bool is_valid_pdu_session_resource_release_response(const srs_cu_cp::ngap_messag bool is_valid_pdu_session_resource_modify_response(const srs_cu_cp::ngap_message& msg); +bool is_valid_error_indication(const srs_cu_cp::ngap_message& msg); + // Check if the NGAP PDU contains the expected PDU session setup response. bool is_expected_pdu_session_resource_setup_response( const srs_cu_cp::ngap_message& ngap_pdu, @@ -46,4 +48,4 @@ bool is_expected_pdu_session_resource_setup_response( const std::vector& expected_pdu_sessions_failed_to_setup); } // namespace test_helpers -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index ec766f1a5c..21e941782a 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -21,156 +21,6 @@ using namespace srsran; using namespace srs_cu_cp; using namespace asn1::f1ap; -////////////////////////////////////////////////////////////////////////////////////// -/* AMF initiated UE Context Release */ -////////////////////////////////////////////////////////////////////////////////////// - -TEST_F(cu_cp_test, when_release_command_received_then_release_command_is_sent_to_du) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 0; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_creation(du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id); - - // Inject UE Context Release Command - cu_cp_obj->get_ngap_message_handler().handle_message( - generate_valid_ue_context_release_command_with_amf_ue_ngap_id(amf_ue_id)); - - // check that the UE Context Release Command with RRC Container was sent to the DU - span last_f1ap_msgs = f1c_gw.last_tx_pdus(0); - ASSERT_FALSE(last_f1ap_msgs.empty()); - ASSERT_EQ(last_f1ap_msgs.back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(last_f1ap_msgs.back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ue_context_release_cmd); - ASSERT_TRUE(last_f1ap_msgs.back().pdu.init_msg().value.ue_context_release_cmd()->rrc_container_present); - // check that the SRB ID is set if the RRC Container is included - ASSERT_TRUE(last_f1ap_msgs.back().pdu.init_msg().value.ue_context_release_cmd()->srb_id_present); -} - -TEST_F(cu_cp_test, - when_when_pdu_session_resource_setup_request_is_received_during_release_then_error_indication_is_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 0; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_creation(du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id); - - // Inject UE Context Release Command - cu_cp_obj->get_ngap_message_handler().handle_message( - generate_valid_ue_context_release_command_with_amf_ue_ngap_id(amf_ue_id)); - - // check that the UE Context Release Command with RRC Container was sent to the DU - span last_f1ap_msgs = f1c_gw.last_tx_pdus(0); - ASSERT_FALSE(last_f1ap_msgs.empty()); - ASSERT_EQ(last_f1ap_msgs.back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(last_f1ap_msgs.back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ue_context_release_cmd); - ASSERT_TRUE(last_f1ap_msgs.back().pdu.init_msg().value.ue_context_release_cmd()->rrc_container_present); - // check that the SRB ID is set if the RRC Container is included - ASSERT_TRUE(last_f1ap_msgs.back().pdu.init_msg().value.ue_context_release_cmd()->srb_id_present); - - // Inject PDU Session Resource Setup Request - cu_cp_obj->get_ngap_message_handler().handle_message(generate_valid_pdu_session_resource_setup_request_message( - amf_ue_id, ran_ue_id, {{uint_to_pdu_session_id(1), {{uint_to_qos_flow_id(1), 9}}}})); - - // Inject F1AP UE Context Release Complete - f1c_gw.get_du(uint_to_du_index(0)) - .on_new_message(test_helpers::generate_ue_context_release_complete(cu_ue_id, du_ue_id)); - - // check that the ErrorIndication was sent to the AMF - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::error_ind); -} - -////////////////////////////////////////////////////////////////////////////////////// -/* DU Initiated UE Context Release */ -////////////////////////////////////////////////////////////////////////////////////// - -/// Test the handling of a DU initiated release request -TEST_F(cu_cp_test, when_du_initiated_ue_context_release_received_then_ue_context_release_request_is_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 0; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - // Attach UE - test_preamble_ue_creation(du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id); - - // Inject UE Context Release Request - f1c_gw.get_du(du_index).on_new_message(test_helpers::generate_ue_context_release_request(cu_ue_id, du_ue_id)); - - // Check that the UE Context Release Request was sent to the AMF - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_request); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.ue_context_release_request()->cause.type(), - asn1::ngap::cause_c::types_opts::options::radio_network); -} - -/// Test the handling of a DU initiated release request -TEST_F( - cu_cp_test, - when_du_initiated_ue_context_release_received_and_ue_unknown_to_amf_then_ue_is_released_without_release_request_to_amf) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 0; - - // Connect AMF, DU, CU-UP - test_preamble_all_connected(du_index, pci); - - // Attach UE - attach_ue(du_ue_id, cu_ue_id, crnti, du_index); - ASSERT_EQ(cu_cp_obj->get_metrics_handler().request_metrics_report().ues.size(), 1); - - // Inject UE Context Release Request - f1c_gw.get_du(uint_to_du_index(0)) - .on_new_message(test_helpers::generate_ue_context_release_request(cu_ue_id, du_ue_id)); - - // Check that the UE Context Release Request was not sent to the AMF - ASSERT_NE(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_request); - - // Check that the Ue Context Release Command was sent to the DU - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ue_context_release_cmd); - - // Inject UE Context Release Complete - f1c_gw.get_du(uint_to_du_index(0)).on_new_message(generate_ue_context_release_complete(cu_ue_id, du_ue_id)); - - // Check that the UE was removed - ASSERT_EQ(cu_cp_obj->get_metrics_handler().request_metrics_report().ues.size(), 0); -} - ////////////////////////////////////////////////////////////////////////////////////// /* Handover Request handling */ ////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp b/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp index c975215dd5..ad41b6a6da 100644 --- a/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp @@ -12,11 +12,14 @@ #include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" #include "srsran/e1ap/common/e1ap_types.h" #include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/f1ap/common/f1ap_ue_id.h" #include "srsran/ngap/ngap_message.h" #include @@ -42,7 +45,10 @@ class cu_cp_ue_context_release_test : public cu_cp_test_environment, public ::te EXPECT_TRUE(ret.has_value()); cu_up_idx = ret.value(); EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + } + void attach_ue() + { // Connect UE 0x4601. EXPECT_TRUE(connect_new_ue(du_idx, du_ue_id, crnti)); EXPECT_TRUE(authenticate_ue(du_idx, du_ue_id, amf_ue_id)); @@ -56,6 +62,7 @@ class cu_cp_ue_context_release_test : public cu_cp_test_environment, public ::te void setup_ue_pdu_session() { + attach_ue(); EXPECT_TRUE(request_pdu_session_resource_setup(du_idx, cu_up_idx, du_ue_id)); EXPECT_TRUE(setup_pdu_session(du_idx, cu_up_idx, du_ue_id, crnti, cu_up_e1ap_id)); } @@ -101,17 +108,59 @@ class cu_cp_ue_context_release_test : public cu_cp_test_environment, public ::te "Invalid UE Context Release Command"); } + void send_f1ap_ue_context_release_complete(gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) + { + // Inject F1AP UE Context Release Complete + get_du(du_idx).push_ul_pdu(test_helpers::generate_ue_context_release_complete(cu_ue_id_, du_ue_id_)); + } + void send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete() { // Inject F1AP UE Context Release Complete and wait for N1AP UE Context Release Command - get_du(du_idx).push_ul_pdu( - generate_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + send_f1ap_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value()); bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); report_fatal_error_if_not(result, "Failed to receive UE Context Release Complete"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_complete(ngap_pdu), "Invalid UE Context Release Complete"); } + void send_pdu_session_resource_setup_request() + { + // Inject PDU Session Resource Setup Request + get_amf().push_tx_pdu(generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), + ue_ctx->ran_ue_id.value(), + {{uint_to_pdu_session_id(1), {{uint_to_qos_flow_id(1), 9}}}})); + } + + void await_error_indication() + { + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive Error Indication"); + report_fatal_error_if_not(test_helpers::is_valid_error_indication(ngap_pdu), "Invalid Error Indication"); + } + + void send_f1ap_ue_context_release_request(gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) + { + // Inject F1AP UE Context Release Request + get_du(du_idx).push_ul_pdu(test_helpers::generate_ue_context_release_request(cu_ue_id_, du_ue_id_)); + } + + void send_f1ap_ue_context_release_request_and_await_ngap_ue_context_release_request() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject F1AP UE Context Release Request and wait for NGAP UE Context Release Request + send_f1ap_ue_context_release_request(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value()); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive NGAP UE Context Release Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), + "Invalid NGAP UE Context Release Request"); + } + unsigned du_idx = 0; unsigned cu_up_idx = 0; @@ -130,6 +179,9 @@ class cu_cp_ue_context_release_test : public cu_cp_test_environment, public ::te TEST_F(cu_cp_ue_context_release_test, when_ue_context_release_command_but_no_pdu_session_setup_received_then_release_succeeds) { + // Attach UE + attach_ue(); + // Inject NGAP UE Context Release Command and await F1AP UE Context Release Command send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command(); @@ -141,6 +193,32 @@ TEST_F(cu_cp_ue_context_release_test, ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; } +TEST_F(cu_cp_ue_context_release_test, + when_pdu_session_resource_setup_request_is_received_during_release_then_error_indication_is_sent) +{ + // Setup PDU Session + setup_ue_pdu_session(); + + // Inject NGAP UE Context Release Command and await Bearer Context Release Command + send_ngap_ue_context_release_command_and_await_bearer_context_release_command(); + + // Inject Bearer Context Release Complete and await F1AP UE Context Release Command + send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command(); + + // Inject PDU Session Resource Setup Request + send_pdu_session_resource_setup_request(); + + // Inject F1AP UE Context Release Complete and await NGAP UE Context Release Complete + send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete(); + + // STATUS: UE should be removed at this stage + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; + + // STATUS: An error indication should be sent to the AMF + await_error_indication(); +} + TEST_F(cu_cp_ue_context_release_test, when_ue_context_release_command_received_then_release_succeeds) { // Setup PDU Session @@ -159,3 +237,63 @@ TEST_F(cu_cp_ue_context_release_test, when_ue_context_release_command_received_t auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; } + +TEST_F(cu_cp_ue_context_release_test, + when_du_initiated_ue_context_release_received_then_ue_context_release_request_is_sent) +{ + // Setup PDU Session + setup_ue_pdu_session(); + + // Inject F1AP UE Context Release Request and await NGAP UE Context Release Request + send_f1ap_ue_context_release_request_and_await_ngap_ue_context_release_request(); +} + +TEST_F( + cu_cp_ue_context_release_test, + when_du_initiated_ue_context_release_received_and_ue_unknown_to_amf_then_ue_is_released_without_release_request_to_amf) +{ + // RRC connect UE without sending message to AMF + gnb_cu_ue_f1ap_id_t cu_ue_id = gnb_cu_ue_f1ap_id_t::min; + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + + // Inject Initial UL RRC message + f1ap_message init_ul_rrc_msg = generate_init_ul_rrc_message_transfer(du_ue_id, crnti); + test_logger.info("c-rnti={} du_ue={}: Injecting Initial UL RRC message", crnti, du_ue_id); + get_du(du_idx).push_ul_pdu(init_ul_rrc_msg); + + // Wait for DL RRC message transfer (containing RRC Setup) + report_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu, std::chrono::milliseconds{1000}), + "Failed to receive DL RRC message"); + + // Check if the DL RRC Message with Msg4 is valid. + report_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer_with_msg4(f1ap_pdu), "invalid DL RRC message"); + + // Check if the UE Id matches. + auto& dl_rrc_msg = *f1ap_pdu.pdu.init_msg().value.dl_rrc_msg_transfer(); + report_error_if_not(int_to_gnb_du_ue_f1ap_id(dl_rrc_msg.gnb_du_ue_f1ap_id) == du_ue_id, + "invalid gNB-DU-UE-F1AP-ID"); + report_error_if_not(int_to_srb_id(dl_rrc_msg.srb_id) == srb_id_t::srb0, "invalid SRB-Id"); + + // Send RRC Setup Complete. + // > Generate UL DCCH message (containing RRC Setup Complete). + f1ap_message ul_dcch_msg = + generate_ul_rrc_message_transfer(cu_ue_id, du_ue_id, srb_id_t::srb1, generate_rrc_setup_complete()); + // > Generate UL RRC Message (containing RRC Setup Complete) with PDCP SN=0. + get_du(du_idx).push_ul_pdu(ul_dcch_msg); + } + + // Inject F1AP UE Context Release Request + send_f1ap_ue_context_release_request(cu_ue_id, du_ue_id); + + // No NGAP UE Context Release Request should be sent to the AMF + ASSERT_NE(ngap_pdu.pdu.type().value, asn1::ngap::ngap_pdu_c::types_opts::init_msg); + + // Inject F1AP UE Context Release Complete + send_f1ap_ue_context_release_complete(cu_ue_id, du_ue_id); + + // STATUS: UE should be removed at this stage + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; +} From c7df552c9ef46a73d9d49a93ed5e47e4fafedc34 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 14:06:07 +0200 Subject: [PATCH 019/407] cu_cp: refactor handover test --- .../ngap/ngap_test_message_validators.cpp | 14 ++ .../ngap/ngap_test_message_validators.h | 4 + tests/unittests/cu_cp/CMakeLists.txt | 2 +- .../cu_cp/cu_cp_connectivity_test.cpp | 14 +- tests/unittests/cu_cp/cu_cp_handover_test.cpp | 141 ++++++++++++++++++ .../cu_cp/cu_cp_reestablishment_test.cpp | 7 +- tests/unittests/cu_cp/cu_cp_setup_test.cpp | 7 + tests/unittests/cu_cp/cu_cp_test.cpp | 94 ------------ .../unittests/cu_cp/test_doubles/mock_du.cpp | 16 ++ 9 files changed, 197 insertions(+), 102 deletions(-) create mode 100644 tests/unittests/cu_cp/cu_cp_handover_test.cpp delete mode 100644 tests/unittests/cu_cp/cu_cp_test.cpp diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.cpp b/tests/test_doubles/ngap/ngap_test_message_validators.cpp index cf8b6bdabd..3b3be3bfed 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.cpp +++ b/tests/test_doubles/ngap/ngap_test_message_validators.cpp @@ -91,6 +91,20 @@ bool srsran::test_helpers::is_valid_error_indication(const srs_cu_cp::ngap_messa return true; } +bool srsran::test_helpers::is_valid_handover_request_ack(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::successful_outcome); + TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_NGAP_ID_HO_RES_ALLOC); + return true; +} + +bool srsran::test_helpers::is_valid_handover_notify(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_NGAP_ID_HO_NOTIF); + return true; +} + bool srsran::test_helpers::is_expected_pdu_session_resource_setup_response( const ngap_message& ngap_pdu, const std::vector& expected_pdu_sessions_to_setup, diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.h b/tests/test_doubles/ngap/ngap_test_message_validators.h index 58d4f48aca..be5fa93829 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.h +++ b/tests/test_doubles/ngap/ngap_test_message_validators.h @@ -41,6 +41,10 @@ bool is_valid_pdu_session_resource_modify_response(const srs_cu_cp::ngap_message bool is_valid_error_indication(const srs_cu_cp::ngap_message& msg); +bool is_valid_handover_request_ack(const srs_cu_cp::ngap_message& msg); + +bool is_valid_handover_notify(const srs_cu_cp::ngap_message& msg); + // Check if the NGAP PDU contains the expected PDU session setup response. bool is_expected_pdu_session_resource_setup_response( const srs_cu_cp::ngap_message& ngap_pdu, diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index 373da53e8d..9cba3a7c83 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -32,7 +32,6 @@ target_link_libraries(cu_cp_test_helpers srsran_cu_cp srsran_support srslog f1ap add_executable(cu_cp_test - cu_cp_test.cpp cu_cp_connectivity_test.cpp cu_cp_setup_test.cpp cu_cp_reestablishment_test.cpp @@ -43,6 +42,7 @@ add_executable(cu_cp_test cu_cp_pdu_session_resource_modify_test.cpp cu_cp_paging_test.cpp cu_cp_inactivity_notification_test.cpp + cu_cp_handover_test.cpp ) set_target_properties(cu_cp_test PROPERTIES UNITY_BUILD ON) target_link_libraries(cu_cp_test diff --git a/tests/unittests/cu_cp/cu_cp_connectivity_test.cpp b/tests/unittests/cu_cp/cu_cp_connectivity_test.cpp index 6874db5030..630b1f544b 100644 --- a/tests/unittests/cu_cp/cu_cp_connectivity_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_connectivity_test.cpp @@ -16,6 +16,8 @@ #include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" #include "srsran/asn1/rrc_nr/dl_dcch_msg_ies.h" +#include "srsran/asn1/rrc_nr/ul_dcch_msg.h" +#include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" #include "srsran/e1ap/common/e1ap_message.h" #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/ngap/ngap_message.h" @@ -144,15 +146,15 @@ TEST_F(cu_cp_connectivity_test, when_dus_with_duplicate_du_ids_connect_then_f1_s // Ensure the F1 Setup Response is received and correct for first DU. f1ap_message f1ap_pdu; ASSERT_TRUE(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu, std::chrono::milliseconds{1000})); - ASSERT_EQ(f1ap_pdu.pdu.type().value, f1ap_pdu_c::types_opts::successful_outcome); + ASSERT_EQ(f1ap_pdu.pdu.type().value, asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome); ASSERT_EQ(f1ap_pdu.pdu.successful_outcome().value.type().value, - f1ap_elem_procs_o::successful_outcome_c::types_opts::f1_setup_resp); + asn1::f1ap::f1ap_elem_procs_o::successful_outcome_c::types_opts::f1_setup_resp); // Ensure the F1 Setup Failure is received for second DU. ASSERT_TRUE(this->wait_for_f1ap_tx_pdu(du_idx2, f1ap_pdu, std::chrono::milliseconds{1000})); - ASSERT_EQ(f1ap_pdu.pdu.type().value, f1ap_pdu_c::types_opts::unsuccessful_outcome); + ASSERT_EQ(f1ap_pdu.pdu.type().value, asn1::f1ap::f1ap_pdu_c::types_opts::unsuccessful_outcome); ASSERT_EQ(f1ap_pdu.pdu.unsuccessful_outcome().value.type().value, - f1ap_elem_procs_o::unsuccessful_outcome_c::types_opts::f1_setup_fail); + asn1::f1ap::f1ap_elem_procs_o::unsuccessful_outcome_c::types_opts::f1_setup_fail); } TEST_F(cu_cp_connectivity_test, when_a_du_with_non_matching_gnb_id_connects_then_f1_setup_is_rejected) @@ -173,9 +175,9 @@ TEST_F(cu_cp_connectivity_test, when_a_du_with_non_matching_gnb_id_connects_then // Ensure the F1 Setup Failure is received for the DU. ASSERT_TRUE(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu, std::chrono::milliseconds{1000})); - ASSERT_EQ(f1ap_pdu.pdu.type().value, f1ap_pdu_c::types_opts::unsuccessful_outcome); + ASSERT_EQ(f1ap_pdu.pdu.type().value, asn1::f1ap::f1ap_pdu_c::types_opts::unsuccessful_outcome); ASSERT_EQ(f1ap_pdu.pdu.unsuccessful_outcome().value.type().value, - f1ap_elem_procs_o::unsuccessful_outcome_c::types_opts::f1_setup_fail); + asn1::f1ap::f1ap_elem_procs_o::unsuccessful_outcome_c::types_opts::f1_setup_fail); } TEST_F(cu_cp_connectivity_test, when_max_nof_dus_connected_reached_then_cu_cp_rejects_new_du_connections) diff --git a/tests/unittests/cu_cp/cu_cp_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_handover_test.cpp new file mode 100644 index 0000000000..7d863f8375 --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_handover_test.cpp @@ -0,0 +1,141 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" +#include "srsran/e1ap/common/e1ap_types.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/f1ap/common/f1ap_ue_id.h" +#include "srsran/ngap/ngap_message.h" +#include "srsran/support/test_utils.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_handover_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(du_idx)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + } + + void send_handover_request_and_await_bearer_context_setup_request() + { + srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); + srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); + + // Inject Handover Request and wait for Bearer Context Setup Request + get_amf().push_tx_pdu(generate_valid_handover_request(amf_ue_id)); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Setup Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_setup_request(e1ap_pdu), + "Invalid Bearer Context Setup Request"); + + cu_cp_e1ap_id = + int_to_gnb_cu_cp_ue_e1ap_id(e1ap_pdu.pdu.init_msg().value.bearer_context_setup_request()->gnb_cu_cp_ue_e1ap_id); + } + + void send_bearer_context_setup_response_and_await_ue_context_setup_request() + { + // Inject Bearer Context Setup Response and wait for UE Context Setup Request + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_setup_response(cu_cp_e1ap_id, cu_up_e1ap_id)); + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Setup Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_setup_request(f1ap_pdu), + "Invalid UE Context Setup Request"); + + cu_ue_id = int_to_gnb_cu_ue_f1ap_id(f1ap_pdu.pdu.init_msg().value.ue_context_setup_request()->gnb_cu_ue_f1ap_id); + } + + void send_ue_context_setup_response_and_await_bearer_context_modification_request() + { + // Inject UE Context Setup Response and wait for Bearer Context Modification Request + get_du(du_idx).push_ul_pdu(generate_ue_context_setup_response(cu_ue_id, du_ue_id, crnti)); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + } + + void send_bearer_context_modification_response_and_await_handover_request_ack() + { + // Inject Bearer Context Modification Response and wait for Handover Request Ack + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive Handover Request Ack"); + report_fatal_error_if_not(test_helpers::is_valid_handover_request_ack(ngap_pdu), "Invalid Handover Request Ack"); + } + + void send_rrc_reconfiguration_complete_and_await_handover_notify() + { + // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for Handover Notify + get_du(du_idx).push_ul_pdu(generate_ul_rrc_message_transfer( + cu_ue_id, du_ue_id, srb_id_t::srb1, make_byte_buffer("800008004e17dae3").value())); + bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive Handover Notify"); + report_fatal_error_if_not(test_helpers::is_valid_handover_notify(ngap_pdu), "Invalid Handover Notify"); + } + + unsigned du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + gnb_cu_ue_f1ap_id_t cu_ue_id; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( + test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + gnb_cu_cp_ue_e1ap_id_t cu_cp_e1ap_id; + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; + e1ap_message e1ap_pdu; +}; + +TEST_F(cu_cp_handover_test, when_handover_request_received_then_handover_notify_is_sent) +{ + // Inject Handover Request and await Bearer Context Setup Request + send_handover_request_and_await_bearer_context_setup_request(); + + // Inject Bearer Context Setup Response and await UE Context Setup Request + send_bearer_context_setup_response_and_await_ue_context_setup_request(); + + // Inject UE Context Setup Response and await Bearer Context Modification Request + send_ue_context_setup_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await Handover Request Ack + send_bearer_context_modification_response_and_await_handover_request_ack(); + + // Inject RRC Reconfiguration Complete and await Handover Notify + send_rrc_reconfiguration_complete_and_await_handover_notify(); +} diff --git a/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp b/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp index f49a62f5ca..253486ac67 100644 --- a/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp @@ -13,6 +13,11 @@ #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" +#include "srsran/asn1/ngap/ngap_pdu_contents.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" #include using namespace srsran; @@ -90,7 +95,7 @@ class cu_cp_reestablishment_test : public cu_cp_test_environment, public ::testi // Check if the DL RRC Message with Msg4 is valid. report_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer_with_msg4(f1ap_pdu), "invalid DL RRC message"); - dl_rrc_msg_transfer_s& dl_rrc_msg = f1ap_pdu.pdu.init_msg().value.dl_rrc_msg_transfer(); + asn1::f1ap::dl_rrc_msg_transfer_s& dl_rrc_msg = f1ap_pdu.pdu.init_msg().value.dl_rrc_msg_transfer(); report_error_if_not(int_to_gnb_du_ue_f1ap_id(dl_rrc_msg->gnb_du_ue_f1ap_id) == du_ue_id, "invalid gNB-DU-UE-F1AP-ID"); report_error_if_not(int_to_srb_id(dl_rrc_msg->srb_id) == srb_id_t::srb0, "invalid SRB-Id"); diff --git a/tests/unittests/cu_cp/cu_cp_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_setup_test.cpp index 2d56e6a2d8..f476d2bcf5 100644 --- a/tests/unittests/cu_cp/cu_cp_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_setup_test.cpp @@ -9,8 +9,15 @@ */ #include "cu_cp_test_environment.h" +#include "test_helpers.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" +#include "srsran/asn1/rrc_nr/dl_ccch_msg.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/ngap/ngap_message.h" #include using namespace srsran; diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp deleted file mode 100644 index 21e941782a..0000000000 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ /dev/null @@ -1,94 +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 "../rrc/rrc_ue_test_messages.h" -#include "cu_cp_test_helpers.h" -#include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" -#include "srsran/asn1/ngap/ngap_pdu_contents.h" -#include "srsran/ngap/ngap_types.h" -#include "srsran/ran/cu_types.h" -#include "srsran/support/test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; -using namespace asn1::f1ap; - -////////////////////////////////////////////////////////////////////////////////////// -/* Handover Request handling */ -////////////////////////////////////////////////////////////////////////////////////// - -TEST_F(cu_cp_test, when_handover_request_received_then_handover_notify_is_sent) -{ - // Test preamble - du_index_t du_index = uint_to_du_index(0); - pci_t pci = 0; - test_preamble_all_connected(du_index, pci); - - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - - // Inject Handover Request - cu_cp_obj->get_ngap_message_handler().handle_message(generate_valid_handover_request(amf_ue_id)); - - // Check that the Bearer Context Setup Request Message was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_setup_request); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.bearer_context_setup_request()->gnb_cu_cp_ue_e1ap_id, - 0); - - // Inject E1AP Bearer Context Setup Response - e1ap_message bearer_ctxt_setup_resp = - generate_bearer_context_setup_response(int_to_gnb_cu_cp_ue_e1ap_id(0), int_to_gnb_cu_up_ue_e1ap_id(0)); - e1ap_gw.get_cu_up(0).on_new_message(bearer_ctxt_setup_resp); - - // Check that the UE Context Setup Request Message was sent to the DU - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ue_context_setup_request); - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.init_msg().value.ue_context_setup_request()->gnb_cu_ue_f1ap_id, 0); - - // Inject F1AP UE Context Setup Response - f1ap_message ue_ctxt_setup_resp = - generate_ue_context_setup_response(int_to_gnb_cu_ue_f1ap_id(0), int_to_gnb_du_ue_f1ap_id(0), to_rnti(0x4601)); - f1c_gw.get_du(du_index).on_new_message(ue_ctxt_setup_resp); - - // Check that the Bearer Context Modification Request Message was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_mod_request); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.bearer_context_mod_request()->gnb_cu_cp_ue_e1ap_id, 0); - - // Inject E1AP Bearer Context Modification Response - e1ap_message bearer_ctxt_mod_resp = - generate_bearer_context_modification_response(int_to_gnb_cu_cp_ue_e1ap_id(0), int_to_gnb_cu_up_ue_e1ap_id(0)); - e1ap_gw.get_cu_up(0).on_new_message(bearer_ctxt_mod_resp); - - // Check that the Handover Request Ack was sent to the AMF - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::successful_outcome); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.successful_outcome().value.type().value, - asn1::ngap::ngap_elem_procs_o::successful_outcome_c::types_opts::ho_request_ack); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.successful_outcome().value.ho_request_ack()->amf_ue_ngap_id, - amf_ue_id_to_uint(amf_ue_id)); - - // Inject RRC Reconfiguration Complete with transaction_id=0 - f1ap_message rrc_recfg_complete = generate_ul_rrc_message_transfer(int_to_gnb_cu_ue_f1ap_id(0), - int_to_gnb_du_ue_f1ap_id(0), - srb_id_t::srb1, - make_byte_buffer("800008004e17dae3").value()); - f1c_gw.get_du(du_index).on_new_message(rrc_recfg_complete); - - // Check that the Handover Notify was sent to the AMF - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ho_notify); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.ho_notify()->amf_ue_ngap_id, amf_ue_id_to_uint(amf_ue_id)); -} diff --git a/tests/unittests/cu_cp/test_doubles/mock_du.cpp b/tests/unittests/cu_cp/test_doubles/mock_du.cpp index bf3646c2b1..70d9e1c5e1 100644 --- a/tests/unittests/cu_cp/test_doubles/mock_du.cpp +++ b/tests/unittests/cu_cp/test_doubles/mock_du.cpp @@ -12,6 +12,7 @@ #include "lib/f1ap/common/f1ap_asn1_utils.h" #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "srsran/adt/mutexed_mpmc_queue.h" +#include "srsran/asn1/f1ap/f1ap.h" #include "srsran/cu_cp/cu_cp_f1c_handler.h" #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/support/error_handling.h" @@ -47,6 +48,21 @@ class synchronized_mock_du final : public mock_du { report_fatal_error_if_not(tx_pdu_notifier != nullptr, "TNL connection is not established"); + // For inter-CU handover no Init UL RRC message is received + if (msg.pdu.type().value == asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome) { + if (msg.pdu.successful_outcome().value.type().value == + asn1::f1ap::f1ap_elem_procs_o::successful_outcome_c::types_opts::ue_context_setup_resp) { + const asn1::f1ap::ue_context_setup_resp_s& rrcmsg = msg.pdu.successful_outcome().value.ue_context_setup_resp(); + gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(rrcmsg->gnb_du_ue_f1ap_id); + gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(rrcmsg->gnb_cu_ue_f1ap_id); + if (ue_contexts.find(du_ue_id) == ue_contexts.end()) { + report_fatal_error_if_not( + ue_contexts.insert(std::make_pair(du_ue_id, ue_context{du_ue_id, cu_ue_id, {0, 0, 0}})).second, + "DU UE ID already exists"); + } + } + } + if (msg.pdu.type().value == asn1::f1ap::f1ap_pdu_c::types_opts::init_msg) { if (msg.pdu.init_msg().value.type().value == asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::init_ul_rrc_msg_transfer) { From 778bb302b0f4e05fa9d68da1315d5f95246c3365 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 14:06:28 +0200 Subject: [PATCH 020/407] cu_cp: small improvement to pdu session resource setup test --- .../cu_cp/cu_cp_pdu_session_resource_setup_test.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp index c0a2614ad8..1269d4e12e 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp @@ -13,6 +13,7 @@ #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" @@ -329,7 +330,7 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, when_rrc_reconfiguration_succeeds_ // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( - make_byte_buffer("00070e00cc6fcda5").value(), {psi}, {}); + generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {}); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_pdu_session_setup_for_existing_session_arrives_then_setup_fails) @@ -365,7 +366,7 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, when_setup_for_pdu_sessions_with_t // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( - make_byte_buffer("00070e00cc6fcda5").value(), {psi}, {}); + generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {}); } TEST_F( @@ -441,7 +442,7 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( - make_byte_buffer("00070e00cc6fcda5").value(), {psi}, {}); + generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {}); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_two_consecutive_setups_arrive_bearer_setup_and_modification_succeed) @@ -450,5 +451,5 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, when_two_consecutive_setups_arrive setup_pdu_session(psi, drb_id_t::drb1, qfi); // Setup second PDU session - setup_pdu_session(psi2, drb_id_t::drb2, qfi2, make_byte_buffer("00080800e6847bbd").value(), false); + setup_pdu_session(psi2, drb_id_t::drb2, qfi2, generate_rrc_reconfiguration_complete_pdu(0, 8), false); } \ No newline at end of file From d31d97d7634e32f0b91a64454de1aa7bce0c40c2 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 18:22:33 +0200 Subject: [PATCH 021/407] cu_cp: refactor inter du handover test --- .../e1ap/e1ap_test_message_validators.cpp | 9 + .../e1ap/e1ap_test_message_validators.h | 3 + .../f1ap/f1ap_test_message_validators.cpp | 8 + .../f1ap/f1ap_test_message_validators.h | 2 + tests/unittests/cu_cp/CMakeLists.txt | 1 + .../cu_cp/cu_cp_inter_du_handover_test.cpp | 237 +++++++++++++++ .../cu_cp/cu_cp_test_environment.cpp | 109 ++++++- .../unittests/cu_cp/cu_cp_test_environment.h | 5 +- tests/unittests/cu_cp/mobility/CMakeLists.txt | 3 +- .../inter_du_handover_routine_test.cpp | 278 ------------------ 10 files changed, 370 insertions(+), 285 deletions(-) create mode 100644 tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp delete mode 100644 tests/unittests/cu_cp/mobility/inter_du_handover_routine_test.cpp diff --git a/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp b/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp index 628123fce4..519fc74678 100644 --- a/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp +++ b/tests/test_doubles/e1ap/e1ap_test_message_validators.cpp @@ -10,6 +10,7 @@ #include "e1ap_test_message_validators.h" #include "srsran/asn1/e1ap/e1ap.h" +#include "srsran/asn1/e1ap/e1ap_pdu_contents.h" #include "srsran/e1ap/common/e1ap_message.h" using namespace srsran; @@ -43,6 +44,14 @@ bool srsran::test_helpers::is_valid_bearer_context_modification_request(const e1 return true; } +bool srsran::test_helpers::is_valid_bearer_context_modification_request_with_ue_security_info(const e1ap_message& msg) +{ + TRUE_OR_RETURN(is_valid_bearer_context_modification_request(msg)); + TRUE_OR_RETURN(msg.pdu.init_msg().value.bearer_context_mod_request()->security_info_present); + + return true; +} + bool srsran::test_helpers::is_valid_bearer_context_release_command(const e1ap_message& msg) { TRUE_OR_RETURN(msg.pdu.type() == asn1::e1ap::e1ap_pdu_c::types_opts::init_msg); diff --git a/tests/test_doubles/e1ap/e1ap_test_message_validators.h b/tests/test_doubles/e1ap/e1ap_test_message_validators.h index 8ea68f2400..28e23cc78f 100644 --- a/tests/test_doubles/e1ap/e1ap_test_message_validators.h +++ b/tests/test_doubles/e1ap/e1ap_test_message_validators.h @@ -23,6 +23,9 @@ bool is_valid_bearer_context_setup_request(const e1ap_message& msg); /// \brief Check if an E1AP message is a valid Bearer Context Modification Request message. bool is_valid_bearer_context_modification_request(const e1ap_message& msg); +/// \brief Check if an E1AP message is a valid Bearer Context Modification Request message. +bool is_valid_bearer_context_modification_request_with_ue_security_info(const e1ap_message& msg); + /// \brief Check if an E1AP message is a valid Bearer Context Release Command message. bool is_valid_bearer_context_release_command(const e1ap_message& msg); diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp index 150272954a..0057eae9a5 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp @@ -112,6 +112,14 @@ bool srsran::test_helpers::is_valid_ue_context_setup_request(const f1ap_message& return true; } +bool srsran::test_helpers::is_valid_ue_context_setup_request_with_ue_capabilities(const f1ap_message& msg) +{ + TRUE_OR_RETURN(is_valid_ue_context_setup_request(msg)); + TRUE_OR_RETURN( + msg.pdu.init_msg().value.ue_context_setup_request()->cu_to_du_rrc_info.ue_cap_rat_container_list.size() > 0); + return true; +} + bool srsran::test_helpers::is_ue_context_setup_response_valid(const f1ap_message& msg) { if (not(msg.pdu.type() == asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome and diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index ad8e8346ac..6935778bc5 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -38,6 +38,8 @@ bool is_ul_rrc_msg_transfer_valid(const f1ap_message& msg, srb_id_t srb_id); bool is_valid_ue_context_setup_request(const f1ap_message& msg); +bool is_valid_ue_context_setup_request_with_ue_capabilities(const f1ap_message& msg); + bool is_ue_context_setup_response_valid(const f1ap_message& msg); bool is_valid_ue_context_modification_request(const f1ap_message& msg); diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index 9cba3a7c83..2d5fa72556 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -43,6 +43,7 @@ add_executable(cu_cp_test cu_cp_paging_test.cpp cu_cp_inactivity_notification_test.cpp cu_cp_handover_test.cpp + cu_cp_inter_du_handover_test.cpp ) set_target_properties(cu_cp_test PROPERTIES UNITY_BUILD ON) target_link_libraries(cu_cp_test diff --git a/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp new file mode 100644 index 0000000000..d182aed490 --- /dev/null +++ b/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp @@ -0,0 +1,237 @@ +/* + * + * 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_test_environment.h" +#include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" +#include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" +#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" +#include "srsran/e1ap/common/e1ap_types.h" +#include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/f1ap/common/f1ap_ue_id.h" +#include "srsran/ngap/ngap_message.h" +#include "srsran/support/test_utils.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class cu_cp_inter_du_handover_test : public cu_cp_test_environment, public ::testing::Test +{ +public: + cu_cp_inter_du_handover_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + { + // Run NG setup to completion. + run_ng_setup(); + + // Setup source DU. + std::optional ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + source_du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup(source_du_idx)); + + // Setup target DU. + ret = connect_new_du(); + EXPECT_TRUE(ret.has_value()); + target_du_idx = ret.value(); + EXPECT_TRUE(this->run_f1_setup( + target_du_idx, int_to_gnb_du_id(0x22), nr_cell_identity::create(gnb_id_t{411, 22}, 1).value(), 2)); + + // Setup CU-UP. + ret = connect_new_cu_up(); + EXPECT_TRUE(ret.has_value()); + cu_up_idx = ret.value(); + EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); + + // Connect UE 0x4601. + EXPECT_TRUE(cu_cp_test_environment::attach_ue( + source_du_idx, cu_up_idx, du_ue_id, crnti, amf_ue_id, cu_up_e1ap_id, psi, drb_id_t::drb1, qfi)); + ue_ctx = this->find_ue_context(source_du_idx, du_ue_id); + + EXPECT_NE(ue_ctx, nullptr); + } + + void send_rrc_measurement_report_and_await_ue_context_setup_request() + { + // Inject UL RRC Message (containing RRC Measurement Report) and wait for UE Context Setup Request + get_du(source_du_idx) + .push_ul_pdu( + generate_ul_rrc_message_transfer(ue_ctx->cu_ue_id.value(), + ue_ctx->du_ue_id.value(), + srb_id_t::srb1, + make_byte_buffer("000800410004015f741fe0804bf183fcaa6e9699").value())); + bool result = this->wait_for_f1ap_tx_pdu(target_du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Setup Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_setup_request_with_ue_capabilities(f1ap_pdu), + "Invalid UE Context Setup Request"); + } + + void send_ue_context_setup_failure() + { + // Inject UE Context Setup Failure + get_du(target_du_idx) + .push_ul_pdu(generate_ue_context_setup_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + } + + void send_ue_context_setup_response_and_await_bearer_context_modification_request() + { + // Inject UE Context Setup Response and await Bearer Context Modification Request + get_du(target_du_idx) + .push_ul_pdu( + generate_ue_context_setup_response(ue_ctx->cu_ue_id.value(), + ue_ctx->du_ue_id.value(), + crnti, + make_byte_buffer("5c06c0060030258380f80408d07810000929dc601349798002692f" + "1200000464c6b6c61b3704020000080800041a235246c0134978" + "90000023271adb19127c03033255878092748837146e30dc71b963" + "7dfab6387580221603400c162300e20981950001ff0000000003" + "06e10840000402ca0041904000040d31a01100102000e388844800" + "4080038e2221400102000e3888c60004080038e24060088681aa" + "b2420e0008206102860e4a60c9a3670e8f00000850000800b50001" + "000850101800b50102000850202800b50203000850303800b503" + "0b8c8b5040c00504032014120d00505036014160e0050603a0141a" + "120c506a0496302a72fd159e26f2681d2083c5df81821c000000" + "38ffd294a5294f28160000219760000000000005000001456aa280" + "23800c00041000710804e20070101084000e21009c200e040220" + "8001c420138401c0c042100038840270c038200882000710804e18" + "004000000410c04080c100e0d0000e388000000400800100c001" + "0120044014c00004620090e3800c") + .value())); + bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not( + test_helpers::is_valid_bearer_context_modification_request_with_ue_security_info(e1ap_pdu), + "Invalid Bearer Context Modification Request"); + } + + void send_bearer_context_modification_failure_and_await_f1ap_ue_context_release_command() + { + // Inject Bearer Context Modification Failure and wait for UE Context Release Command + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(target_du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), + "Invalid UE Context Release Command"); + } + + void send_bearer_context_modification_response_and_await_ue_context_modification_request() + { + // Inject Bearer Context Modification Response and wait for RRC Reconfiguration + get_cu_up(cu_up_idx).push_tx_pdu( + generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); + bool result = this->wait_for_f1ap_tx_pdu(source_du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), + "Invalid UE Context Modification Request"); + } + + void send_ue_context_modification_response() + { + // Inject UE Context Modification Response and wait for UE Context Release Command + get_du(source_du_idx) + .push_ul_pdu( + generate_ue_context_modification_response(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value(), crnti)); + } + + void send_rrc_reconfiguration_complete() + { + get_du(target_du_idx) + .push_ul_pdu(generate_ul_rrc_message_transfer(ue_ctx->cu_ue_id.value(), + ue_ctx->du_ue_id.value(), + srb_id_t::srb1, + make_byte_buffer("8000080035c41efd").value())); + } + + void send_f1ap_ue_context_release_complete(unsigned du_idx) + { + // Inject F1AP UE Context Release Complete + get_du(du_idx).push_ul_pdu( + generate_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + } + + unsigned source_du_idx = 0; + unsigned target_du_idx = 0; + unsigned cu_up_idx = 0; + + gnb_du_ue_f1ap_id_t du_ue_id = gnb_du_ue_f1ap_id_t::min; + gnb_cu_ue_f1ap_id_t cu_ue_id; + rnti_t crnti = to_rnti(0x4601); + amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( + test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); + gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; + gnb_cu_cp_ue_e1ap_id_t cu_cp_e1ap_id; + + const ue_context* ue_ctx = nullptr; + + pdu_session_id_t psi = uint_to_pdu_session_id(1); + qos_flow_id_t qfi = uint_to_qos_flow_id(1); + + ngap_message ngap_pdu; + f1ap_message f1ap_pdu; + e1ap_message e1ap_pdu; +}; + +TEST_F(cu_cp_inter_du_handover_test, when_ue_context_setup_fails_then_ho_fails) +{ + // Inject Measurement Report and await F1AP UE Context Setup Request + send_rrc_measurement_report_and_await_ue_context_setup_request(); + + // Inject UE Context Setup Failure + send_ue_context_setup_failure(); + + // STATUS: UE should be removed from target DU + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 1) << "UE should be removed"; +} + +TEST_F(cu_cp_inter_du_handover_test, when_bearer_context_modification_fails_then_ho_fails) +{ + // Inject Measurement Report and await F1AP UE Context Setup Request + send_rrc_measurement_report_and_await_ue_context_setup_request(); + + // Inject UE Context Setup Response and await Bearer Context Modification Request + send_ue_context_setup_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Failure + send_bearer_context_modification_failure_and_await_f1ap_ue_context_release_command(); + + // Inject F1AP UE Context Release Complete + send_f1ap_ue_context_release_complete(target_du_idx); + + // STATUS: UE should be removed from target DU + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 1) << "UE should be removed"; +} + +TEST_F(cu_cp_inter_du_handover_test, when_ho_succeeds_then_source_ue_is_removed) +{ + // Inject Measurement Report and await F1AP UE Context Setup Request + send_rrc_measurement_report_and_await_ue_context_setup_request(); + + // Inject UE Context Setup Response and await Bearer Context Modification Request + send_ue_context_setup_response_and_await_bearer_context_modification_request(); + + // Inject Bearer Context Modification Response and await UE Context Modification Request + send_bearer_context_modification_response_and_await_ue_context_modification_request(); + + // Inject UE Context Modification Response + send_ue_context_modification_response(); + + // Inject RRC Reconfiguration Complete + send_rrc_reconfiguration_complete(); + + // Inject F1AP UE Context Release Complete + send_f1ap_ue_context_release_complete(source_du_idx); + + // STATUS: UE should be removed from source DU + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 1) << "UE should be removed"; +} diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index 15b780c7c0..e71031ceb3 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -22,6 +22,7 @@ #include "srsran/asn1/ngap/ngap_pdu_contents.h" #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" #include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" +#include "srsran/cu_cp/cell_meas_manager_config.h" #include "srsran/cu_cp/cu_cp_configuration_helpers.h" #include "srsran/cu_cp/cu_cp_factory.h" #include "srsran/cu_cp/cu_cp_types.h" @@ -66,7 +67,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : srslog::fetch_basic_logger("SEC").set_hex_dump_max_size(32); srslog::init(); - // create CU-CP config + // Create CU-CP config cu_cp_cfg = config_helpers::make_default_cu_cp_config(); cu_cp_cfg.services.cu_cp_executor = cu_cp_workers->exec.get(); cu_cp_cfg.services.n2_gw = &*amf_stub; @@ -75,7 +76,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : cu_cp_cfg.admission.max_nof_cu_ups = params.max_nof_cu_ups; cu_cp_cfg.admission.max_nof_ues = params.max_nof_ues; cu_cp_cfg.bearers.drb_config = config_helpers::make_default_cu_cp_qos_config_list(); - // > security config. + // > Security config. cu_cp_cfg.security.int_algo_pref_list = {security::integrity_algorithm::nia2, security::integrity_algorithm::nia1, security::integrity_algorithm::nia3, @@ -87,6 +88,106 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : cu_cp_cfg.f1ap.json_log_enabled = true; + // > Mobility config + cu_cp_cfg.mobility.mobility_manager_config.trigger_handover_from_measurements = true; + { + // > Meas manager config + cell_meas_manager_cfg meas_mng_cfg; + { + // Generate NCIs. + gnb_id_t gnb_id1 = cu_cp_cfg.node.gnb_id; + nr_cell_identity nci1 = nr_cell_identity::create(gnb_id1, 0).value(); + nr_cell_identity nci2 = nr_cell_identity::create(gnb_id1, 1).value(); + gnb_id_t gnb_id2 = {cu_cp_cfg.node.gnb_id.id + 1, cu_cp_cfg.node.gnb_id.bit_length}; + nr_cell_identity nci3 = nr_cell_identity::create(gnb_id2, 0).value(); + + // Cell 1 + { + cell_meas_config cell_cfg_1; + cell_cfg_1.periodic_report_cfg_id = uint_to_report_cfg_id(1); + cell_cfg_1.serving_cell_cfg.gnb_id_bit_length = gnb_id1.bit_length; + cell_cfg_1.serving_cell_cfg.nci = nci1; + cell_cfg_1.ncells.push_back({nci2, {uint_to_report_cfg_id(2)}}); + // Add external cell (for inter CU handover tests) + cell_cfg_1.ncells.push_back({nci3, {uint_to_report_cfg_id(2)}}); + + meas_mng_cfg.cells.emplace(nci1, cell_cfg_1); + } + + // Cell 2 + { + cell_meas_config cell_cfg_2; + cell_cfg_2.periodic_report_cfg_id = uint_to_report_cfg_id(1); + cell_cfg_2.serving_cell_cfg.gnb_id_bit_length = gnb_id1.bit_length; + cell_cfg_2.serving_cell_cfg.nci = nci2; + cell_cfg_2.ncells.push_back({nci1, {uint_to_report_cfg_id(2)}}); + meas_mng_cfg.cells.emplace(nci2, cell_cfg_2); + } + + // Add an external cell + { + cell_meas_config cell_cfg_3; + cell_cfg_3.periodic_report_cfg_id = uint_to_report_cfg_id(1); + cell_cfg_3.serving_cell_cfg.gnb_id_bit_length = gnb_id2.bit_length; + cell_cfg_3.serving_cell_cfg.nci = nci3; + cell_cfg_3.serving_cell_cfg.pci = 3; + cell_cfg_3.serving_cell_cfg.ssb_arfcn = 632628; + cell_cfg_3.serving_cell_cfg.band = nr_band::n78; + cell_cfg_3.serving_cell_cfg.ssb_scs = subcarrier_spacing::kHz15; + cell_cfg_3.serving_cell_cfg.ssb_mtc = rrc_ssb_mtc{{rrc_periodicity_and_offset::periodicity_t::sf20, 0}, 5}; + + cell_cfg_3.ncells.push_back({nci1, {uint_to_report_cfg_id(2)}}); + meas_mng_cfg.cells.emplace(nci3, cell_cfg_3); + } + + // Add periodic event + { + rrc_report_cfg_nr periodic_report_cfg; + auto& periodical_cfg = periodic_report_cfg.periodical.emplace(); + + periodical_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; + periodical_cfg.report_interv = 1024; + periodical_cfg.report_amount = -1; + periodical_cfg.report_quant_cell.rsrp = true; + periodical_cfg.report_quant_cell.rsrq = true; + periodical_cfg.report_quant_cell.sinr = true; + periodical_cfg.max_report_cells = 4; + + periodic_report_cfg.periodical = periodical_cfg; + meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), periodic_report_cfg); + } + + // Add event A3 + { + rrc_report_cfg_nr a3_report_cfg; + auto& event_trigger_cfg = a3_report_cfg.event_triggered.emplace(); + auto& event_a3 = a3_report_cfg.event_triggered.value().event_id.event_a3.emplace(); + + event_a3.a3_offset.rsrp.emplace() = 6; + event_a3.hysteresis = 0; + event_a3.time_to_trigger = 100; + + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; + event_trigger_cfg.report_interv = 1024; + event_trigger_cfg.report_amount = -1; + event_trigger_cfg.report_quant_cell.rsrp = true; + event_trigger_cfg.report_quant_cell.rsrq = true; + event_trigger_cfg.report_quant_cell.sinr = true; + event_trigger_cfg.max_report_cells = 4; + + rrc_meas_report_quant report_quant_rs_idxes; + report_quant_rs_idxes.rsrp = true; + report_quant_rs_idxes.rsrq = true; + report_quant_rs_idxes.sinr = true; + event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; + + a3_report_cfg.event_triggered = event_trigger_cfg; + meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); + } + } + cu_cp_cfg.mobility.meas_manager_config = meas_mng_cfg; + } + // create CU-CP instance. cu_cp_inst = create_cu_cp(cu_cp_cfg); } @@ -210,9 +311,9 @@ bool cu_cp_test_environment::drop_du_connection(unsigned du_idx) return true; } -bool cu_cp_test_environment::run_f1_setup(unsigned du_idx) +bool cu_cp_test_environment::run_f1_setup(unsigned du_idx, gnb_du_id_t gnb_du_id, nr_cell_identity nci, pci_t pci) { - get_du(du_idx).push_ul_pdu(test_helpers::generate_f1_setup_request()); + get_du(du_idx).push_ul_pdu(test_helpers::generate_f1_setup_request(gnb_du_id, nci, pci)); f1ap_message f1ap_pdu; bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); return result; diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index 35416da6c1..25554a78b0 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -61,7 +61,10 @@ class cu_cp_test_environment /// Drop TNL connection between a DU and the CU-CP. bool drop_du_connection(unsigned du_idx); /// Run F1 setup procedure to completion. - bool run_f1_setup(unsigned du_idx); + bool run_f1_setup(unsigned du_idx, + gnb_du_id_t gnb_du_id = int_to_gnb_du_id(0x11), + nr_cell_identity nci = nr_cell_identity::create(gnb_id_t{411, 22}, 0U).value(), + pci_t pci = 0); /// Establish a TNL connection between a CU-UP and the CU-CP. std::optional connect_new_cu_up(); diff --git a/tests/unittests/cu_cp/mobility/CMakeLists.txt b/tests/unittests/cu_cp/mobility/CMakeLists.txt index 6e4dacc5ef..515d5da2d6 100644 --- a/tests/unittests/cu_cp/mobility/CMakeLists.txt +++ b/tests/unittests/cu_cp/mobility/CMakeLists.txt @@ -10,8 +10,7 @@ add_library(mobility_test_helpers mobility_test_helpers.cpp ../du_processor_test target_include_directories(mobility_test_helpers PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(mobility_test_helpers srsran_cu_cp e1ap_test_helpers f1ap_test_helpers rrc_ue_test_helpers ngap_test_helpers srsran_support f1ap_asn1 srslog) -set(SOURCES inter_du_handover_routine_test.cpp - inter_cu_handover_routine_test.cpp +set(SOURCES inter_cu_handover_routine_test.cpp handover_reconfiguration_routine_test.cpp) add_executable(cu_cp_mobility_test ${SOURCES}) diff --git a/tests/unittests/cu_cp/mobility/inter_du_handover_routine_test.cpp b/tests/unittests/cu_cp/mobility/inter_du_handover_routine_test.cpp deleted file mode 100644 index b2c0a76d6e..0000000000 --- a/tests/unittests/cu_cp/mobility/inter_du_handover_routine_test.cpp +++ /dev/null @@ -1,278 +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 "mobility_test_helpers.h" -#include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" -#include "srsran/support/async/async_test_utils.h" -#include "srsran/support/test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -class inter_du_handover_routine_test : public mobility_test -{ -protected: - inter_du_handover_routine_test() {} - - /// \brief Create two DUs and attach a single UE to the first DU. - void create_dus_and_attach_ue() - { - // Test preamble to create CU-CP, attach to 5GC, attach CU-UP, create and attach DU and attach UE. - du_index_t du_index = source_du_index; - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - source_rnti = to_rnti(0x4601); - source_pci = 1; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - std::vector psis = {uint_to_pdu_session_id(1)}; - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(0); - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id = int_to_gnb_cu_up_ue_e1ap_id(0); - - // Connect AMF, DU, CU-UP. - test_preamble_all_connected(du_index, source_pci); - // Attach target DU. - test_du_attach(target_du_index, target_du_id, target_nrcell_id, target_pci); - // Attach UE. - test_preamble_ue_full_attach( - du_index, du_ue_id, cu_ue_id, source_rnti, amf_ue_id, ran_ue_id, psis, cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - - // Assert single UE attached to source DU. - ASSERT_EQ(get_nof_ues_in_source_du(), 1); - ASSERT_EQ(get_nof_ues_in_target_du(), 0); - } - - /// \brief Inject an RRC measurement report to trigger handover. - void inject_rrc_meas_report() - { - // Inject UL RRC message containing RRC measurement report to trigger HO - f1ap_message ul_rrc_msg = - generate_ul_rrc_message_transfer(int_to_gnb_cu_ue_f1ap_id(0), - int_to_gnb_du_ue_f1ap_id(0), - srb_id_t::srb1, - make_byte_buffer("000800410004015f741fe0804bf183fcaa6e9699").value()); - test_logger.info("Injecting UL RRC message (RRC Measurement Report)"); - f1c_gw.get_du(source_du_index).on_new_message(ul_rrc_msg); - } - - /// \brief Start the inter-DU handover procedure. - void start_procedure(pci_t source_pci_, rnti_t crnti, pci_t target_pci_) - { - // Not needed anymore - cu_cp_obj->get_command_handler().get_mobility_command_handler().trigger_handover(source_pci_, crnti, target_pci_); - } - - /// \brief Inject UE Context Setup Failure. - void inject_ue_context_setup_failure() - { - f1ap_message ue_context_setup_fail = - generate_ue_context_setup_failure(int_to_gnb_cu_ue_f1ap_id(0), int_to_gnb_du_ue_f1ap_id(0)); - f1c_gw.get_du(target_du_index).on_new_message(ue_context_setup_fail); - } - - /// \brief Inject UE Context Setup Response. - void inject_ue_context_setup_response() - { - f1ap_message ue_context_setup_resp = generate_ue_context_setup_response( - int_to_gnb_cu_ue_f1ap_id(0), - int_to_gnb_du_ue_f1ap_id(0), - to_rnti(0x4601), - make_byte_buffer( - "5c06c0060030258380f80408d07810000929dc601349798002692f1200000464c6b6c61b3704020000080800041a235246c0134978" - "90000023271adb19127c03033255878092748837146e30dc71b9637dfab6387580221603400c162300e20981950001ff0000000003" - "06e10840000402ca0041904000040d31a01100102000e3888448004080038e2221400102000e3888c60004080038e24060088681aa" - "b2420e0008206102860e4a60c9a3670e8f00000850000800b50001000850101800b50102000850202800b50203000850303800b503" - "0b8c8b5040c00504032014120d00505036014160e0050603a0141a120c506a0496302a72fd159e26f2681d2083c5df81821c000000" - "38ffd294a5294f28160000219760000000000005000001456aa28023800c00041000710804e20070101084000e21009c200e040220" - "8001c420138401c0c042100038840270c038200882000710804e18004000000410c04080c100e0d0000e388000000400800100c001" - "0120044014c00004620090e3800c") - .value()); - f1c_gw.get_du(target_du_index).on_new_message(ue_context_setup_resp); - } - - /// \brief Inject Bearer Context Modification Failure. - void inject_bearer_context_modification_failure() - { - e1ap_message bearer_context_modification_fail = - generate_bearer_context_modification_failure(int_to_gnb_cu_cp_ue_e1ap_id(0), int_to_gnb_cu_up_ue_e1ap_id(0)); - e1ap_gw.get_cu_up(0).on_new_message(bearer_context_modification_fail); - } - - /// \brief Inject Bearer Context Modification Response. - void inject_bearer_context_modification_response() - { - e1ap_message bearer_context_modification_resp = - generate_bearer_context_modification_response(int_to_gnb_cu_cp_ue_e1ap_id(0), int_to_gnb_cu_up_ue_e1ap_id(0)); - e1ap_gw.get_cu_up(0).on_new_message(bearer_context_modification_resp); - } - - /// \brief Inject Bearer Context Release Complete. - void inject_bearer_context_release_complete() - { - e1ap_message bearer_context_release_complete = - generate_bearer_context_release_complete(int_to_gnb_cu_cp_ue_e1ap_id(0), int_to_gnb_cu_up_ue_e1ap_id(0)); - e1ap_gw.get_cu_up(0).on_new_message(bearer_context_release_complete); - } - - /// \brief Inject UE Context Modification Response. - void inject_ue_context_modification_response() - { - f1ap_message ue_context_mod_resp = generate_ue_context_modification_response( - int_to_gnb_cu_ue_f1ap_id(0), int_to_gnb_du_ue_f1ap_id(0), to_rnti(0x4601)); - f1c_gw.get_du(source_du_index).on_new_message(ue_context_mod_resp); - } - - /// \brief Inject RRC Reconfiguration Complete. - void inject_rrc_reconfig_complete(std::optional transaction_id = {}) - { - f1ap_message rrc_recfg_complete = generate_ul_rrc_message_transfer(int_to_gnb_cu_ue_f1ap_id(0), - int_to_gnb_du_ue_f1ap_id(0), - srb_id_t::srb1, - make_byte_buffer("8000080035c41efd").value()); - f1c_gw.get_du(target_du_index).on_new_message(rrc_recfg_complete); - } - - /// \brief Inject UE Context Release Complete. - void inject_ue_context_release_complete(du_index_t du_index) - { - f1ap_message ue_context_release_complete = - generate_ue_context_release_complete(int_to_gnb_cu_ue_f1ap_id(0), int_to_gnb_du_ue_f1ap_id(0)); - f1c_gw.get_du(du_index).on_new_message(ue_context_release_complete); - } - - du_index_t get_source_du_index() { return source_du_index; } - - ue_index_t get_source_ue() { return source_ue_index; } - - unsigned get_target_pci() { return target_pci; } - - du_index_t get_target_du_index() { return target_du_index; } - - nr_cell_global_id_t get_target_cgi() { return target_cgi; } - - size_t get_nof_ues_in_target_du() const { return nof_du_ues(target_du_index); } - size_t get_nof_ues_in_source_du() const { return nof_du_ues(source_du_index); } - -private: - size_t nof_du_ues(du_index_t idx) const - { - const metrics_report report = cu_cp_obj->get_metrics_handler().request_metrics_report(); - gnb_du_id_t du_id = report.dus.at((size_t)idx).id; - return std::count_if(report.ues.begin(), report.ues.end(), [du_id](const auto& u) { return u.du_id == du_id; }); - } - - // source DU parameters. - du_index_t source_du_index = uint_to_du_index(0); - pci_t source_pci; - rnti_t source_rnti; - - // target DU parameters. - du_index_t target_du_index = uint_to_du_index(1); - gnb_du_id_t target_du_id = int_to_gnb_du_id(0x22); - nr_cell_identity target_nrcell_id = nr_cell_identity::create(gnb_id_t{411, 22}, 1).value(); - nr_cell_global_id_t target_cgi = {plmn_identity::test_value(), target_nrcell_id}; - unsigned target_pci = 2; - - ue_index_t source_ue_index = uint_to_ue_index(0); -}; - -TEST_F(inter_du_handover_routine_test, when_invalid_pci_is_used_then_ho_fails) -{ - // Test Preamble. - create_dus_and_attach_ue(); - - // it should be ready immediately - start_procedure(1, to_rnti(0x4601), INVALID_PCI); -} - -TEST_F(inter_du_handover_routine_test, when_ue_context_setup_fails_then_ho_fails) -{ - // Test Preamble. - create_dus_and_attach_ue(); - - // Start handover by injecting measurement report - inject_rrc_meas_report(); - - // Inject UE Context Setup Failure - inject_ue_context_setup_failure(); - - // Verify new UE has been deleted in target DU again. - ASSERT_EQ(get_nof_ues_in_source_du(), 1); - ASSERT_EQ(get_nof_ues_in_target_du(), 0); -} - -TEST_F(inter_du_handover_routine_test, when_bearer_context_modification_fails_then_ho_fails) -{ - // Test Preamble. - create_dus_and_attach_ue(); - - // Start handover by injecting measurement report - inject_rrc_meas_report(); - - // Inject UE Context Setup Response - inject_ue_context_setup_response(); - - // Inject Bearer Context Modification Failure - inject_bearer_context_modification_failure(); - - // Inject UE Context Release Complete - inject_ue_context_release_complete(get_target_du_index()); - - // Verify new UE has been deleted in target DU again. - ASSERT_EQ(get_nof_ues_in_source_du(), 1); - ASSERT_EQ(get_nof_ues_in_target_du(), 0); -} - -TEST_F(inter_du_handover_routine_test, when_ho_succeeds_then_source_ue_is_removed) -{ - // Test Preamble. - create_dus_and_attach_ue(); - - // Start handover by injecting measurement report - inject_rrc_meas_report(); - - // check that the UE Context Setup Request contains the UE capabilities - ASSERT_EQ(f1c_gw.last_tx_pdus(1).back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(f1c_gw.last_tx_pdus(1).back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ue_context_setup_request); - ASSERT_NE(f1c_gw.last_tx_pdus(1) - .back() - .pdu.init_msg() - .value.ue_context_setup_request() - ->cu_to_du_rrc_info.ue_cap_rat_container_list.size(), - 0U); - - // Inject UE Context Setup Response - inject_ue_context_setup_response(); - - // Make sure Bearer Context Modification contains security info - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_mod_request); - ASSERT_TRUE(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.bearer_context_mod_request()->security_info_present); - - // Inject Bearer Context Modification Response - inject_bearer_context_modification_response(); - - // Inject UE Context Modification Response - inject_ue_context_modification_response(); - - // Inject RRC Reconfiguration Complete - inject_rrc_reconfig_complete(); - - // Inject UE Context Release Complete - inject_ue_context_release_complete(get_source_du_index()); - - // Verify that the HO was successful and the UE has been deleted in source DU. - ASSERT_EQ(get_nof_ues_in_source_du(), 0); - ASSERT_EQ(get_nof_ues_in_target_du(), 1); -} From 02048147a8a9af428479208b4ed91a7469d75562 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 22 Jul 2024 14:44:29 +0200 Subject: [PATCH 022/407] phy: synchronous PDSCH processor pool accepts one thread --- .../upper/channel_processors/channel_processor_factories.cpp | 3 +-- .../phy/upper/channel_processors/pdsch_processor_benchmark.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/phy/upper/channel_processors/channel_processor_factories.cpp b/lib/phy/upper/channel_processors/channel_processor_factories.cpp index edf90d83b2..1cae7c26fe 100644 --- a/lib/phy/upper/channel_processors/channel_processor_factories.cpp +++ b/lib/phy/upper/channel_processors/channel_processor_factories.cpp @@ -496,8 +496,7 @@ class pdsch_processor_pool_factory : public pdsch_processor_factory factory(std::move(factory_)), max_nof_processors(max_nof_processors_) { srsran_assert(factory, "Invalid PDSCH processor factory."); - srsran_assert( - max_nof_processors > 1, "The number of processors (i.e., {}) must be greater than one.", max_nof_processors); + srsran_assert(max_nof_processors != 0, "The number of processors must not be zero."); } std::unique_ptr create() override diff --git a/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp index ea395e37e8..2d4ef21485 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp @@ -610,7 +610,7 @@ static pdsch_processor_factory& get_processor_factory() } // Create synchronous PDSCH processor pool if the processor is synchronous. - if (pdsch_proc_factory) { + if (pdsch_proc_factory && (nof_threads > 1)) { // Only valid for generic and lite. pdsch_proc_factory = create_pdsch_processor_pool(std::move(pdsch_proc_factory), nof_threads); } From 530fd33d43058fc17d2c9ce83150df9ce5c69f10 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 19 Jul 2024 17:20:51 +0200 Subject: [PATCH 023/407] phy: PRACH buffer uses CBF16 phy: review PRACH buffer related --- include/srsran/phy/support/prach_buffer.h | 5 +- include/srsran/srsvec/add.h | 1 + include/srsran/srsvec/dot_prod.h | 13 ++-- ...h_uplane_prach_symbol_data_flow_writer.cpp | 8 +-- lib/ofh/support/prach_context_repository.h | 9 +-- .../ofdm_prach_demodulator_impl.cpp | 9 +-- lib/phy/support/prach_buffer_impl.h | 6 +- .../prach_detector_generic_impl.cpp | 22 +++---- ..._phy_rx_symbol_handler_printer_decorator.h | 14 +++- lib/ru/dummy/ru_dummy_rx_prach_buffer.h | 8 +-- lib/srsvec/add.cpp | 28 ++++++++ lib/srsvec/dot_prod.cpp | 66 +++++++++++++++++++ .../prach_detector_benchmark.cpp | 4 +- tests/unittests/ofh/receiver/helpers.h | 10 +-- ...h_uplane_prach_data_flow_notifier_test.cpp | 4 +- .../ofh_uplink_request_handler_impl_test.cpp | 6 +- .../ofdm_prach_demodulator_test.cpp | 12 ++-- .../phy/support/prach_buffer_test_doubles.h | 18 ++--- .../unittests/srsvec/srsvec_dot_prod_test.cpp | 56 ++++++++++++++++ 19 files changed, 229 insertions(+), 70 deletions(-) diff --git a/include/srsran/phy/support/prach_buffer.h b/include/srsran/phy/support/prach_buffer.h index 56456837a9..4fbee4e7d3 100644 --- a/include/srsran/phy/support/prach_buffer.h +++ b/include/srsran/phy/support/prach_buffer.h @@ -50,7 +50,8 @@ class prach_buffer /// \param[in] i_fd_occasion Frequency-domain occasion. /// \param[in] i_symbol Symbol index within the occasion. /// \return A read-write view of a PRACH OFDM symbol. - virtual span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) = 0; + virtual span + get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) = 0; /// \brief Gets a read-only PRACH symbol for a given port, occasion and symbol. /// @@ -59,7 +60,7 @@ class prach_buffer /// \param[in] i_fd_occasion Frequency-domain occasion. /// \param[in] i_symbol Symbol index within the occasion. /// \return A read-only view of a PRACH OFDM symbol. - virtual span + virtual span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const = 0; }; diff --git a/include/srsran/srsvec/add.h b/include/srsran/srsvec/add.h index ba306b0f84..c9a96a1e03 100644 --- a/include/srsran/srsvec/add.h +++ b/include/srsran/srsvec/add.h @@ -16,6 +16,7 @@ namespace srsran { namespace srsvec { void add(span x, span y, span z); +void add(span x, span y, span z); void add(span x, span y, span z); void add(span x, span y, span z); void add(span x, span y, span z); diff --git a/include/srsran/srsvec/dot_prod.h b/include/srsran/srsvec/dot_prod.h index a821c1065a..c496378b82 100644 --- a/include/srsran/srsvec/dot_prod.h +++ b/include/srsran/srsvec/dot_prod.h @@ -69,14 +69,13 @@ cf_t dot_prod(span x, span y); /// /// The average power of a span is defined as its squared Euclidean norm divided by the number of its elements, i.e. /// dot_prod(x, x) / x.size(). -inline float average_power(span x) -{ - if (x.empty()) { - return 0.0F; - } +float average_power(span x); - return std::real(srsvec::dot_prod(x, x)) / static_cast(x.size()); -} +/// \brief Estimates the average power of a complex span - linear scale. +/// +/// The average power of a span is defined as its squared Euclidean norm divided by the number of its elements, i.e. +/// dot_prod(x, x) / x.size(). +float average_power(span x); } // namespace srsvec } // namespace srsran diff --git a/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp b/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp index 3a9544bb8a..ae491deba4 100644 --- a/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp +++ b/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp @@ -18,8 +18,6 @@ using namespace ofh; void uplane_prach_symbol_data_flow_writer::write_to_prach_buffer(unsigned eaxc, const uplane_message_decoder_results& results) { - std::array conv_buffer; - slot_point slot = results.params.slot; prach_context prach_context = prach_context_repo->get(slot); @@ -92,12 +90,10 @@ void uplane_prach_symbol_data_flow_writer::write_to_prach_buffer(unsigned unsigned iq_size_re = std::min(section_nof_re, prach_nof_res); // Grab the data. - span prach_in_data_cbf16 = span(section.iq_samples).subspan(iq_start_re, iq_size_re); - span prach_in_data_cf(conv_buffer.data(), prach_in_data_cbf16.size()); - srsvec::convert(prach_in_data_cf, prach_in_data_cbf16); + span prach_in_data = span(section.iq_samples).subspan(iq_start_re, iq_size_re); // Copy the data in the buffer. - prach_context_repo->write_iq(slot, port, results.params.symbol_id, start_re, prach_in_data_cf); + prach_context_repo->write_iq(slot, port, results.params.symbol_id, start_re, prach_in_data); logger.debug("Handling PRACH in slot '{}', symbol '{}' and port '{}'", slot, results.params.symbol_id, port); } diff --git a/lib/ofh/support/prach_context_repository.h b/lib/ofh/support/prach_context_repository.h index 6ea8bd8a38..2e54e47723 100644 --- a/lib/ofh/support/prach_context_repository.h +++ b/lib/ofh/support/prach_context_repository.h @@ -19,6 +19,7 @@ #include "srsran/ran/prach/prach_frequency_mapping.h" #include "srsran/ran/prach/prach_preamble_information.h" #include "srsran/srslog/srslog.h" +#include "srsran/srsvec/copy.h" #include #include #include @@ -105,7 +106,7 @@ class prach_context } /// Writes the given IQ buffer corresponding to the given symbol and port. - void write_iq(unsigned port, unsigned symbol, unsigned re_start, span iq_buffer) + void write_iq(unsigned port, unsigned symbol, unsigned re_start, span iq_buffer) { if (is_long_preamble(context_info.context.format)) { // Some RUs always set PRACH symbolId to 0 when long format is used ignoring the value indicated in C-Plane. @@ -125,13 +126,13 @@ class prach_context } // Update the buffer. - span prach_out_buffer = context_info.buffer->get_symbol( + span prach_out_buffer = context_info.buffer->get_symbol( port, context_info.context.nof_fd_occasions - 1, context_info.context.nof_td_occasions - 1, symbol); srsran_assert(prach_out_buffer.last(prach_out_buffer.size() - re_start).size() >= iq_buffer.size(), "Invalid IQ data buffer size to copy as it does not fit into the PRACH buffer"); - std::copy(iq_buffer.begin(), iq_buffer.end(), prach_out_buffer.begin() + re_start); + srsvec::copy(prach_out_buffer.subspan(re_start, iq_buffer.size()), iq_buffer); // Update statistics. buffer_stats[symbol].re_written[port].fill(re_start, re_start + iq_buffer.size()); @@ -225,7 +226,7 @@ class prach_context_repository } /// Function to write the uplink PRACH buffer. - void write_iq(slot_point slot, unsigned port, unsigned symbol, unsigned re_start, span iq_buffer) + void write_iq(slot_point slot, unsigned port, unsigned symbol, unsigned re_start, span iq_buffer) { std::lock_guard lock(mutex); entry(slot).write_iq(port, symbol, re_start, iq_buffer); diff --git a/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp b/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp index 69204dd27c..be518186a1 100644 --- a/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp +++ b/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp @@ -12,6 +12,7 @@ #include "srsran/phy/constants.h" #include "srsran/ran/prach/prach_frequency_mapping.h" #include "srsran/ran/prach/prach_preamble_information.h" +#include "srsran/srsvec/conversion.h" #include "srsran/srsvec/copy.h" using namespace srsran; @@ -164,7 +165,7 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& prach_grid_size); // Select destination PRACH symbol in the buffer. - span prach_symbol = buffer.get_symbol(config.port, i_td_occasion, i_fd_occasion, i_symbol); + span prach_symbol = buffer.get_symbol(config.port, i_td_occasion, i_fd_occasion, i_symbol); // Create views of the lower and upper grid. span lower_grid = dft_output.last(prach_grid_size / 2); @@ -176,11 +177,11 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& unsigned N = std::min(prach_grid_size / 2 - k_start, preamble_info.sequence_length); // Copy first N subcarriers of the sequence in the lower half grid. - srsvec::copy(prach_symbol.first(N), lower_grid.subspan(k_start, N)); + srsvec::convert(prach_symbol.first(N), lower_grid.subspan(k_start, N)); // Copy the remainder of the sequence in the upper half grid. - srsvec::copy(prach_symbol.last(preamble_info.sequence_length - N), - upper_grid.first(preamble_info.sequence_length - N)); + srsvec::convert(prach_symbol.last(preamble_info.sequence_length - N), + upper_grid.first(preamble_info.sequence_length - N)); } else { // Copy the sequence in the upper half grid. srsvec::copy(prach_symbol, upper_grid.subspan(k_start - prach_grid_size / 2, preamble_info.sequence_length)); diff --git a/lib/phy/support/prach_buffer_impl.h b/lib/phy/support/prach_buffer_impl.h index bef89048cf..4e5aff91d4 100644 --- a/lib/phy/support/prach_buffer_impl.h +++ b/lib/phy/support/prach_buffer_impl.h @@ -31,7 +31,7 @@ class prach_buffer_impl : public prach_buffer }; /// Data storage. - dynamic_tensor>(dims::count), cf_t, dims> data; + dynamic_tensor>(dims::count), cbf16_t, dims> data; public: /// Creates a PRACH buffer from the maximum parameters depending on the configuration. @@ -60,7 +60,7 @@ class prach_buffer_impl : public prach_buffer unsigned get_sequence_length() const override { return data.get_dimension_size(dims::re); } // See interface for documentation. - span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override { srsran_assert(i_port < get_max_nof_ports(), "The port index (i.e., {}) exceeds the maximum number of ports (i.e., {}).", @@ -83,7 +83,7 @@ class prach_buffer_impl : public prach_buffer } // See interface for documentation. - span + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const override { srsran_assert(i_port < get_max_nof_ports(), diff --git a/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp b/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp index 72125ee40a..9c74122474 100644 --- a/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp +++ b/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp @@ -16,6 +16,7 @@ #include "srsran/srsvec/accumulate.h" #include "srsran/srsvec/add.h" #include "srsran/srsvec/compare.h" +#include "srsran/srsvec/conversion.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/division.h" #include "srsran/srsvec/dot_prod.h" @@ -221,31 +222,28 @@ prach_detection_result prach_detector_generic_impl::detect(const prach_buffer& i // Iterate all PRACH symbols if they are not combined, otherwise process only one PRACH symbol. for (unsigned i_symbol = 0, i_symbol_end = (combine_symbols) ? 1 : nof_symbols; i_symbol != i_symbol_end; ++i_symbol) { - // Get view of the preamble. - span preamble = input.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol); + // Get a temporary destination for the symbol combination. + span combined_symbols = span(cf_temp).first(L_ra); - // Combine symbols. - if (combine_symbols && (nof_symbols > 1)) { - // Get a temporary destination for the symbol combination. - span combined_symbols = span(cf_temp).first(L_ra); + // Get view of the preamble. + span preamble = input.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol); - // Copy the first PRACH symbol. - srsvec::copy(combined_symbols, preamble); + // Copy the first PRACH symbol. + srsvec::convert(combined_symbols, preamble); - // Combine the rest of PRACH symbols. + // Combine the rest of PRACH symbols. + if (combine_symbols && (nof_symbols > 1)) { for (unsigned i_comb_symbol = 1; i_comb_symbol != nof_symbols; ++i_comb_symbol) { srsvec::add(combined_symbols, input.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_comb_symbol), combined_symbols); } - - preamble = combined_symbols; } // Multiply the preamble by the complex conjugate of the root sequence. std::array no_root_temp; span no_root = span(no_root_temp).first(L_ra); - srsvec::prod_conj(preamble, root, no_root); + srsvec::prod_conj(combined_symbols, root, no_root); // Prepare IDFT for correlation. srsvec::copy(idft_input.first(L_ra / 2 + 1), no_root.last(L_ra / 2 + 1)); diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h b/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h index 74ee3a95c6..60b98cb17a 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h @@ -12,6 +12,7 @@ #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/srsvec/aligned_vec.h" +#include "srsran/srsvec/conversion.h" #include "srsran/support/error_handling.h" #include "srsran/support/executors/task_worker.h" #include @@ -31,6 +32,7 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol logger(logger_), worker("rx_symb_print", 40), temp_buffer(nof_rb * NRE), + temp_prach_buffer(prach_constants::LONG_SEQUENCE_LENGTH), nof_symbols(MAX_NSYMB_PER_SLOT), start_port(ul_print_ports.start()), end_port(ul_print_ports.stop()), @@ -100,8 +102,15 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol unsigned prach_stop = buffer.get_max_nof_ports(); for (unsigned i_port = prach_start; i_port != prach_stop; ++i_port) { for (unsigned i_replica = 0; i_replica != nof_replicas; ++i_replica) { - span samples = buffer.get_symbol(i_port, 0, 0, i_replica); - file.write(reinterpret_cast(samples.data()), samples.size() * sizeof(cf_t)); + // Select view of the replica. + span samples = buffer.get_symbol(i_port, 0, 0, i_replica); + + // Convert samples to complex float. + span samples_cf = temp_prach_buffer.first(samples.size()); + srsvec::convert(samples_cf, samples); + + // Write file. + file.write(reinterpret_cast(samples_cf.data()), samples.size() * sizeof(cf_t)); } } @@ -130,6 +139,7 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol std::ofstream file; task_worker worker; srsvec::aligned_vec temp_buffer; + srsvec::aligned_vec temp_prach_buffer; unsigned nof_symbols; unsigned start_port; unsigned end_port; diff --git a/lib/ru/dummy/ru_dummy_rx_prach_buffer.h b/lib/ru/dummy/ru_dummy_rx_prach_buffer.h index 6ce20d1c20..3520f5f8b1 100644 --- a/lib/ru/dummy/ru_dummy_rx_prach_buffer.h +++ b/lib/ru/dummy/ru_dummy_rx_prach_buffer.h @@ -36,7 +36,7 @@ class ru_dummy_rx_prach_buffer : private prach_buffer // Fill PRACH buffer with random data. complex_normal_distribution dist(0, 1); std::mt19937 rgen(seed); - span data_view = data.get_data(); + span data_view = data.get_data(); std::generate(data_view.begin(), data_view.end(), [&dist, &rgen]() { return dist(rgen); }); } @@ -91,7 +91,7 @@ class ru_dummy_rx_prach_buffer : private prach_buffer unsigned get_sequence_length() const override { return data.get_dimension_size(dims::re); } // See interface for documentation. - span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override { srsran_assert(i_port < get_max_nof_ports(), "The port index (i.e., {}) exceeds the maximum number of ports (i.e., {}).", @@ -114,7 +114,7 @@ class ru_dummy_rx_prach_buffer : private prach_buffer } // See interface for documentation. - span + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const override { srsran_assert(i_port < get_max_nof_ports(), @@ -148,7 +148,7 @@ class ru_dummy_rx_prach_buffer : private prach_buffer }; /// Data storage. - dynamic_tensor>(dims::count), cf_t, dims> data; + dynamic_tensor>(dims::count), cbf16_t, dims> data; }; } // namespace srsran diff --git a/lib/srsvec/add.cpp b/lib/srsvec/add.cpp index 1071b9d866..10a22c59eb 100644 --- a/lib/srsvec/add.cpp +++ b/lib/srsvec/add.cpp @@ -45,6 +45,26 @@ static void add_fff_simd(const float* x, const float* y, float* z, std::size_t l } } +static void add_ccc_simd(const cf_t* x, const cbf16_t* y, cf_t* z, std::size_t len) +{ + std::size_t i = 0; + +#if SRSRAN_SIMD_F_SIZE + for (std::size_t i_end = (len / SRSRAN_SIMD_F_SIZE) * SRSRAN_SIMD_F_SIZE; i != i_end; i += SRSRAN_SIMD_F_SIZE) { + simd_cf_t a = srsran_simd_cfi_loadu(x + i); + simd_cf_t b = srsran_simd_cbf16_loadu(y + i); + + simd_cf_t r = srsran_simd_cf_add(a, b); + + srsran_simd_cfi_storeu(z + i, r); + } +#endif + + for (; i != len; ++i) { + z[i] = x[i] + to_cf(y[i]); + } +} + static void add_sss_simd(const int16_t* x, const int16_t* y, int16_t* z, std::size_t len) { std::size_t i = 0; @@ -118,6 +138,14 @@ void srsran::srsvec::add(span x, span y, span z) 2 * z.size()); } +void srsran::srsvec::add(span x, span y, span z) +{ + srsran_srsvec_assert_size(x, y); + srsran_srsvec_assert_size(x, z); + + add_ccc_simd(x.data(), y.data(), z.data(), 2 * z.size()); +} + void srsran::srsvec::add(span x, span y, span z) { srsran_srsvec_assert_size(x, y); diff --git a/lib/srsvec/dot_prod.cpp b/lib/srsvec/dot_prod.cpp index 7d860843a7..c362a3a8f7 100644 --- a/lib/srsvec/dot_prod.cpp +++ b/lib/srsvec/dot_prod.cpp @@ -45,3 +45,69 @@ cf_t srsran::srsvec::dot_prod(span x, span y) return result; } + +float srsran::srsvec::average_power(span x) +{ + float result = 0; + unsigned i = 0; + unsigned len = x.size(); + + if (len == 0) { + return 0.0F; + } + +#if SRSRAN_SIMD_CF_SIZE + if (len >= SRSRAN_SIMD_CF_SIZE) { + simd_f_t simd_result = srsran_simd_f_zero(); + for (unsigned simd_end = SRSRAN_SIMD_CF_SIZE * (len / SRSRAN_SIMD_CF_SIZE); i != simd_end; + i += SRSRAN_SIMD_CF_SIZE) { + simd_cf_t simd_x = srsran_simd_cfi_loadu(x.data() + i); + + simd_result = srsran_simd_f_add(srsran_simd_cf_norm_sq(simd_x), simd_result); + } + + alignas(SIMD_BYTE_ALIGN) std::array simd_vector_sum; + srsran_simd_f_store(simd_vector_sum.data(), simd_result); + result = std::accumulate(simd_vector_sum.begin(), simd_vector_sum.end(), 0.0F); + } +#endif // SRSRAN_SIMD_CF_SIZE + + for (; i != len; ++i) { + result += std::norm(x[i]); + } + + return result / static_cast(len); +} + +float srsran::srsvec::average_power(span x) +{ + float result = 0; + unsigned i = 0; + unsigned len = x.size(); + + if (len == 0) { + return 0.0F; + } + +#if SRSRAN_SIMD_CF_SIZE + if (len >= SRSRAN_SIMD_CF_SIZE) { + simd_f_t simd_result = srsran_simd_f_zero(); + for (unsigned simd_end = SRSRAN_SIMD_CF_SIZE * (len / SRSRAN_SIMD_CF_SIZE); i != simd_end; + i += SRSRAN_SIMD_CF_SIZE) { + simd_cf_t simd_x = srsran_simd_cbf16_loadu(x.data() + i); + + simd_result = srsran_simd_f_add(srsran_simd_cf_norm_sq(simd_x), simd_result); + } + + alignas(SIMD_BYTE_ALIGN) std::array simd_vector_sum; + srsran_simd_f_store(simd_vector_sum.data(), simd_result); + result = std::accumulate(simd_vector_sum.begin(), simd_vector_sum.end(), 0.0F); + } +#endif // SRSRAN_SIMD_CF_SIZE + + for (; i != len; ++i) { + result += std::norm(to_cf(x[i])); + } + + return result / static_cast(len); +} diff --git a/tests/benchmarks/phy/upper/channel_processors/prach_detector_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/prach_detector_benchmark.cpp index 26574891fe..1e8f7c2aad 100644 --- a/tests/benchmarks/phy/upper/channel_processors/prach_detector_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/prach_detector_benchmark.cpp @@ -115,8 +115,8 @@ static std::unique_ptr create_buffer(prach_format_type format, uns for (unsigned i_antenna = 0; i_antenna != nof_antennas; ++i_antenna) { for (unsigned i_symbol = 0, i_symbol_end = buffer->get_max_nof_symbols(); i_symbol != i_symbol_end; ++i_symbol) { - span prach_symbol = buffer->get_symbol(i_antenna, 0, 0, i_symbol); - for (cf_t& sample : prach_symbol) { + span prach_symbol = buffer->get_symbol(i_antenna, 0, 0, i_symbol); + for (cbf16_t& sample : prach_symbol) { sample = complex_float_dist(rgen); } } diff --git a/tests/unittests/ofh/receiver/helpers.h b/tests/unittests/ofh/receiver/helpers.h index 30fd6c03ff..e47dfa8c99 100644 --- a/tests/unittests/ofh/receiver/helpers.h +++ b/tests/unittests/ofh/receiver/helpers.h @@ -22,9 +22,9 @@ namespace testing { /// PRACH buffer dummy implementation. class prach_buffer_dummy : public prach_buffer { - unsigned nof_symbols; - static_vector buffer; - mutable bool symbol_out_of_bounds; + unsigned nof_symbols; + static_vector buffer; + mutable bool symbol_out_of_bounds; public: prach_buffer_dummy(unsigned nof_symbols_, bool long_format = true) : @@ -42,12 +42,12 @@ class prach_buffer_dummy : public prach_buffer unsigned get_sequence_length() const override { return buffer.size(); } - span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override { return buffer; } - span + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const override { if (i_symbol >= nof_symbols) { diff --git a/tests/unittests/ofh/receiver/ofh_uplane_prach_data_flow_notifier_test.cpp b/tests/unittests/ofh/receiver/ofh_uplane_prach_data_flow_notifier_test.cpp index 05c89aa8d4..68096f082b 100644 --- a/tests/unittests/ofh/receiver/ofh_uplane_prach_data_flow_notifier_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_uplane_prach_data_flow_notifier_test.cpp @@ -73,7 +73,7 @@ TEST(ofh_uplane_prach_data_flow_notifier, completed_long_prach_buffer_triggers_n context.pusch_scs = srsran::subcarrier_spacing::kHz30; context.start_symbol = 0; - static_vector samples(839); + static_vector samples(839); repo->add(context, buffer, std::nullopt, std::nullopt); ASSERT_FALSE(repo->get(slot).empty()); @@ -107,7 +107,7 @@ TEST(ofh_uplane_prach_data_flow_notifier, completed_short_prach_buffer_triggers_ context.pusch_scs = srsran::subcarrier_spacing::kHz30; context.start_symbol = 0; - static_vector samples(139); + static_vector samples(139); repo->add(context, buffer, std::nullopt, std::nullopt); ASSERT_FALSE(repo->get(slot).empty()); diff --git a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp index 082919e009..7becd09f4e 100644 --- a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp @@ -46,7 +46,7 @@ class uplane_rx_symbol_notifier_spy : public uplane_rx_symbol_notifier class prach_buffer_dummy : public prach_buffer { - std::array buffer; + std::array buffer; public: unsigned get_max_nof_ports() const override { return 0; } @@ -59,12 +59,12 @@ class prach_buffer_dummy : public prach_buffer unsigned get_sequence_length() const override { return 0; } - span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override { return buffer; } - span + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const override { return buffer; diff --git a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp index 18c0193982..8a1d16eb45 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp +++ b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp @@ -21,16 +21,16 @@ namespace srsran { static float ASSERT_MAX_ERROR = 1e-3; -static std::ostream& operator<<(std::ostream& os, span data) +static std::ostream& operator<<(std::ostream& os, span data) { fmt::print(os, "{}", data); return os; } -static bool operator==(span lhs, span rhs) +static bool operator==(span lhs, span rhs) { - return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](cf_t lhs_val, cf_t rhs_val) { - return (std::abs(lhs_val - rhs_val) <= ASSERT_MAX_ERROR); + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](cbf16_t lhs_val, cbf16_t rhs_val) { + return (std::abs(to_cf(lhs_val) - to_cf(rhs_val)) <= ASSERT_MAX_ERROR); }); } @@ -116,8 +116,8 @@ TEST_P(ofdm_prach_demodulator_tester, vector) for (unsigned i_td_occasion = 0; i_td_occasion != config.nof_td_occasions; ++i_td_occasion) { for (unsigned i_fd_occasion = 0; i_fd_occasion != config.nof_fd_occasions; ++i_fd_occasion) { for (unsigned i_symbol = 0; i_symbol != nof_symbols; ++i_symbol) { - ASSERT_EQ(span(expected_buffer.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol)), - span(output->get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol))); + ASSERT_EQ(span(expected_buffer.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol)), + span(output->get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol))); } } } diff --git a/tests/unittests/phy/support/prach_buffer_test_doubles.h b/tests/unittests/phy/support/prach_buffer_test_doubles.h index 9bf8e66e5e..036a0a9a3b 100644 --- a/tests/unittests/phy/support/prach_buffer_test_doubles.h +++ b/tests/unittests/phy/support/prach_buffer_test_doubles.h @@ -83,7 +83,7 @@ class prach_buffer_spy : public prach_buffer return buffer.get_sequence_length(); } - span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override { get_symbol_entries.emplace_back(); entry_t& entry = get_symbol_entries.back(); @@ -94,7 +94,7 @@ class prach_buffer_spy : public prach_buffer return buffer.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol); } - span + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const override { get_symbol_const_entries.emplace_back(); @@ -158,10 +158,12 @@ class prach_buffer_tensor : public prach_buffer count = 5, }; - using storage_type = tensor>(dims::count), cf_t, dims>; - /// Creates a PRACH buffer from the maximum parameters depending on the configuration. - explicit prach_buffer_tensor(storage_type& data_) : data(data_) {} + explicit prach_buffer_tensor(tensor>(dims::count), cf_t, dims>& data_cf) : + data(data_cf.get_dimensions_size()) + { + srsvec::copy(data.get_data(), data_cf.get_view(dims::count)>({})); + } // See interface for documentation. unsigned get_max_nof_ports() const override { return data.get_dimension_size(dims::port); } @@ -179,7 +181,7 @@ class prach_buffer_tensor : public prach_buffer unsigned get_sequence_length() const override { return data.get_dimension_size(dims::re); } // See interface for documentation. - span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) override { srsran_assert(i_port < get_max_nof_ports(), "The port index (i.e., {}) exceeds the maximum number of ports (i.e., {}).", @@ -202,7 +204,7 @@ class prach_buffer_tensor : public prach_buffer } // See interface for documentation. - span + span get_symbol(unsigned i_port, unsigned i_td_occasion, unsigned i_fd_occasion, unsigned i_symbol) const override { srsran_assert(i_port < get_max_nof_ports(), @@ -227,7 +229,7 @@ class prach_buffer_tensor : public prach_buffer private: /// Data storage. - storage_type& data; + dynamic_tensor>(dims::count), cbf16_t, dims> data; }; } // namespace srsran diff --git a/tests/unittests/srsvec/srsvec_dot_prod_test.cpp b/tests/unittests/srsvec/srsvec_dot_prod_test.cpp index 15b183da0f..525fd47e2f 100644 --- a/tests/unittests/srsvec/srsvec_dot_prod_test.cpp +++ b/tests/unittests/srsvec/srsvec_dot_prod_test.cpp @@ -47,11 +47,67 @@ static void test_dot_prod_ccc(std::size_t N) z); } +static void test_avg_power_cf(std::size_t N) +{ + std::uniform_real_distribution dist(-1.0, 1.0); + + srsvec::aligned_vec x(N); + for (cf_t& v : x) { + v = {dist(rgen), dist(rgen)}; + } + + float z = srsvec::average_power(x); + + float expected = + std::accumulate( + x.begin(), x.end(), 0.0F, [](float acc, cf_t in) { return acc + std::real(in * std::conj(in)); }) / + static_cast(N); + + float err = std::abs(z - expected); + TESTASSERT(err < ASSERT_MAX_ERROR, + "Error {} is too high (max {}) for size of {} samples. Expected z={} but got z={}.", + err, + ASSERT_MAX_ERROR, + N, + expected, + z); +} + +static void test_avg_power_cbf16(std::size_t N) +{ + std::uniform_real_distribution dist(-1.0, 1.0); + + srsvec::aligned_vec x(N); + for (cbf16_t& v : x) { + v = cbf16_t(dist(rgen), dist(rgen)); + } + + float z = srsvec::average_power(x); + + float expected = + std::accumulate(x.begin(), + x.end(), + 0.0F, + [](float acc, cbf16_t in) { return acc + std::real(to_cf(in) * std::conj(to_cf(in))); }) / + static_cast(N); + + float err = std::abs(z - expected); + TESTASSERT(err < ASSERT_MAX_ERROR, + "Error {} is too high (max {}) for size of {} samples. Expected z={} but got z={}.", + err, + ASSERT_MAX_ERROR, + N, + expected, + z); +} + int main() { std::vector sizes = {1, 5, 7, 19, 23, 65, 130, 257}; for (std::size_t N : sizes) { test_dot_prod_ccc(N); + test_avg_power_cf(N); + test_avg_power_cbf16(N); } } From c594b271c611e1324e7ccc1f15ae32f6bbbbe2af Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 22 Jul 2024 18:13:32 +0200 Subject: [PATCH 024/407] phy: integrate SCS 120kHz to radio SSB --- apps/examples/phy/radio_ssb.cpp | 51 ++++++++++++++++++++++++----- lib/phy/lower/lower_phy_factory.cpp | 8 +++-- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/apps/examples/phy/radio_ssb.cpp b/apps/examples/phy/radio_ssb.cpp index a27d93dacc..4b00fe85b7 100644 --- a/apps/examples/phy/radio_ssb.cpp +++ b/apps/examples/phy/radio_ssb.cpp @@ -110,7 +110,7 @@ static const auto profiles = to_array({ []() { // Do nothing. }}, - {"b200_50MHz", + {"b200_50MHz_15kHz", "Single channel B200 USRP 50MHz bandwidth.", []() { device_arguments = "type=b200"; @@ -118,7 +118,21 @@ static const auto profiles = to_array({ bw_rb = 270; otw_format = radio_configuration::over_the_wire_format::SC12; }}, - {"x300_50MHz", + {"b200_50MHz_120kHz", + "Single channel B200 USRP 50MHz bandwidth.", + []() { + device_arguments = "type=b200"; + srate = sampling_rate::from_MHz(61.44); + bw_rb = 32; + ssb_pattern = ssb_pattern_case::D; + scs = to_subcarrier_spacing(ssb_pattern); + otw_format = radio_configuration::over_the_wire_format::SC12; + dl_center_freq = 3.5e9; + ssb_center_freq = 3.5e9; + rx_freq = 3.5e9; + tx_gain = 80; + }}, + {"x300_50MHz_15kHz", "Single channel X3x0 USRP 50MHz bandwidth.", []() { device_arguments = "type=x300"; @@ -126,6 +140,21 @@ static const auto profiles = to_array({ tx_gain = 10; rx_gain = 10; }}, + {"x300_100MHz_120kHz", + "Single channel X3x0 USRP 100MHz bandwidth.", + []() { + device_arguments = "type=x300"; + srate = sampling_rate::from_MHz(184.32); + bw_rb = 66; + ssb_pattern = ssb_pattern_case::D; + scs = to_subcarrier_spacing(ssb_pattern); + otw_format = radio_configuration::over_the_wire_format::SC16; + dl_center_freq = 3.5e9; + ssb_center_freq = 3.5e9; + rx_freq = 3.5e9; + tx_gain = 30; + rx_gain = 5; + }}, {"n310_50MHz", "Single channel N310 USRP 50MHz bandwidth.", []() { @@ -614,8 +643,14 @@ int main(int argc, char** argv) double scs_Hz = static_cast(1000U * scs_to_khz(scs)); + subcarrier_spacing ref_scs = subcarrier_spacing::kHz15; + if (ssb_pattern > ssb_pattern_case::C) { + ref_scs = subcarrier_spacing::kHz60; + } + double ref_scs_Hz = scs_to_khz(ref_scs) * 1000; + // Ratio between the resource grid SCS and 15kHz SCS. - unsigned ratio_scs_over_15kHz = pow2(to_numerology_value(scs)); + unsigned ratio_scs_over_ref = pow2(to_numerology_value(scs) - to_numerology_value(ref_scs)); // Frequency of Point A in Hz. double dl_pointA_freq_Hz = dl_center_freq - scs_Hz * NRE * bw_rb / 2; // Frequency of the lowest SS/PBCH block subcarrier. @@ -623,20 +658,20 @@ int main(int argc, char** argv) // Frequency offset from Point A to the lowest SS/PBCH block subcarrier in Hz. double ssb_offset_pointA_Hz = ssb_lowest_freq_Hz - dl_pointA_freq_Hz; // Frequency offset from Point A to the lowest SS/PBCH block subcarrier in 15kHz subcarriers (only valid for FR1). - unsigned ssb_offset_pointA_subc_15kHz = static_cast(ssb_offset_pointA_Hz / 15e3); + unsigned ssb_offset_pointA_subc_ref = static_cast(ssb_offset_pointA_Hz / ref_scs_Hz); // Make sure it is possible to map the SS/PBCH block in the grid. - srsran_assert(ssb_offset_pointA_subc_15kHz % ratio_scs_over_15kHz == 0, + srsran_assert(ssb_offset_pointA_subc_ref % ratio_scs_over_ref == 0, "The combination of DL center frequency {} MHz and SSB center frequency {} MHz results in a fractional " "offset of {}kHz SCS between Point A and the lowest SS/PBCH block lowest subcarrier.", dl_center_freq, ssb_center_freq, scs_to_khz(scs)); // SSB frequency offset to Point A as a number of RBs. - ssb_offset_to_pointA ssb_offset_pointA_subc_rb = ssb_offset_pointA_subc_15kHz / NRE; + ssb_offset_to_pointA ssb_offset_pointA_subc_rb = ssb_offset_pointA_subc_ref / NRE; // Round down the offset to Point A to match CRB boundaries. - ssb_offset_pointA_subc_rb = (ssb_offset_pointA_subc_rb.to_uint() / ratio_scs_over_15kHz) * ratio_scs_over_15kHz; + ssb_offset_pointA_subc_rb = (ssb_offset_pointA_subc_rb.to_uint() / ratio_scs_over_ref) * ratio_scs_over_ref; // Remainder SSB frequency offset from Point A after rounding. - ssb_subcarrier_offset subcarrier_offset = ssb_offset_pointA_subc_15kHz - ssb_offset_pointA_subc_rb.to_uint() * NRE; + ssb_subcarrier_offset subcarrier_offset = ssb_offset_pointA_subc_ref - ssb_offset_pointA_subc_rb.to_uint() * NRE; upper_phy_ssb_example::configuration upper_phy_sample_config; upper_phy_sample_config.log_level = log_level; diff --git a/lib/phy/lower/lower_phy_factory.cpp b/lib/phy/lower/lower_phy_factory.cpp index f1c6757ab7..fcd4fdb464 100644 --- a/lib/phy/lower/lower_phy_factory.cpp +++ b/lib/phy/lower/lower_phy_factory.cpp @@ -73,11 +73,13 @@ class lower_phy_factory_sw : public lower_phy_factory const lower_phy_sector_description& sector = config.sectors.front(); - srsran_assert(config.scs < subcarrier_spacing::kHz60, - "Subcarrier spacing of {} is not supported. Only {} and {} are supported.", + srsran_assert((config.scs == subcarrier_spacing::kHz15) || (config.scs == subcarrier_spacing::kHz30) || + (config.scs == subcarrier_spacing::kHz120), + "Subcarrier spacing of {} is not supported. Only {}, {} and {} are supported.", to_string(config.scs), to_string(subcarrier_spacing::kHz15), - to_string(subcarrier_spacing::kHz30)); + to_string(subcarrier_spacing::kHz30), + to_string(subcarrier_spacing::kHz120)); unsigned nof_samples_per_slot = config.srate.to_kHz() / pow2(to_numerology_value(config.scs)); unsigned tx_buffer_size = config.bb_gateway->get_transmitter_optimal_buffer_size(); From ac42853b54683cc01c6e50ba8f3ff2bc20d8dd5b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 25 Jul 2024 09:35:10 +0200 Subject: [PATCH 025/407] cu_cp,rrc: simplify rrc interface name --- include/srsran/rrc/rrc_du.h | 10 +++++----- include/srsran/rrc/rrc_du_factory.h | 2 +- lib/cu_cp/du_processor/du_processor_impl.h | 4 ++-- lib/rrc/rrc_du_factory.cpp | 2 +- lib/rrc/rrc_du_impl.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/srsran/rrc/rrc_du.h b/include/srsran/rrc/rrc_du.h index 1d6c106c4c..521979d20b 100644 --- a/include/srsran/rrc/rrc_du.h +++ b/include/srsran/rrc/rrc_du.h @@ -98,13 +98,13 @@ class rrc_du_statistics_handler }; /// Combined entry point for the RRC DU handling. -class rrc_du_interface : public rrc_du_cell_manager, - public rrc_du_ue_repository, - public rrc_ue_handler, - public rrc_du_statistics_handler +class rrc_du : public rrc_du_cell_manager, + public rrc_du_ue_repository, + public rrc_ue_handler, + public rrc_du_statistics_handler { public: - virtual ~rrc_du_interface() = default; + virtual ~rrc_du() = default; virtual rrc_du_cell_manager& get_rrc_du_cell_manager() = 0; virtual rrc_du_ue_repository& get_rrc_du_ue_repository() = 0; diff --git a/include/srsran/rrc/rrc_du_factory.h b/include/srsran/rrc/rrc_du_factory.h index bb331ab0b6..eaa62e9233 100644 --- a/include/srsran/rrc/rrc_du_factory.h +++ b/include/srsran/rrc/rrc_du_factory.h @@ -28,7 +28,7 @@ struct rrc_du_creation_message { }; /// Create an instance of an RRC entity -std::unique_ptr create_rrc_du(const rrc_du_creation_message& msg); +std::unique_ptr create_rrc_du(const rrc_du_creation_message& msg); } // namespace srs_cu_cp diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index d73390b6ca..a07ea33e07 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -113,8 +113,8 @@ class du_processor_impl : public du_processor, public du_metrics_handler, public std::unordered_map rrc_ue_adapters; // Components - std::unique_ptr f1ap; - std::unique_ptr rrc; + std::unique_ptr f1ap; + std::unique_ptr rrc; }; } // namespace srs_cu_cp diff --git a/lib/rrc/rrc_du_factory.cpp b/lib/rrc/rrc_du_factory.cpp index 752d3c8359..81f620ada4 100644 --- a/lib/rrc/rrc_du_factory.cpp +++ b/lib/rrc/rrc_du_factory.cpp @@ -15,7 +15,7 @@ using namespace srsran; using namespace srs_cu_cp; -std::unique_ptr srsran::srs_cu_cp::create_rrc_du(const rrc_du_creation_message& msg) +std::unique_ptr srsran::srs_cu_cp::create_rrc_du(const rrc_du_creation_message& msg) { return std::make_unique(msg.cfg, msg.nas_notifier, msg.ngap_ctrl_notifier, msg.rrc_du_cu_cp_notifier); } diff --git a/lib/rrc/rrc_du_impl.h b/lib/rrc/rrc_du_impl.h index c3f48fe179..ef5ae7d108 100644 --- a/lib/rrc/rrc_du_impl.h +++ b/lib/rrc/rrc_du_impl.h @@ -21,7 +21,7 @@ namespace srsran { namespace srs_cu_cp { /// Main RRC representation with the DU -class rrc_du_impl : public rrc_du_interface +class rrc_du_impl : public rrc_du { public: rrc_du_impl(const rrc_cfg_t& cfg_, From 4cc4ac4477165595b67c33b30b49d6a8a20ad1f1 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 25 Jul 2024 09:37:42 +0200 Subject: [PATCH 026/407] cu_cp: simplify rrc ue counting for statistics report --- lib/cu_cp/cu_cp_impl.cpp | 5 +---- lib/cu_cp/du_processor/du_processor.h | 3 +++ lib/cu_cp/du_processor/du_processor_impl.h | 2 ++ lib/cu_cp/du_processor/du_processor_repository.cpp | 9 +++++++++ lib/cu_cp/du_processor/du_processor_repository.h | 2 ++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 119ed783ce..e93fcfc281 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -712,10 +712,7 @@ void cu_cp_impl::on_statistics_report_timer_expired() unsigned nof_f1ap_ues = du_db.get_nof_f1ap_ues(); // Get number of RRC UEs - unsigned nof_rrc_ues = 0; - for (auto& rrc_du_adapter_pair : rrc_du_adapters) { - nof_rrc_ues += rrc_du_adapter_pair.second.get_nof_ues(); - } + unsigned nof_rrc_ues = du_db.get_nof_rrc_ues(); // Get number of NGAP UEs unsigned nof_ngap_ues = ngap_entity->get_ngap_statistics_handler().get_nof_ues(); diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index d900232860..a0d612f7d5 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -230,6 +230,9 @@ class du_processor : public du_processor_cell_info_interface /// \brief Retrieve F1AP handler for the respective DU. virtual f1ap_cu& get_f1ap_handler() = 0; + /// \brief Retrieve RRC DU handler for the respective DU. + virtual rrc_du& get_rrc_du_handler() = 0; + virtual du_processor_mobility_handler& get_mobility_handler() = 0; /// \brief Get the F1AP message handler interface of the DU processor object. diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index a07ea33e07..59f9738179 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -44,6 +44,8 @@ class du_processor_impl : public du_processor, public du_metrics_handler, public f1ap_cu& get_f1ap_handler() override { return *f1ap; }; + rrc_du& get_rrc_du_handler() override { return *rrc; }; + size_t get_nof_ues() const { return ue_mng.get_nof_du_ues(cfg.du_index); }; // du_processor_mobility_manager_interface diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index 8561e8c5e7..eb5d819d4d 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -150,3 +150,12 @@ size_t du_processor_repository::get_nof_f1ap_ues() } return nof_ues; } + +size_t du_processor_repository::get_nof_rrc_ues() +{ + size_t nof_ues = 0; + for (auto& du : du_db) { + nof_ues += du.second.processor->get_rrc_du_handler().get_nof_ues(); + } + return nof_ues; +} diff --git a/lib/cu_cp/du_processor/du_processor_repository.h b/lib/cu_cp/du_processor/du_processor_repository.h index 72762f930e..7112104b4e 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.h +++ b/lib/cu_cp/du_processor/du_processor_repository.h @@ -63,6 +63,8 @@ class du_processor_repository : public du_repository_metrics_handler size_t get_nof_f1ap_ues(); + size_t get_nof_rrc_ues(); + /// \brief Adds a DU processor object to the CU-CP. /// \return The DU index of the added DU processor object. du_index_t add_du(std::unique_ptr f1ap_tx_pdu_notifier); From b4af5162c0f107d3bc5b1b087efd382349aaec8f Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 25 Jul 2024 09:38:32 +0200 Subject: [PATCH 027/407] cu_cp,rrc: remove cu-cp to rrc du adapter --- lib/cu_cp/adapters/cu_cp_adapters.h | 35 --------------- lib/cu_cp/adapters/du_processor_adapters.h | 11 ----- lib/cu_cp/cu_cp_impl.cpp | 21 ++------- lib/cu_cp/cu_cp_impl.h | 10 ----- lib/cu_cp/cu_cp_impl_interface.h | 43 ------------------- lib/cu_cp/du_processor/du_processor.h | 12 ------ lib/cu_cp/du_processor/du_processor_impl.cpp | 6 --- .../du_processor/du_processor_repository.cpp | 3 -- lib/cu_cp/routines/ue_removal_routine.cpp | 2 +- lib/cu_cp/routines/ue_removal_routine.h | 4 +- lib/rrc/rrc_du_impl.h | 4 +- .../du_processor_test_helpers.cpp | 8 ---- tests/unittests/cu_cp/test_helpers.h | 16 ------- 13 files changed, 9 insertions(+), 166 deletions(-) diff --git a/lib/cu_cp/adapters/cu_cp_adapters.h b/lib/cu_cp/adapters/cu_cp_adapters.h index 647e5d6cc2..d6ce8e051c 100644 --- a/lib/cu_cp/adapters/cu_cp_adapters.h +++ b/lib/cu_cp/adapters/cu_cp_adapters.h @@ -18,41 +18,6 @@ namespace srsran { namespace srs_cu_cp { -/// Adapter between CU-CP and RRC DU to request UE removal -class cu_cp_rrc_du_adapter : public cu_cp_rrc_ue_notifier, public cu_cp_rrc_du_statistics_notifier -{ -public: - cu_cp_rrc_du_adapter() = default; - - void connect_rrc_du(rrc_ue_handler& rrc_ue_hndlr_, rrc_du_statistics_handler& rrc_du_statistic_handler_) - { - rrc_ue_hndlr = &rrc_ue_hndlr_; - rrc_du_statistic_handler = &rrc_du_statistic_handler_; - } - - rrc_ue_interface* find_rrc_ue(ue_index_t ue_index) override - { - srsran_assert(rrc_ue_hndlr != nullptr, "RRC UE handler must not be nullptr"); - return rrc_ue_hndlr->find_ue(ue_index); - } - - void remove_ue(ue_index_t ue_index) override - { - srsran_assert(rrc_ue_hndlr != nullptr, "RRC UE handler must not be nullptr"); - rrc_ue_hndlr->remove_ue(ue_index); - } - - size_t get_nof_ues() const override - { - srsran_assert(rrc_du_statistic_handler != nullptr, "RRC DU statistics handler must not be nullptr"); - return rrc_du_statistic_handler->get_nof_ues(); - } - -private: - rrc_ue_handler* rrc_ue_hndlr = nullptr; - rrc_du_statistics_handler* rrc_du_statistic_handler = nullptr; -}; - /// Adapter between CU-CP and RRC UE, to transfer UE context e.g. for RRC Reestablishments class cu_cp_rrc_ue_adapter : public cu_cp_rrc_ue_context_transfer_notifier { diff --git a/lib/cu_cp/adapters/du_processor_adapters.h b/lib/cu_cp/adapters/du_processor_adapters.h index 3bac60a81c..f786619438 100644 --- a/lib/cu_cp/adapters/du_processor_adapters.h +++ b/lib/cu_cp/adapters/du_processor_adapters.h @@ -33,17 +33,6 @@ class du_processor_cu_cp_adapter : public du_processor_cu_cp_notifier ue_context_handler = &ue_context_handler_; } - void on_du_processor_created(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) override - { - srsran_assert(cu_cp_handler != nullptr, "CU-CP handler must not be nullptr"); - cu_cp_handler->handle_du_processor_creation( - du_index, f1ap_handler, f1ap_statistic_handler, rrc_handler, rrc_statistic_handler); - } - void on_rrc_ue_created(ue_index_t ue_index, rrc_ue_interface& rrc_ue) override { srsran_assert(cu_cp_handler != nullptr, "CU-CP handler must not be nullptr"); diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index e93fcfc281..b4936b4bbc 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -397,7 +397,7 @@ cu_cp_impl::handle_new_initial_context_setup_request(const ngap_init_context_set { cu_cp_ue* ue = ue_mng.find_du_ue(request.ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find UE", request.ue_index); - rrc_ue_interface* rrc_ue = rrc_du_adapters.at(ue->get_du_index()).find_rrc_ue(request.ue_index); + rrc_ue_interface* rrc_ue = du_db.get_du_processor(ue->get_du_index()).get_rrc_du_handler().find_ue(request.ue_index); srsran_assert(rrc_ue != nullptr, "ue={}: Could not find RRC UE", request.ue_index); return launch_async(request, @@ -621,7 +621,7 @@ async_task cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) } return launch_async(ue_index, - rrc_du_adapters.at(du_index), + du_db.get_du_processor(du_index).get_rrc_du_handler(), e1ap_removal_handler, du_db.get_du_processor(du_index).get_f1ap_handler(), ngap_entity->get_ngap_ue_context_removal_handler(), @@ -638,7 +638,7 @@ void cu_cp_impl::handle_pending_ue_task_cancellation(ue_index_t ue_index) ue_mng.get_task_sched().clear_pending_tasks(ue_index); // Cancel running transactions for the RRC UE. - rrc_ue_interface* rrc_ue = rrc_du_adapters.at(du_index).find_rrc_ue(ue_index); + rrc_ue_interface* rrc_ue = du_db.get_du_processor(du_index).get_rrc_du_handler().find_ue(ue_index); if (rrc_ue != nullptr) { rrc_ue->get_controller().stop(); } @@ -646,21 +646,6 @@ void cu_cp_impl::handle_pending_ue_task_cancellation(ue_index_t ue_index) // private -void cu_cp_impl::handle_du_processor_creation(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) -{ - rrc_du_adapters[du_index] = {}; - rrc_du_adapters.at(du_index).connect_rrc_du(rrc_handler, rrc_statistic_handler); -} - -void cu_cp_impl::handle_du_processor_removal(du_index_t du_index) -{ - rrc_du_adapters.erase(du_index); -} - void cu_cp_impl::handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& rrc_ue) { // Connect RRC UE to NGAP to RRC UE adapter diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index c1a89d9daa..8144b36f2a 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -136,13 +136,6 @@ class cu_cp_impl final : public cu_cp, private: // Handling of DU events. - void handle_du_processor_creation(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) override; - void handle_du_processor_removal(du_index_t du_index) override; - void handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& rrc_ue) override; byte_buffer handle_target_cell_sib1_required(du_index_t du_index, nr_cell_global_id_t cgi) override; @@ -173,9 +166,6 @@ class cu_cp_impl final : public cu_cp, cu_cp_common_task_scheduler common_task_sched; - // CU-CP to RRC DU adapters - std::map rrc_du_adapters; - // DU repository to Node Manager adapter. du_processor_cu_cp_connection_adapter conn_notifier; diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 231faaebcd..0d05cc5f26 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -117,55 +117,12 @@ class cu_cp_e1ap_event_handler : public cu_cp_task_scheduler_handler virtual void handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) = 0; }; -/// Methods used by CU-CP to fetch or request removal of an RRC UE from the RRC DU -class cu_cp_rrc_ue_notifier -{ -public: - virtual ~cu_cp_rrc_ue_notifier() = default; - - /// \brief Remove the context of a UE at the RRC DU. - /// \param[in] ue_index The index of the UE to fetch. - /// \returns The RRC UE interface if the UE exists, nullptr otherwise. - virtual rrc_ue_interface* find_rrc_ue(ue_index_t ue_index) = 0; - - /// \brief Remove the context of a UE at the RRC DU. - /// \param[in] ue_index The index of the UE to remove. - virtual void remove_ue(ue_index_t ue_index) = 0; -}; - -/// Methods used by CU-CP to request RRC DU statistics -class cu_cp_rrc_du_statistics_notifier -{ -public: - virtual ~cu_cp_rrc_du_statistics_notifier() = default; - - /// \brief Get the number of UEs registered at the RRC DU. - /// \return The number of UEs. - virtual size_t get_nof_ues() const = 0; -}; - /// Interface used to handle DU specific procedures class cu_cp_du_event_handler { public: virtual ~cu_cp_du_event_handler() = default; - /// \brief Handle about a successful F1AP and RRC creation. - /// \param[in] du_index The index of the DU the UE is connected to. - /// \param[in] f1ap_handler Handler to the F1AP to initiate the UE context removal. - /// \param[in] f1ap_statistic_handler Handler to the F1AP statistic interface. - /// \param[in] rrc_handler Handler to the RRC DU to initiate the RRC UE removal. - /// \param[in] rrc_statistic_handler Handler to the RRC DU statistic interface. - virtual void handle_du_processor_creation(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) = 0; - - /// \brief Handle DU removal event. - /// \param[in] du_index The index of the DU. - virtual void handle_du_processor_removal(du_index_t du_index) = 0; - /// \brief Handle a RRC UE creation notification from the DU processor. /// \param[in] ue_index The index of the UE. /// \param[in] rrc_ue The interface of the created RRC UE. diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index a0d612f7d5..5ac6d3f60f 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -187,18 +187,6 @@ class du_processor_cu_cp_notifier public: virtual ~du_processor_cu_cp_notifier() = default; - /// \brief Notifies about a successful F1AP and RRC creation. - /// \param[in] du_index The index of the DU the UE is connected to. - /// \param[in] f1ap_handler Handler to the F1AP to initiate the UE context removal. - /// \param[in] f1ap_statistic_handler Handler to the F1AP statistic interface. - /// \param[in] rrc_handler Handler to the RRC DU to initiate the RRC UE removal. - /// \param[in] rrc_statistic_handler Handler to the RRC DU statistic interface. - virtual void on_du_processor_created(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) = 0; - /// \brief Notifies about a successful RRC UE creation. /// \param[in] ue_index The index of the UE. /// \param[in] rrc_ue_msg_handler The created RRC UE. diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index 07e1af1576..36583e5d70 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -101,12 +101,6 @@ du_processor_impl::du_processor_impl(du_processor_config_t du_proc create_rrc_config(cfg.cu_cp_cfg), rrc_ue_nas_pdu_notifier, rrc_ue_ngap_ctrl_notifier, rrc_du_cu_cp_notifier}; rrc = create_rrc_du(du_creation_req); rrc_du_adapter.connect_rrc_du(rrc->get_rrc_du_cell_manager(), rrc->get_rrc_du_ue_repository()); - - cu_cp_notifier.on_du_processor_created(cfg.du_index, - f1ap->get_f1ap_ue_context_removal_handler(), - f1ap->get_f1ap_statistics_handler(), - rrc->get_rrc_ue_handler(), - rrc->get_rrc_du_statistics_handler()); } du_setup_result du_processor_impl::handle_du_setup_request(const du_setup_request& request) diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index eb5d819d4d..a2932f52ed 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -72,9 +72,6 @@ async_task du_processor_repository::remove_du(du_index_t du_index) // Stop DU activity, eliminating pending transactions for the DU and respective UEs. CORO_AWAIT(du_db.find(du_index)->second.processor->get_f1ap_handler().stop()); - // Notify the CU-CP about the removal of the DU processor. - cfg.cu_cp_du_handler.handle_du_processor_removal(du_index); - // Remove DU du_db.erase(du_index); logger.info("Removed DU {}", du_index); diff --git a/lib/cu_cp/routines/ue_removal_routine.cpp b/lib/cu_cp/routines/ue_removal_routine.cpp index e6516ca409..c6fb3f9731 100644 --- a/lib/cu_cp/routines/ue_removal_routine.cpp +++ b/lib/cu_cp/routines/ue_removal_routine.cpp @@ -14,7 +14,7 @@ using namespace srsran; using namespace srsran::srs_cu_cp; ue_removal_routine::ue_removal_routine(ue_index_t ue_index_, - cu_cp_rrc_ue_notifier& rrc_du_notifier_, + rrc_ue_handler& rrc_du_notifier_, e1ap_bearer_context_removal_handler* e1ap_removal_handler_, f1ap_ue_context_removal_handler& f1ap_removal_handler_, ngap_ue_context_removal_handler& ngap_removal_handler_, diff --git a/lib/cu_cp/routines/ue_removal_routine.h b/lib/cu_cp/routines/ue_removal_routine.h index 55fa7f3e48..619062acdf 100644 --- a/lib/cu_cp/routines/ue_removal_routine.h +++ b/lib/cu_cp/routines/ue_removal_routine.h @@ -22,7 +22,7 @@ class ue_removal_routine { public: ue_removal_routine(ue_index_t ue_index_, - cu_cp_rrc_ue_notifier& rrc_du_notifier_, + rrc_ue_handler& rrc_du_notifier_, e1ap_bearer_context_removal_handler* e1ap_removal_handler_, f1ap_ue_context_removal_handler& f1ap_removal_handler_, ngap_ue_context_removal_handler& ngap_removal_handler_, @@ -35,7 +35,7 @@ class ue_removal_routine private: const ue_index_t ue_index; - cu_cp_rrc_ue_notifier& rrc_du_notifier; // to trigger removal of the UE at the RRC + rrc_ue_handler& rrc_du_notifier; // to trigger removal of the UE at the RRC e1ap_bearer_context_removal_handler* e1ap_removal_handler; // to trigger removal of the UE at the E1AP f1ap_ue_context_removal_handler& f1ap_removal_handler; // to trigger removal of the UE at the F1AP ngap_ue_context_removal_handler& ngap_removal_handler; // to trigger removal of the UE at the NGAP diff --git a/lib/rrc/rrc_du_impl.h b/lib/rrc/rrc_du_impl.h index ef5ae7d108..76ea42cc3f 100644 --- a/lib/rrc/rrc_du_impl.h +++ b/lib/rrc/rrc_du_impl.h @@ -41,7 +41,9 @@ class rrc_du_impl : public rrc_du // rrc_ue_handler rrc_ue_interface* find_ue(ue_index_t ue_index) override { - srsran_assert(ue_db.find(ue_index) != ue_db.end(), "UE not found"); + if (ue_db.find(ue_index) == ue_db.end()) { + return nullptr; + } return ue_db.at(ue_index).get(); } void remove_ue(ue_index_t ue_index) override; diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp index bc30b78554..369b3dea93 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp @@ -76,14 +76,6 @@ struct dummy_cu_cp_du_event_handler : public cu_cp_du_event_handler { public: dummy_cu_cp_du_event_handler(ue_manager& ue_mng_) : ue_mng(ue_mng_) {} - void handle_du_processor_creation(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) override - { - } - void handle_du_processor_removal(du_index_t du_index) override {} void handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& rrc_ue) override { ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp(rrc_ue_handler, diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index 51374324c5..fe47eea456 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -45,22 +45,6 @@ struct dummy_du_processor_cu_cp_notifier : public du_processor_cu_cp_notifier { ue_removal_handler = ue_removal_handler_; } - void on_du_processor_created(du_index_t du_index, - f1ap_ue_context_removal_handler& f1ap_handler, - f1ap_statistics_handler& f1ap_statistic_handler, - rrc_ue_handler& rrc_handler, - rrc_du_statistics_handler& rrc_statistic_handler) override - { - logger.info("du={}: Received a DU Processor creation notification", du_index); - - if (cu_cp_handler != nullptr) { - cu_cp_handler->handle_du_processor_creation( - du_index, f1ap_handler, f1ap_statistic_handler, rrc_handler, rrc_statistic_handler); - } else { - rrc_removal_handler = &rrc_handler; - } - } - void on_rrc_ue_created(ue_index_t ue_index, rrc_ue_interface& rrc_ue) override { logger.info("ue={}: Received a RRC UE creation notification", ue_index); From 1d7a10504c109ed1964e3f86570d4fb40be764d8 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 25 Jul 2024 09:53:26 +0200 Subject: [PATCH 028/407] cu_cp: change du processor repository function to remove duplicate --- .../du_processor/du_processor_repository.cpp | 18 ++++++++++-------- .../du_processor/du_processor_repository.h | 15 +++++++++------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index a2932f52ed..1d76580df0 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -92,13 +92,6 @@ du_index_t du_processor_repository::get_next_du_index() return du_index_t::invalid; } -du_processor& du_processor_repository::find_du(du_index_t du_index) -{ - srsran_assert(du_index != du_index_t::invalid, "Invalid du_index={}", du_index); - srsran_assert(du_db.find(du_index) != du_db.end(), "DU not found du_index={}", du_index); - return *du_db.at(du_index).processor; -} - du_index_t du_processor_repository::find_du(pci_t pci) { du_index_t index = du_index_t::invalid; @@ -123,6 +116,14 @@ du_index_t du_processor_repository::find_du(const nr_cell_global_id_t& cgi) return index; } +du_processor* du_processor_repository::find_du_processor(du_index_t du_index) +{ + if (du_db.find(du_index) == du_db.end()) { + return nullptr; + } + return du_db.at(du_index).processor.get(); +} + du_processor& du_processor_repository::get_du_processor(du_index_t du_index) { srsran_assert(du_index != du_index_t::invalid, "Invalid du_index={}", du_index); @@ -133,7 +134,8 @@ du_processor& du_processor_repository::get_du_processor(du_index_t du_index) std::vector du_processor_repository::handle_du_metrics_report_request() const { std::vector du_reports; - for (auto& du : du_db) { + du_reports.reserve(du_db.size()); + for (const auto& du : du_db) { du_reports.emplace_back(du.second.processor->get_metrics_handler().handle_du_metrics_report_request()); } return du_reports; diff --git a/lib/cu_cp/du_processor/du_processor_repository.h b/lib/cu_cp/du_processor/du_processor_repository.h index 7112104b4e..9ec59a143b 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.h +++ b/lib/cu_cp/du_processor/du_processor_repository.h @@ -57,6 +57,14 @@ class du_processor_repository : public du_repository_metrics_handler /// \return The index of the DU serving the given CGI. du_index_t find_du(const nr_cell_global_id_t& cgi); + /// \brief Find a DU object. + /// \param[in] du_index The index of the DU processor object. + /// \return A pointer to the DU processor object, nullptr if the DU processor object is not found. + du_processor* find_du_processor(du_index_t du_index); + + /// \brief Find a DU object. + /// \param[in] du_index The index of the DU processor object. + /// \return The DU processor object. du_processor& get_du_processor(du_index_t du_index); std::vector handle_du_metrics_report_request() const override; @@ -72,7 +80,7 @@ class du_processor_repository : public du_repository_metrics_handler /// \brief Launches task that removes the specified DU processor object from the CU-CP. /// \param[in] du_index The index of the DU processor to delete. /// \return asynchronous task for the DU processor removal. - async_task remove_du(du_index_t du_idx); + async_task remove_du(du_index_t du_index); /// Number of DUs managed by the CU-CP. size_t get_nof_dus() const { return du_db.size(); } @@ -88,11 +96,6 @@ class du_processor_repository : public du_repository_metrics_handler std::unique_ptr f1ap_tx_pdu_notifier; }; - /// \brief Find a DU object. - /// \param[in] du_index The index of the DU processor object. - /// \return The DU processor object. - du_processor& find_du(du_index_t du_index); - /// \brief Get the next available index from the DU processor database. /// \return The DU index. du_index_t get_next_du_index(); From ee65b39ba86e8a3c10f0069e655e85c03688fb73 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 25 Jul 2024 10:03:51 +0200 Subject: [PATCH 029/407] cu_cp,rrc: remove cu-cp to rrc ue adapter --- lib/cu_cp/adapters/cu_cp_adapters.h | 40 -------------------------- lib/cu_cp/cu_cp_impl.cpp | 27 +++++++++++++---- lib/cu_cp/cu_cp_impl.h | 1 - lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 5 ---- lib/cu_cp/ue_manager/ue_manager_impl.h | 10 ------- 5 files changed, 21 insertions(+), 62 deletions(-) delete mode 100644 lib/cu_cp/adapters/cu_cp_adapters.h diff --git a/lib/cu_cp/adapters/cu_cp_adapters.h b/lib/cu_cp/adapters/cu_cp_adapters.h deleted file mode 100644 index d6ce8e051c..0000000000 --- a/lib/cu_cp/adapters/cu_cp_adapters.h +++ /dev/null @@ -1,40 +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 "../cu_cp_impl_interface.h" -#include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" -#include "srsran/f1ap/cu_cp/f1ap_cu.h" -#include "srsran/ngap/ngap.h" - -namespace srsran { -namespace srs_cu_cp { - -/// Adapter between CU-CP and RRC UE, to transfer UE context e.g. for RRC Reestablishments -class cu_cp_rrc_ue_adapter : public cu_cp_rrc_ue_context_transfer_notifier -{ -public: - cu_cp_rrc_ue_adapter() = default; - - void connect_rrc_ue(rrc_ue_context_handler& rrc_context_handler_) { rrc_context_handler = &rrc_context_handler_; } - - rrc_ue_reestablishment_context_response on_rrc_ue_context_transfer() override - { - srsran_assert(rrc_context_handler != nullptr, "RRC UE handler must not be nullptr"); - return rrc_context_handler->get_context(); - } - -private: - rrc_ue_context_handler* rrc_context_handler = nullptr; -}; - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index b4936b4bbc..89f7d211e6 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -206,21 +206,37 @@ cu_cp_impl::handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, return reest_context; } + auto* const old_ue = ue_mng.find_du_ue(old_ue_index); + // check if a DRB and SRB2 were setup - if (ue_mng.find_du_ue(old_ue_index)->get_up_resource_manager().get_drbs().empty()) { - logger.debug("ue={}: No DRB setup for this UE - rejecting RRC reestablishment.", old_ue_index); + if (old_ue->get_up_resource_manager().get_drbs().empty()) { + logger.debug("ue={}: No DRB setup for this UE - rejecting RRC reestablishment", old_ue_index); reest_context.ue_index = old_ue_index; return reest_context; } - auto srbs = ue_mng.find_du_ue(old_ue_index)->get_rrc_ue_srb_notifier().get_srbs(); + + auto srbs = old_ue->get_rrc_ue_srb_notifier().get_srbs(); if (std::find(srbs.begin(), srbs.end(), srb_id_t::srb2) == srbs.end()) { - logger.debug("ue={}: SRB2 not setup for this UE - rejecting RRC reestablishment.", old_ue_index); + logger.debug("ue={}: SRB2 not setup for this UE - rejecting RRC reestablishment", old_ue_index); + reest_context.ue_index = old_ue_index; + return reest_context; + } + + if (du_db.find_du_processor(old_ue->get_du_index()) == nullptr) { + logger.debug("ue={}: DU processor not found for this UE - rejecting RRC reestablishment", old_ue_index); + reest_context.ue_index = old_ue_index; + return reest_context; + } + + if (du_db.find_du_processor(old_ue->get_du_index())->get_rrc_du_handler().find_ue(old_ue_index) == nullptr) { + logger.debug("ue={}: RRC UE not found for this UE - rejecting RRC reestablishment", old_ue_index); reest_context.ue_index = old_ue_index; return reest_context; } // Get RRC Reestablishment UE Context from old UE - reest_context = ue_mng.get_cu_cp_rrc_ue_adapter(old_ue_index).on_rrc_ue_context_transfer(); + reest_context = + du_db.find_du_processor(old_ue->get_du_index())->get_rrc_du_handler().find_ue(old_ue_index)->get_context(); reest_context.old_ue_fully_attached = true; reest_context.ue_index = old_ue_index; @@ -654,7 +670,6 @@ void cu_cp_impl::handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& r rrc_ue.get_rrc_ue_handover_preparation_handler()); // Connect cu-cp to rrc ue adapters - ue_mng.get_cu_cp_rrc_ue_adapter(ue_index).connect_rrc_ue(rrc_ue.get_rrc_ue_context_handler()); ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp(get_cu_cp_rrc_ue_interface(), get_cu_cp_ue_removal_handler(), *controller, diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 8144b36f2a..8b3f1ec1fb 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -11,7 +11,6 @@ #pragma once #include "adapters/cell_meas_manager_adapters.h" -#include "adapters/cu_cp_adapters.h" #include "adapters/du_processor_adapters.h" #include "adapters/e1ap_adapters.h" #include "adapters/mobility_manager_adapters.h" diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index 9eeee1ca5e..c774a84bdb 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -10,7 +10,6 @@ #pragma once -#include "../adapters/cu_cp_adapters.h" #include "../adapters/ngap_adapters.h" #include "../adapters/rrc_ue_adapters.h" #include "../cell_meas_manager/measurement_context.h" @@ -131,9 +130,6 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \brief Get the NGAP to RRC UE adapter of the UE. ngap_rrc_ue_adapter& get_ngap_rrc_ue_adapter() { return ngap_rrc_ue_ev_notifier; } - /// \brief Get the CU-CP to RRC UE adapter of the UE. - cu_cp_rrc_ue_adapter& get_cu_cp_rrc_ue_adapter() { return cu_cp_rrc_ue_ev_notifier; } - /// \brief Get the RRC to CU-CP adapter of the UE. rrc_ue_cu_cp_adapter& get_rrc_ue_cu_cp_adapter() { return rrc_ue_cu_cp_ev_notifier; } @@ -158,7 +154,6 @@ class cu_cp_ue : public cu_cp_ue_impl_interface ngap_rrc_ue_adapter ngap_rrc_ue_ev_notifier; // cu-cp ue context - cu_cp_rrc_ue_adapter cu_cp_rrc_ue_ev_notifier; rrc_ue_cu_cp_adapter rrc_ue_cu_cp_ev_notifier; cell_meas_manager_ue_context meas_context; }; diff --git a/lib/cu_cp/ue_manager/ue_manager_impl.h b/lib/cu_cp/ue_manager/ue_manager_impl.h index 97f7ee7b2a..deb7bd67a4 100644 --- a/lib/cu_cp/ue_manager/ue_manager_impl.h +++ b/lib/cu_cp/ue_manager/ue_manager_impl.h @@ -10,7 +10,6 @@ #pragma once -#include "../adapters/cu_cp_adapters.h" #include "../adapters/ngap_adapters.h" #include "../adapters/rrc_ue_adapters.h" #include "../cell_meas_manager/measurement_context.h" @@ -110,15 +109,6 @@ class ue_manager : public ue_metrics_handler return ues.at(ue_index).get_ngap_rrc_ue_adapter(); } - /// \brief Get the CU-CP to RRC UE adapter of the UE. - cu_cp_rrc_ue_adapter& get_cu_cp_rrc_ue_adapter(ue_index_t ue_index) - { - srsran_assert(ue_index != ue_index_t::invalid, "Invalid ue_index={}", ue_index); - srsran_assert(ues.find(ue_index) != ues.end(), "UE with ue_index={} does not exist", ue_index); - - return ues.at(ue_index).get_cu_cp_rrc_ue_adapter(); - } - rrc_ue_cu_cp_adapter& get_rrc_ue_cu_cp_adapter(ue_index_t ue_index) { srsran_assert(ue_index != ue_index_t::invalid, "Invalid ue_index={}", ue_index); From 536f951b828b729f47d463ae06f14b4bc3129500 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 26 Jul 2024 16:17:20 +0200 Subject: [PATCH 030/407] cu_cp: store rrc ue in the cu-cp ue --- lib/cu_cp/cu_cp_impl.cpp | 27 +++++++++++++------------- lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp | 7 +++++++ lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 9 +++++++++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 89f7d211e6..e3ab23041a 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -207,6 +207,10 @@ cu_cp_impl::handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, } auto* const old_ue = ue_mng.find_du_ue(old_ue_index); + if (old_ue == nullptr) { + logger.debug("ue={}: Could not find UE", old_ue_index); + return reest_context; + } // check if a DRB and SRB2 were setup if (old_ue->get_up_resource_manager().get_drbs().empty()) { @@ -222,21 +226,15 @@ cu_cp_impl::handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, return reest_context; } - if (du_db.find_du_processor(old_ue->get_du_index()) == nullptr) { - logger.debug("ue={}: DU processor not found for this UE - rejecting RRC reestablishment", old_ue_index); - reest_context.ue_index = old_ue_index; - return reest_context; - } - - if (du_db.find_du_processor(old_ue->get_du_index())->get_rrc_du_handler().find_ue(old_ue_index) == nullptr) { + auto* rrc_ue = old_ue->get_rrc_ue(); + if (rrc_ue == nullptr) { logger.debug("ue={}: RRC UE not found for this UE - rejecting RRC reestablishment", old_ue_index); reest_context.ue_index = old_ue_index; return reest_context; } // Get RRC Reestablishment UE Context from old UE - reest_context = - du_db.find_du_processor(old_ue->get_du_index())->get_rrc_du_handler().find_ue(old_ue_index)->get_context(); + reest_context = rrc_ue->get_context(); reest_context.old_ue_fully_attached = true; reest_context.ue_index = old_ue_index; @@ -413,7 +411,7 @@ cu_cp_impl::handle_new_initial_context_setup_request(const ngap_init_context_set { cu_cp_ue* ue = ue_mng.find_du_ue(request.ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find UE", request.ue_index); - rrc_ue_interface* rrc_ue = du_db.get_du_processor(ue->get_du_index()).get_rrc_du_handler().find_ue(request.ue_index); + rrc_ue_interface* rrc_ue = ue->get_rrc_ue(); srsran_assert(rrc_ue != nullptr, "ue={}: Could not find RRC UE", request.ue_index); return launch_async(request, @@ -648,13 +646,12 @@ async_task cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) void cu_cp_impl::handle_pending_ue_task_cancellation(ue_index_t ue_index) { srsran_assert(ue_mng.find_du_ue(ue_index) != nullptr, "ue={}: Could not find DU UE", ue_index); - du_index_t du_index = ue_mng.find_du_ue(ue_index)->get_du_index(); // Clear all enqueued tasks for this UE. ue_mng.get_task_sched().clear_pending_tasks(ue_index); // Cancel running transactions for the RRC UE. - rrc_ue_interface* rrc_ue = du_db.get_du_processor(du_index).get_rrc_du_handler().find_ue(ue_index); + rrc_ue_interface* rrc_ue = ue_mng.find_du_ue(ue_index)->get_rrc_ue(); if (rrc_ue != nullptr) { rrc_ue->get_controller().stop(); } @@ -664,6 +661,10 @@ void cu_cp_impl::handle_pending_ue_task_cancellation(ue_index_t ue_index) void cu_cp_impl::handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& rrc_ue) { + // Store the RRC UE in the UE manager + auto* ue = ue_mng.find_ue(ue_index); + ue->set_rrc_ue(rrc_ue); + // Connect RRC UE to NGAP to RRC UE adapter ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(rrc_ue.get_rrc_dl_nas_message_handler(), rrc_ue.get_rrc_ue_radio_access_capability_handler(), @@ -673,7 +674,7 @@ void cu_cp_impl::handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& r ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp(get_cu_cp_rrc_ue_interface(), get_cu_cp_ue_removal_handler(), *controller, - ue_mng.find_ue(ue_index)->get_up_resource_manager(), + ue->get_up_resource_manager(), get_cu_cp_measurement_handler()); } diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp index 0905adc1a6..62aff68a69 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp @@ -90,6 +90,13 @@ void cu_cp_ue::set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier = &rrc_ue_srb_notifier_; } +/// \brief Set the RRC UE of the UE. +/// \param[in] rrc_ue_ RRC UE of the UE. +void cu_cp_ue::set_rrc_ue(rrc_ue_interface& rrc_ue_) +{ + rrc_ue = &rrc_ue_; +} + /// \brief Get the RRC UE PDU notifier of the UE. ngap_rrc_ue_pdu_notifier& cu_cp_ue::get_rrc_ue_pdu_notifier() { diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index c774a84bdb..be9a1a7324 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -104,6 +104,9 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. void set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_); + /// \brief Set the RRC UE of the UE. + void set_rrc_ue(rrc_ue_interface& rrc_ue_); + /// \brief Get the RRC UE PDU notifier of the UE. ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() override; @@ -133,6 +136,9 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \brief Get the RRC to CU-CP adapter of the UE. rrc_ue_cu_cp_adapter& get_rrc_ue_cu_cp_adapter() { return rrc_ue_cu_cp_ev_notifier; } + /// \brief Get the RRC UE of the UE. + rrc_ue_interface* get_rrc_ue() { return rrc_ue; } + private: // common context ue_index_t ue_index = ue_index_t::invalid; @@ -149,6 +155,9 @@ class cu_cp_ue : public cu_cp_ue_impl_interface du_processor_rrc_ue_control_message_notifier* rrc_ue_notifier = nullptr; du_processor_rrc_ue_srb_control_notifier* rrc_ue_srb_notifier = nullptr; + // rrc ue + rrc_ue_interface* rrc_ue = nullptr; + // ngap ue context ngap_cu_cp_ue_adapter ngap_cu_cp_ue_ev_notifier; ngap_rrc_ue_adapter ngap_rrc_ue_ev_notifier; From 3827c496969f1f0ff6ffa857a9cb73d483b6cad2 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 22 Jul 2024 18:13:03 +0200 Subject: [PATCH 031/407] cu_cp,rrc: remove unused duplicate ue capabilities --- include/srsran/rrc/rrc_ue.h | 13 +++++++------ .../ue/procedures/rrc_reestablishment_procedure.cpp | 4 ++-- .../rrc_ue_capability_transfer_procedure.cpp | 6 ++---- lib/rrc/ue/rrc_ue_context.h | 7 +++---- lib/rrc/ue/rrc_ue_message_handlers.cpp | 5 +++-- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 0b404847b6..aee37773fb 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -14,6 +14,7 @@ #include "srsran/adt/byte_buffer.h" #include "srsran/adt/static_vector.h" #include "srsran/asn1/rrc_nr/ue_cap.h" +#include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/cu_cp/cu_cp_ue_messages.h" #include "srsran/ran/rnti.h" @@ -316,12 +317,12 @@ class rrc_ue_cu_cp_ue_notifier /// Struct containing all information needed from the old RRC UE for Reestablishment. struct rrc_ue_reestablishment_context_response { - ue_index_t ue_index = ue_index_t::invalid; - security::security_context sec_context; - std::optional capabilities; - up_context up_ctx; - bool old_ue_fully_attached = false; - bool reestablishment_ongoing = false; + ue_index_t ue_index = ue_index_t::invalid; + security::security_context sec_context; + std::optional capabilities_list; + up_context up_ctx; + bool old_ue_fully_attached = false; + bool reestablishment_ongoing = false; }; /// Interface to notify about UE context updates. diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp index ea31ec4bb9..65781fdfc4 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp @@ -225,8 +225,8 @@ bool rrc_reestablishment_procedure::verify_security_context() void rrc_reestablishment_procedure::transfer_reestablishment_context_and_update_keys() { // store capabilities if available - if (old_ue_reest_context.capabilities.has_value()) { - context.capabilities = old_ue_reest_context.capabilities.value(); + if (old_ue_reest_context.capabilities_list.has_value()) { + context.capabilities_list = old_ue_reest_context.capabilities_list.value(); } // Transfer UP context from old UE diff --git a/lib/rrc/ue/procedures/rrc_ue_capability_transfer_procedure.cpp b/lib/rrc/ue/procedures/rrc_ue_capability_transfer_procedure.cpp index 9b8e2444f1..68236ce165 100644 --- a/lib/rrc/ue/procedures/rrc_ue_capability_transfer_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_ue_capability_transfer_procedure.cpp @@ -28,7 +28,7 @@ void rrc_ue_capability_transfer_procedure::operator()(coro_context meas_cfg; std::optional five_g_s_tmsi; std::variant> - setup_ue_id; ///< this is either a random value or the 5G-S-TMSI-PART1 - asn1::rrc_nr::establishment_cause_opts connection_cause; - std::map srbs; - std::optional capabilities; + setup_ue_id; ///< this is either a random value or the 5G-S-TMSI-PART1 + asn1::rrc_nr::establishment_cause_opts connection_cause; + std::map srbs; std::optional capabilities_list; std::optional transfer_context; // Context of old UE when created through mobility. bool reestablishment_ongoing = false; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index e0bc24a1c6..b413f35146 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -16,6 +16,7 @@ #include "rrc_ue_helpers.h" #include "rrc_ue_impl.h" #include "ue/rrc_measurement_types_asn1_converters.h" +#include "srsran/asn1/asn1_utils.h" #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" #include "srsran/asn1/rrc_nr/ul_ccch_msg.h" #include "srsran/ran/lcid.h" @@ -535,8 +536,8 @@ rrc_ue_reestablishment_context_response rrc_ue_impl::get_context() rrc_ue_reestablishment_context_response rrc_reest_context; rrc_reest_context.sec_context = cu_cp_ue_notifier.get_security_context(); - if (context.capabilities.has_value()) { - rrc_reest_context.capabilities = context.capabilities.value(); + if (context.capabilities_list.has_value()) { + rrc_reest_context.capabilities_list = context.capabilities_list.value(); } rrc_reest_context.up_ctx = cu_cp_notifier.on_up_context_required(); From 4e51aacb2b563a548293584c977a3a03afd52ab1 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 09:14:41 +0200 Subject: [PATCH 032/407] cu_cp,rrc: store ue capabilities from initial context setup request --- include/srsran/rrc/rrc_ue.h | 5 +++ .../initial_context_setup_routine.cpp | 8 +++-- .../routines/initial_context_setup_routine.h | 1 + lib/rrc/ue/rrc_ue_impl.h | 1 + lib/rrc/ue/rrc_ue_message_handlers.cpp | 34 +++++++++++++++++++ 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index aee37773fb..0d6edddca3 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -224,6 +224,11 @@ class rrc_ue_control_message_handler /// \returns True if the RRC Reconfiguration Complete was received, false otherwise. virtual async_task handle_handover_reconfiguration_complete_expected(uint8_t transaction_id) = 0; + /// \brief Store UE capabilities received from the NGAP. + /// \param[in] ue_capabilities The UE capabilities. + /// \returns True if the UE capabilities were stored successfully, false otherwise. + virtual bool store_ue_capabilities(byte_buffer ue_capabilities) = 0; + /// \brief Initiate the UE capability transfer procedure. virtual async_task handle_rrc_ue_capability_transfer_request(const rrc_ue_capability_transfer_request& msg) = 0; diff --git a/lib/cu_cp/routines/initial_context_setup_routine.cpp b/lib/cu_cp/routines/initial_context_setup_routine.cpp index bb14e79270..16d5a1b9b4 100644 --- a/lib/cu_cp/routines/initial_context_setup_routine.cpp +++ b/lib/cu_cp/routines/initial_context_setup_routine.cpp @@ -87,7 +87,9 @@ void initial_context_setup_routine::operator()( } // Start UE Capability Enquiry Procedure - { + if (request.ue_radio_cap.has_value()) { + ue_cap_store_result = rrc_ue.store_ue_capabilities(std::move(request.ue_radio_cap.value())); + } else { CORO_AWAIT_VALUE(ue_capability_transfer_result, rrc_ue.handle_rrc_ue_capability_transfer_request(ue_capability_transfer_request)); @@ -132,7 +134,9 @@ void initial_context_setup_routine::operator()( } // Schedule transmission of UE Radio Capability Info Indication - send_ue_radio_capability_info_indication(); + if (!ue_cap_store_result) { + send_ue_radio_capability_info_indication(); + } logger.info("ue={}: \"{}\" finished successfully", request.ue_index, name()); CORO_RETURN(resp_msg); diff --git a/lib/cu_cp/routines/initial_context_setup_routine.h b/lib/cu_cp/routines/initial_context_setup_routine.h index d8b257ed68..ae9a9dc0b1 100644 --- a/lib/cu_cp/routines/initial_context_setup_routine.h +++ b/lib/cu_cp/routines/initial_context_setup_routine.h @@ -56,6 +56,7 @@ class initial_context_setup_routine rrc_reconfiguration_procedure_request rrc_reconfig_args; // (sub-)routine results + bool ue_cap_store_result = false; f1ap_ue_context_setup_response ue_context_setup_response; bool ue_capability_transfer_result = false; // to query the UE capabilities cu_cp_pdu_session_resource_setup_response pdu_session_setup_response; diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index ecf2095e48..86c47c558c 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -70,6 +70,7 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller rrc_ue_handover_reconfiguration_context get_rrc_ue_handover_reconfiguration_context(const rrc_reconfiguration_procedure_request& request) override; async_task handle_handover_reconfiguration_complete_expected(uint8_t transaction_id) override; + bool store_ue_capabilities(byte_buffer ue_capabilities) override; async_task handle_rrc_ue_capability_transfer_request(const rrc_ue_capability_transfer_request& msg) override; rrc_ue_release_context get_rrc_ue_release_context(bool requires_rrc_message) override; rrc_ue_transfer_context get_transfer_context() override; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index b413f35146..34cf7904fb 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -442,6 +442,40 @@ async_task rrc_ue_impl::handle_handover_reconfiguration_complete_expected( }); } +bool rrc_ue_impl::store_ue_capabilities(byte_buffer ue_capabilities) +{ + // Unpack UE Capabilities + asn1::rrc_nr::ue_radio_access_cap_info_s ue_radio_access_cap_info; + asn1::cbit_ref bref({ue_capabilities.begin(), ue_capabilities.end()}); + + if (ue_radio_access_cap_info.unpack(bref) != asn1::SRSASN_SUCCESS) { + logger.log_error("Couldn't unpack UE Radio Access Capability Info RRC container"); + return false; + } + + asn1::rrc_nr::ue_cap_rat_container_list_l ue_cap_rat_container_list; + asn1::cbit_ref bref2( + {ue_radio_access_cap_info.crit_exts.c1().ue_radio_access_cap_info().ue_radio_access_cap_info.begin(), + ue_radio_access_cap_info.crit_exts.c1().ue_radio_access_cap_info().ue_radio_access_cap_info.end()}); + if (asn1::unpack_dyn_seq_of(ue_cap_rat_container_list, bref2, 0, 8) != asn1::SRSASN_SUCCESS) { + logger.log_error("Couldn't unpack UE Capability RAT Container List RRC container"); + return false; + } + + context.capabilities_list.emplace(ue_cap_rat_container_list); + + if (logger.get_basic_logger().debug.enabled()) { + logger.log_debug("UE Capabilities:\n"); + asn1::json_writer json_writer; + for (const auto& rat_container : ue_cap_rat_container_list) { + rat_container.to_json(json_writer); + logger.log_debug("{}\n", json_writer.to_string().c_str()); + } + } + + return true; +} + async_task rrc_ue_impl::handle_rrc_ue_capability_transfer_request(const rrc_ue_capability_transfer_request& msg) { // Launch RRC UE capability transfer procedure From 6cad2d5d2acbd90dbf29e5903752e241d961fe81 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 09:30:40 +0200 Subject: [PATCH 033/407] cu_cp: add unittest for initial context setup request with ue capabilities --- .../cu_cp_initial_context_setup_test.cpp | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp index 1e955c5930..f0027f9593 100644 --- a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp @@ -17,6 +17,7 @@ #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" +#include "srsran/asn1/ngap/ngap_pdu_contents.h" #include "srsran/e1ap/common/e1ap_types.h" #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/ngap/ngap_message.h" @@ -54,7 +55,7 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : EXPECT_NE(ue_ctx, nullptr); } - void send_initial_context_setup_request(bool with_pdu_sessions = false) + void send_initial_context_setup_request(bool with_pdu_sessions = false, bool with_ue_capabilities = false) { srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); @@ -69,6 +70,13 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : generate_valid_initial_context_setup_request_message(ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value()); } + if (with_ue_capabilities) { + init_ctxt_setup_req.pdu.init_msg().value.init_context_setup_request()->ue_radio_cap_present = true; + init_ctxt_setup_req.pdu.init_msg().value.init_context_setup_request()->ue_radio_cap.from_string( + "02c0856c18033a047465a025f800082a00241260e000307838031bff001300098a00d00000001c058d006007a071e439f0000240400e" + "03000000001001be00000000000002074000000000005038a12007000f00000004008010"); + } + get_amf().push_tx_pdu(init_ctxt_setup_req); } @@ -133,6 +141,26 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : "Invalid init ctxt setup"); } + void send_security_mode_complete_and_await_registration_accept_and_initial_context_setup_response() + { + // Inject Security Mode Complete + f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( + ue_ctx->cu_ue_id.value(), du_ue_id, srb_id_t::srb1, make_byte_buffer("00032a00fd5ec7ff").value()); + get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); + + // Wait for DL RRC Message Transfer (containing NAS Registration Accept) + bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); + report_fatal_error_if_not(result, "Failed to receive DL RRC Message, containing NAS Registration Accept"); + report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), + "Invalid DL RRC Message Transfer"); + + // Wait for Initial Context Setup Response + result = this->wait_for_ngap_tx_pdu(ngap_pdu); + report_fatal_error_if_not(result, "Failed to receive Initial Context Setup Response"); + report_fatal_error_if_not(test_helpers::is_valid_initial_context_setup_response(ngap_pdu), + "Invalid init ctxt setup"); + } + void send_ue_capability_info_and_handle_pdu_session_resource_setup_request() { // Inject UL RRC Message Transfer (containing UE Capability Info) @@ -328,4 +356,17 @@ TEST_F(cu_cp_initial_context_setup_test, // Wait for UE Capability Info Indication await_ue_capability_info_indication(); -} \ No newline at end of file +} + +TEST_F(cu_cp_initial_context_setup_test, + when_initial_context_setup_contains_ue_capabilities_then_initial_context_setup_succeeds) +{ + // Inject Initial Context Setup Request with UE capabilities + send_initial_context_setup_request(false, true); + + // Wait for F1AP UE Context Setup Request (containing Security Mode Command) and inject UE Context Setup Response + send_ue_context_setup_request_and_await_response(); + + // Inject Security Mode Complete and await DL RRC Message (Registration Accept) and Initial Context Setup Response + send_security_mode_complete_and_await_registration_accept_and_initial_context_setup_response(); +} From 2d1b068aaf47412766c600e3a4a03b5ce674a907 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 26 Jul 2024 15:27:55 +0200 Subject: [PATCH 034/407] cu_cp: fail initial context setup routine if unpacking of ue capabilites from request failed --- .../initial_context_setup_routine.cpp | 27 ++++++++++++------- .../routines/initial_context_setup_routine.h | 3 +-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/cu_cp/routines/initial_context_setup_routine.cpp b/lib/cu_cp/routines/initial_context_setup_routine.cpp index 16d5a1b9b4..c609ec7cdd 100644 --- a/lib/cu_cp/routines/initial_context_setup_routine.cpp +++ b/lib/cu_cp/routines/initial_context_setup_routine.cpp @@ -10,6 +10,8 @@ #include "initial_context_setup_routine.h" #include "pdu_session_routine_helpers.h" +#include "srsran/ran/cause/common.h" +#include "srsran/ran/cause/f1ap_cause_converters.h" #include "srsran/ran/cause/ngap_cause.h" #include "srsran/rrc/rrc_ue.h" #include @@ -45,7 +47,7 @@ void initial_context_setup_routine::operator()( // Initialize security context if (!security_mng.init_security_context(request.security_context)) { - handle_failure(); + handle_failure(ngap_cause_radio_network_t::unspecified); CORO_EARLY_RETURN(make_unexpected(fail_msg)); } @@ -53,7 +55,7 @@ void initial_context_setup_routine::operator()( { rrc_smc_ctxt = rrc_ue.get_security_mode_command_context(); if (rrc_smc_ctxt.rrc_ue_security_mode_command_pdu.empty()) { - handle_failure(); + handle_failure(ngap_cause_radio_network_t::unspecified); CORO_EARLY_RETURN(make_unexpected(fail_msg)); } } @@ -71,7 +73,11 @@ void initial_context_setup_routine::operator()( f1ap_ue_ctxt_mng.handle_ue_context_setup_request(ue_context_setup_request, std::nullopt)); // Handle UE Context Setup Response if (!ue_context_setup_response.success) { - handle_failure(); + if (ue_context_setup_response.cause.has_value()) { + handle_failure(f1ap_to_ngap_cause(ue_context_setup_response.cause.value())); + } else { + handle_failure(ngap_cause_radio_network_t::unspecified); + } CORO_EARLY_RETURN(make_unexpected(fail_msg)); } } @@ -81,14 +87,17 @@ void initial_context_setup_routine::operator()( CORO_AWAIT_VALUE(security_mode_command_result, rrc_ue.handle_security_mode_complete_expected(rrc_smc_ctxt.transaction_id)); if (!security_mode_command_result) { - handle_failure(); + handle_failure(ngap_cause_radio_network_t::radio_conn_with_ue_lost); CORO_EARLY_RETURN(make_unexpected(fail_msg)); } } // Start UE Capability Enquiry Procedure if (request.ue_radio_cap.has_value()) { - ue_cap_store_result = rrc_ue.store_ue_capabilities(std::move(request.ue_radio_cap.value())); + if (!rrc_ue.store_ue_capabilities(std::move(request.ue_radio_cap.value()))) { + handle_failure(cause_protocol_t::abstract_syntax_error_falsely_constructed_msg); + CORO_EARLY_RETURN(make_unexpected(fail_msg)); + } } else { CORO_AWAIT_VALUE(ue_capability_transfer_result, rrc_ue.handle_rrc_ue_capability_transfer_request(ue_capability_transfer_request)); @@ -96,7 +105,7 @@ void initial_context_setup_routine::operator()( // Handle UE Capability Transfer result if (not ue_capability_transfer_result) { logger.warning("ue={}: \"{}\" UE capability transfer failed", request.ue_index, name()); - handle_failure(); + handle_failure(ngap_cause_radio_network_t::radio_conn_with_ue_lost); CORO_EARLY_RETURN(make_unexpected(fail_msg)); } } @@ -134,7 +143,7 @@ void initial_context_setup_routine::operator()( } // Schedule transmission of UE Radio Capability Info Indication - if (!ue_cap_store_result) { + if (!request.ue_radio_cap.has_value()) { send_ue_radio_capability_info_indication(); } @@ -142,7 +151,7 @@ void initial_context_setup_routine::operator()( CORO_RETURN(resp_msg); } -void initial_context_setup_routine::handle_failure() +void initial_context_setup_routine::handle_failure(ngap_cause_t cause) { fail_msg.cause = cause_protocol_t::unspecified; // Add failed PDU Sessions @@ -151,7 +160,7 @@ void initial_context_setup_routine::handle_failure() request.pdu_session_res_setup_list_cxt_req.value().pdu_session_res_setup_items) { cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = pdu_session_item.pdu_session_id; - failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::unspecified; + failed_item.unsuccessful_transfer.cause = cause; fail_msg.pdu_session_res_failed_to_setup_items.emplace(pdu_session_item.pdu_session_id, failed_item); } diff --git a/lib/cu_cp/routines/initial_context_setup_routine.h b/lib/cu_cp/routines/initial_context_setup_routine.h index ae9a9dc0b1..a1cca92a1b 100644 --- a/lib/cu_cp/routines/initial_context_setup_routine.h +++ b/lib/cu_cp/routines/initial_context_setup_routine.h @@ -34,7 +34,7 @@ class initial_context_setup_routine static const char* name() { return "Initial Context Setup Routine"; } - void handle_failure(); + void handle_failure(ngap_cause_t cause); void handle_nas_pdu(byte_buffer nas_pdu); void send_ue_radio_capability_info_indication(); @@ -56,7 +56,6 @@ class initial_context_setup_routine rrc_reconfiguration_procedure_request rrc_reconfig_args; // (sub-)routine results - bool ue_cap_store_result = false; f1ap_ue_context_setup_response ue_context_setup_response; bool ue_capability_transfer_result = false; // to query the UE capabilities cu_cp_pdu_session_resource_setup_response pdu_session_setup_response; From 3cf4aed4258eb4bf652cbf0ed1782584ffc8bb26 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Wed, 24 Jul 2024 15:25:01 +0200 Subject: [PATCH 035/407] cmake: removed option AUTO_DETECT_ISA and the FindSSE.cmake file. Added 2 variables to pass the -march (ARCH) and -mtune (TUNE) option to the compiler. --- CMakeLists.txt | 44 ++----- cmake/modules/FindSSE.cmake | 226 ------------------------------------ 2 files changed, 7 insertions(+), 263 deletions(-) delete mode 100644 cmake/modules/FindSSE.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 206300e151..2343f4efc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,6 @@ option(ENABLE_DPDK "Enable DPDK" OFF) option(ENABLE_LIBNUMA "Enable LibNUMA" OFF) option(ENABLE_EXPORT "Enable PIC and export libraries" OFF) option(ENABLE_TRX_DRIVER "Enable Amarisoft TRX driver library" OFF) -option(AUTO_DETECT_ISA "Enable automatic ISA detection" ON) option(BUILD_TESTS "Compile tests" ON) option(ENABLE_GPROF "Enable gprof" OFF) option(USE_PHY_TESTVECTORS "Enable testvector PHY tests" ON) @@ -312,42 +311,13 @@ endif (ENABLE_DPDK) ######################################################################## # Instruction Set Architecture setup ######################################################################## -if (AUTO_DETECT_ISA) - if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") - set(GCC_ARCH armv8-a CACHE STRING "GCC compile for specific architecture.") - message(STATUS "Detected aarch64 processor") - set(HAVE_NEON True CACHE BOOL "NEON Instruction set is supported") - else (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") - set(GCC_ARCH native CACHE STRING "GCC compile for specific architecture.") - endif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") - - find_package(SSE) - - # Add default architecture if enabled and available. - ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-march=${GCC_ARCH}" HAVE_MARCH) - - if (HAVE_AVX2) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx2") - endif (HAVE_AVX2) - if (HAVE_AVX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx") - endif (HAVE_AVX) - if (HAVE_SSE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1") - endif (HAVE_SSE) - if (HAVE_FMA) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfma") - endif (HAVE_FMA) - if (HAVE_AVX512) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512cd -mavx512bw -mavx512dq") - endif (HAVE_AVX512) -else (AUTO_DETECT_ISA) - unset(HAVE_SSE CACHE) - unset(HAVE_AVX CACHE) - unset(HAVE_AVX2 CACHE) - unset(HAVE_FMA CACHE) - unset(HAVE_AVX512 CACHE) -endif (AUTO_DETECT_ISA) +set(ARCH "native" CACHE STRING "Compiler march flag. Default value is 'native'") +set(TUNE "generic" CACHE STRING "Compiler mtune flag. Default value is 'generic'") +message(STATUS "ARCH value is ${ARCH}") +message(STATUS "TUNE value is ${TUNE}") + +# Append march and mtune to the compilation flags. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${ARCH} -mtune=${TUNE}") ######################################################################## # Compiler launcher setup diff --git a/cmake/modules/FindSSE.cmake b/cmake/modules/FindSSE.cmake deleted file mode 100644 index 675bd8cd97..0000000000 --- a/cmake/modules/FindSSE.cmake +++ /dev/null @@ -1,226 +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(CheckCSourceRuns) - -option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON) -option(ENABLE_AVX "Enable compile-time AVX support." ON) -option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) -option(ENABLE_FMA "Enable compile-time FMA support." ON) -option(ENABLE_AVX512 "Enable compile-time AVX512 support." ON) - -# Unset cached variables if corresponding options are disabled -if(NOT ENABLE_SSE) - unset(HAVE_SSE CACHE) -endif() -if(NOT ENABLE_AVX) - unset(HAVE_AVX CACHE) -endif() -if(NOT ENABLE_AVX2) - unset(HAVE_AVX2 CACHE) -endif() -if(NOT ENABLE_FMA) - unset(HAVE_FMA CACHE) -endif() -if(NOT ENABLE_AVX512) - unset(HAVE_AVX512 CACHE) -endif() - -if (ENABLE_SSE) - # - # Check compiler for SSE4_1 intrinsics - # - if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(CMAKE_REQUIRED_FLAGS "-msse4.1") - check_c_source_runs(" - #include - #include - - int main() - { - __m128i a = _mm_setzero_si128(); - __m128i b = _mm_minpos_epu16(a); - return 0; - }" - HAVE_SSE) - endif() - - if (HAVE_SSE) - message(STATUS "SSE4.1 is enabled - target CPU must support it") - endif() - - if (ENABLE_AVX) - - # - # Check compiler for AVX intrinsics - # - if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(CMAKE_REQUIRED_FLAGS "-mavx") - check_c_source_runs(" - #include - int main() - { - __m256 a, b, c; - const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; - float dst[8]; - a = _mm256_loadu_ps( src ); - b = _mm256_loadu_ps( src ); - c = _mm256_add_ps( a, b ); - _mm256_storeu_ps( dst, c ); - int i = 0; - for( i = 0; i < 8; i++ ){ - if( ( src[i] + src[i] ) != dst[i] ){ - return -1; - } - } - return 0; - }" - HAVE_AVX) - endif() - - if (HAVE_AVX) - message(STATUS "AVX is enabled - target CPU must support it") - endif() - endif() - - if (ENABLE_AVX2) - - # - # Check compiler for AVX intrinsics - # - if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(CMAKE_REQUIRED_FLAGS "-mavx2") - check_c_source_runs(" - #include - int main() - { - __m256i a, b, c; - const int src[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; - int dst[8]; - a = _mm256_loadu_si256( (__m256i*)src ); - b = _mm256_loadu_si256( (__m256i*)src ); - c = _mm256_add_epi32( a, b ); - _mm256_storeu_si256( (__m256i*)dst, c ); - int i = 0; - for( i = 0; i < 8; i++ ){ - if( ( src[i] + src[i] ) != dst[i] ){ - return -1; - } - } - return 0; - }" - HAVE_AVX2) - endif() - - if (HAVE_AVX2) - message(STATUS "AVX2 is enabled - target CPU must support it") - endif() - endif() - - if (ENABLE_FMA) - - # - # Check compiler for AVX intrinsics - # - if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(CMAKE_REQUIRED_FLAGS "-mfma") - check_c_source_runs(" - #include - int main() - { - __m256 a, b, c, r; - const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; - float dst[8]; - a = _mm256_loadu_ps( src ); - b = _mm256_loadu_ps( src ); - c = _mm256_loadu_ps( src ); - r = _mm256_fmadd_ps( a, b, c ); - _mm256_storeu_ps( dst, r ); - int i = 0; - for( i = 0; i < 8; i++ ){ - if( ( src[i] * src[i] + src[i] ) != dst[i] ){ - return -1; - } - } - return 0; - }" - HAVE_FMA) - endif() - - if (HAVE_FMA) - message(STATUS "FMA is enabled - target CPU must support it") - endif() - endif() - - if (ENABLE_AVX512) - - # - # Check compiler for AVX512 intrinsics - # - if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(CMAKE_REQUIRED_FLAGS "-mavx512f -mavx512cd -mavx512bw -mavx512dq -DLV_HAVE_AVX512") - check_c_source_runs(" - #include - int main() - { - __m512i a, b, c; - const int src[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 , 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; - int dst[16]; - a = _mm512_loadu_si512( (__m512i*)src ); - b = _mm512_loadu_si512( (__m512i*)src ); - c = _mm512_add_epi32( a, b ); - _mm512_storeu_si512( (__m512i*)dst, c ); - int i = 0; - for( i = 0; i < 16; i++ ){ - if( ( src[i] + src[i] ) != dst[i] ){ - return -1; - } - } - return 0; - }" - HAVE_AVX512) - endif() - - if (HAVE_AVX512) - message(STATUS "AVX512 is enabled - target CPU must support it") - - if (NOT HAVE_AVX) - message(WARNING "AVX512 is enabled but AVX is not. This has not been tested. Enable AVX if you can.") - endif() - - if (NOT HAVE_AVX2) - message(WARNING "AVX512 is enabled but AVX2 is not. This has not been tested. Enable AVX2 if you can.") - endif() - - endif() - elseif (${GCC_ARCH} MATCHES "native") - # When a GNU compiler flag -march=native is present and the CPU supports AVX512, the compiler enables - # automatically all the supported AVX512 flags automatically. - - # Get the CPU AVX512 enabled flags. - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") - execute_process(COMMAND bash -c "${CMAKE_CXX_COMPILER} -march=native -Q --help=target | grep -E \"\\-m.*avx512.*\\[enabled]\" -o | cut -c 3- | grep -E \"^\\w*\" -o" - OUTPUT_VARIABLE NATIVE_AVX512_FLAGS) - STRING(REGEX REPLACE "\n" ";" NATIVE_AVX512_FLAGS "${NATIVE_AVX512_FLAGS}") - elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - execute_process(COMMAND bash -c "echo 'int main(){}' | ${CMAKE_CXX_COMPILER} -march=native -S -emit-llvm -x c - -o - | grep attributes. | grep -E \"\\+avx512\\w*,\" -o | cut -c 2-" - OUTPUT_VARIABLE NATIVE_AVX512_FLAGS) - STRING(REGEX REPLACE ",\n" ";" NATIVE_AVX512_FLAGS "${NATIVE_AVX512_FLAGS}") - else() - message(WARNING "AVX512 detection is disabled but AVX512 flags are not disabled.") - endif() - - # Disable all the AVX512 related flags. - foreach (FLAG ${NATIVE_AVX512_FLAGS}) - STRING(TOUPPER FLAG_UPPER ${FLAG}) - ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-mno-${FLAG} " HAVE_NO_${FLAG_UPPER}) - endforeach () - endif () -endif() - -mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA, HAVE_AVX512) From 1c571da429e5db24be49649597f95346d5eca6c6 Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 25 Jul 2024 15:49:08 +0200 Subject: [PATCH 036/407] ci: replace isa flags with new ARCH and TUNE --- .github/workflows/docker.yml | 9 +- .gitlab-ci.yml | 2 +- .gitlab/ci/build.yml | 398 ++++++++++++---------------------- .gitlab/ci/docker.yml | 15 +- .gitlab/ci/trx.yml | 2 +- .gitlab/run_viavi_pipeline.py | 2 +- docker/Dockerfile | 2 +- 7 files changed, 153 insertions(+), 277 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b321c117e1..45f9edf59c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -37,7 +37,6 @@ jobs: # AMD AVX2 - TAGNAME: split72_release_avx2 REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: x86-64-v3 PLATFORM: amd64 LIB: dpdk @@ -46,7 +45,7 @@ jobs: CONTEXT: ./ - TAGNAME: split72_release_with_debug_avx2 REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: x86-64-v3 PLATFORM: amd64 LIB: dpdk @@ -56,7 +55,6 @@ jobs: # AMD AVX512 - TAGNAME: split72_release_avx512 REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: x86-64-v4 PLATFORM: amd64 LIB: dpdk @@ -65,7 +63,7 @@ jobs: CONTEXT: ./ - TAGNAME: split72_release_with_debug_avx512 REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: x86-64-v4 PLATFORM: amd64 LIB: dpdk @@ -76,7 +74,6 @@ jobs: # AMD AVX2 - TAGNAME: split8_release_avx2 REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: x86-64-v3 PLATFORM: amd64 LIB: uhd @@ -85,7 +82,7 @@ jobs: CONTEXT: ./ - TAGNAME: split8_release_with_debug_avx2 REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: x86-64-v3 PLATFORM: amd64 LIB: uhd diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cd9759ea83..a1df13aa68 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -191,7 +191,7 @@ full-code-format: export CXX=/usr/bin/clang++ mkdir -p build cd build || exit - cmake -DASSERT_LEVEL=PARANOID -DAUTO_DETECT_ISA=False -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTS=False .. + cmake -DASSERT_LEVEL=PARANOID -DARCH=x86-64-v3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTS=False .. make srsran_build_info # needed to generate hashes.h - | monitor_child_process() { diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index d7f86ac84f..3c779bbdf1 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -76,12 +76,12 @@ variables: ################ .cache_build_set: &cache_build_set - - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${BUILD_ARGS} + - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${ARCH} paths: [ccache] policy: push .cache_build_get: &cache_build_get - - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${BUILD_ARGS} + - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${ARCH} paths: [ccache] policy: pull-push @@ -112,7 +112,8 @@ variables: ENABLE_GCOV: "" # Empty for cmake default ENABLE_WERROR: "" # Empty for cmake default FORCE_DEBUG_INFO: "" # Empty for cmake default - AUTO_DETECT_ISA: "" + ARCH: "" + TUNE: "" # TEST TEST_EXECUTION_TIMEOUT: 0 # CI @@ -147,9 +148,6 @@ variables: if [ -n "${ASSERT_LEVEL}" ]; then BUILD_CMD="${BUILD_CMD} -DASSERT_LEVEL=${ASSERT_LEVEL}" fi - if [ -n "${AUTO_DETECT_ISA}" ]; then - BUILD_CMD="${BUILD_CMD} -DAUTO_DETECT_ISA=${AUTO_DETECT_ISA}" - fi if [ -n "${ENABLE_EXPORT}" ]; then BUILD_CMD="${BUILD_CMD} -DENABLE_EXPORT=${ENABLE_EXPORT}" fi @@ -174,11 +172,11 @@ variables: if [ -n "${ENABLE_GCOV}" ]; then BUILD_CMD="${BUILD_CMD} -DENABLE_GCOV=${ENABLE_GCOV}" fi - if [ -n "${ENABLE_AVX2}" ]; then - BUILD_CMD="${BUILD_CMD} -DENABLE_AVX2=${ENABLE_AVX2}" + if [ -n "${ARCH}" ]; then + BUILD_CMD="${BUILD_CMD} -DARCH=${ARCH}" fi - if [ -n "${ENABLE_AVX512}" ]; then - BUILD_CMD="${BUILD_CMD} -DENABLE_AVX512=${ENABLE_AVX512}" + if [ -n "${TUNE}" ]; then + BUILD_CMD="${BUILD_CMD} -DTUNE=${TUNE}" fi if [ -n "${ENABLE_WERROR}" ]; then BUILD_CMD="${BUILD_CMD} -DENABLE_WERROR=${ENABLE_WERROR}" @@ -363,9 +361,8 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: coverage - AUTO_DETECT_ISA: "False" ENABLE_GCOV: "True" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke relwithdeb: @@ -376,8 +373,7 @@ variables: BUILD_TYPE: RelWithDebInfo ASSERT_LEVEL: PARANOID TEST_MODE: default - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke tsan: @@ -389,8 +385,7 @@ variables: ASSERT_LEVEL: PARANOID ENABLE_TSAN: "True" TEST_MODE: tsan - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke rhel: @@ -401,9 +396,8 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" - tags: ["${AMD64_TAG}"] + ARCH: x86-64-v3 + tags: ["${AMD64_AVX2_TAG}"] .smoke archlinux: extends: .build_and_unit @@ -414,9 +408,8 @@ variables: BUILD_TYPE: Debug ASSERT_LEVEL: PARANOID TEST_MODE: default - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" - tags: ["${AMD64_TAG}"] + ARCH: x86-64-v3 + tags: ["${AMD64_AVX2_TAG}"] .smoke dpdk: extends: .build_and_unit @@ -428,9 +421,8 @@ variables: ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" ASSERT_LEVEL: PARANOID - AUTO_DETECT_ISA: "False" DPDK_VERSION: "23.11_avx2" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke valgrind: @@ -441,8 +433,7 @@ variables: BUILD_TYPE: Debug ASSERT_LEVEL: PARANOID TEST_MODE: valgrind - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DEXIT_TIMEOUT=120 -DCMAKE_CXX_FLAGS="-march=x86-64-v3" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke avx512: @@ -453,8 +444,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v4" + ARCH: x86-64-v3 tags: ["${AMD64_AVX512_TAG}"] .smoke arm: @@ -465,7 +455,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - AUTO_DETECT_ISA: "False" + ARCH: armv8-a tags: ["${ARM64_TAG}"] .smoke arm neon: @@ -476,8 +466,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=armv8.2-a+crypto+fp16+dotprod" + ARCH: armv8.2-a+crypto+fp16+dotprod tags: ["${ARM64_TAG}"] # Combinations to use in schedules matrix @@ -913,8 +902,7 @@ smoke asan: ASSERT_LEVEL: PARANOID ENABLE_ASAN: "True" TEST_MODE: asan - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] # Packaging @@ -935,12 +923,12 @@ package: KUBERNETES_MEMORY_LIMIT: 12Gi DEB_BUILD_OPTIONS: parallel=${KUBERNETES_CPU_LIMIT} MAKEFLAGS: -j${KUBERNETES_CPU_LIMIT} - extraopts: -DAUTO_DETECT_ISA=False -DCMAKE_CXX_FLAGS="-march=x86-64-v3" + extraopts: -DARCH=x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS_VERSION: "20.04" - extraopts: -DAUTO_DETECT_ISA=False -DCMAKE_CXX_FLAGS="-march=x86-64" + extraopts: -DARCH=x86-64 - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" @@ -985,14 +973,12 @@ export on amd64: COMPILER: gcc TEST_MODE: none ENABLE_EXPORT: "True" - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - AUTO_DETECT_ISA: "False" - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 export on amd64 avx512: extends: export on amd64 @@ -1000,8 +986,7 @@ export on amd64 avx512: parallel: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 # Build + unit tests combinations @@ -1010,141 +995,128 @@ ubuntu-24.04 amd64 avx2: rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 270 minutes + start_in: 120 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS: ubuntu-24.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 -ubuntu-23.10 amd64 avx2: +ubuntu-24.04 amd64 avx512: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed start_in: 120 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX512_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.04 + <<: *basic_combinations + ARCH: x86-64-v4 + +ubuntu-23.10 amd64 avx2: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + when: delayed + start_in: 150 minutes + interruptible: false + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS: ubuntu-23.10 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 -ubuntu-22.04 amd64 avx2: +ubuntu-23.10 amd64 avx512: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 210 minutes + start_in: 150 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX512_TAG}"] parallel: matrix: - - OS: ubuntu-22.04 + - OS: ubuntu-23.10 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v4 -rhel-8 amd64 avx2: +ubuntu-22.04 amd64 avx2: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed start_in: 180 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - - OS: rhel-8 + - OS: ubuntu-22.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" - -# Basic AMD NO_ISA / AVX512 + ARCH: x86-64-v3 -ubuntu-24.04 amd64 no isa release: +ubuntu-20.04 amd64 avx2: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 150 minutes + start_in: 210 minutes interruptible: false - variables: - OS: ubuntu-24.04 - COMPILER: gcc - BUILD_TYPE: Release - ASSERT_LEVEL: PARANOID - TEST_MODE: default - AUTO_DETECT_ISA: "False" - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - - COMPILER: [gcc, clang] + - OS: ubuntu-20.04 + <<: *basic_combinations + ARCH: x86-64-v3 -ubuntu-24.04 amd64 avx512 release: +rhel-8 amd64 avx2: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 120 minutes + start_in: 240 minutes interruptible: false - variables: - OS: ubuntu-24.04 - COMPILER: gcc - BUILD_TYPE: Release - ASSERT_LEVEL: PARANOID - TEST_MODE: default - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" - tags: ["${AMD64_AVX512_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - - COMPILER: [gcc, clang] + - OS: rhel-8 + <<: *basic_combinations + ARCH: x86-64-v3 # Basic ARM NO_ISA / NEON -ubuntu-24.04 arm no isa release: +ubuntu-24.04 arm neon: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 150 minutes + start_in: 60 minutes interruptible: false - variables: - OS: ubuntu-24.04 - COMPILER: gcc - BUILD_TYPE: Release - ASSERT_LEVEL: PARANOID - TEST_MODE: default - AUTO_DETECT_ISA: "False" tags: ["${ARM64_TAG}"] parallel: matrix: - - COMPILER: [gcc, clang] + - OS: ubuntu-24.04 + <<: *basic_combinations + ARCH: armv8.2-a+crypto+fp16+dotprod -ubuntu-24.04 arm neon release: +ubuntu-23.10 arm neon: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 120 minutes + start_in: 90 minutes interruptible: false - variables: - OS: ubuntu-24.04 - COMPILER: gcc - BUILD_TYPE: Release - ASSERT_LEVEL: PARANOID - TEST_MODE: default - AUTO_DETECT_ISA: "True" tags: ["${ARM64_TAG}"] parallel: matrix: - - COMPILER: [gcc, clang] + - OS: ubuntu-23.10 + <<: *basic_combinations + ARCH: armv8.2-a+crypto+fp16+dotprod # Basic DPDK @@ -1160,8 +1132,7 @@ ubuntu dpdk: ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" ASSERT_LEVEL: PARANOID - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: @@ -1181,7 +1152,7 @@ ubuntu dpdk: ################### # Alternative OSs # ################### -archlinux amd64 no isa: +archlinux amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Alternative OSs/ @@ -1192,7 +1163,6 @@ archlinux amd64 no isa: - OS: archlinux-latest ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "False" archlinux amd64 avx2: extends: .build_and_unit @@ -1201,14 +1171,13 @@ archlinux amd64 avx2: when: delayed start_in: 30 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS: archlinux-latest ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 archlinux amd64 avx512: extends: .build_and_unit @@ -1221,9 +1190,9 @@ archlinux amd64 avx512: - OS: archlinux-latest ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "True" + ARCH: x86-64-v4 -debian 12 amd64 no isa: +debian 12 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Alternative OSs/ @@ -1236,7 +1205,6 @@ debian 12 amd64 no isa: - OS: debian-12 ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "False" debian 12 amd64 avx2: extends: .build_and_unit @@ -1245,14 +1213,13 @@ debian 12 amd64 avx2: when: delayed start_in: 90 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS: debian-12 ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 debian 12 amd64 avx512: extends: .build_and_unit @@ -1267,9 +1234,9 @@ debian 12 amd64 avx512: - OS: debian-12 ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "True" + ARCH: x86-64-v4 -debian 11 amd64 no isa: +debian 11 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Alternative OSs/ @@ -1282,7 +1249,6 @@ debian 11 amd64 no isa: - OS: debian-11 ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "False" debian 11 amd64 avx2: extends: .build_and_unit @@ -1291,14 +1257,13 @@ debian 11 amd64 avx2: when: delayed start_in: 150 minutes interruptible: false - tags: ["${AMD64_TAG}"] + tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS: debian-11 ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v2 debian 11 amd64 avx512: extends: .build_and_unit @@ -1313,7 +1278,7 @@ debian 11 amd64 avx512: - OS: debian-11 ENABLE_WERROR: "False" <<: *basic_combinations - AUTO_DETECT_ISA: "True" + ARCH: x86-64-v4 ########## # Weekly # @@ -1353,23 +1318,40 @@ debian 11 amd64 avx512: COMPILER: gcc TEST_MODE: valgrind -sanitizers amd64 no isa: +sanitizers amd64 native: extends: .weekly sanitizers - variables: - AUTO_DETECT_ISA: "False" tags: ["${AMD64_TAG}"] + parallel: + matrix: + # ubuntu-20.04 disabled due to https://bugs.launchpad.net/ubuntu/+source/gcc-9/+bug/2029910 + # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 + - OS: [ubuntu-24.04, ubuntu-23.10] + SANITIZER: tsan + COMPILER: [gcc, clang] + ENABLE_TSAN: "True" + TEST_MODE: default + - OS: [ubuntu-22.04, ubuntu-20.04] + SANITIZER: asan + COMPILER: [gcc, clang] + ENABLE_ASAN: "True" + TEST_MODE: default + - OS: [ubuntu-24.04, ubuntu-23.10] + SANITIZER: asan + COMPILER: clang + ENABLE_ASAN: "True" + TEST_MODE: default + # Valgrind doesn't support AVX512 instruction set sanitizers amd64 avx2: extends: .weekly sanitizers variables: - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] sanitizers amd64 avx512: extends: .weekly sanitizers variables: - AUTO_DETECT_ISA: "True" + ARCH: x86-64-v4 tags: ["${AMD64_AVX512_TAG}"] parallel: matrix: @@ -1392,16 +1374,14 @@ sanitizers amd64 avx512: TEST_MODE: default # Valgrind doesn't support AVX512 instruction set -sanitizers arm no isa: +sanitizers arm native: extends: .weekly sanitizers - variables: - AUTO_DETECT_ISA: "False" tags: ["${ARM64_TAG}"] sanitizers arm neon: extends: .weekly sanitizers variables: - AUTO_DETECT_ISA: "True" + ARCH: armv8.2-a+crypto+fp16+dotprod tags: ["${ARM64_TAG}"] # UHD Alternatives @@ -1414,7 +1394,7 @@ build uhd alt: variables: TEST_MODE: none ASSERT_LEVEL: PARANOID - AUTO_DETECT_ISA: "False" + ARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: @@ -1433,7 +1413,7 @@ build uhd alt: # Build + unit tests combinations -ubuntu-24.04 amd64 no isa: +ubuntu-24.04 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1445,38 +1425,8 @@ ubuntu-24.04 amd64 no isa: matrix: - OS: ubuntu-24.04 <<: *basic_combinations - AUTO_DETECT_ISA: "False" - -ubuntu-24.04 amd64 avx512: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 30 minutes - interruptible: false - tags: ["${AMD64_AVX512_TAG}"] - parallel: - matrix: - - OS: ubuntu-24.04 - <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" - -ubuntu-24.04 arm no isa: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 30 minutes - interruptible: false - tags: ["${ARM64_TAG}"] - parallel: - matrix: - - OS: ubuntu-24.04 - <<: *basic_combinations - AUTO_DETECT_ISA: "False" -ubuntu-24.04 arm neon: +ubuntu-24.04 arm native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1488,9 +1438,8 @@ ubuntu-24.04 arm neon: matrix: - OS: ubuntu-24.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" -ubuntu-23.10 amd64 no isa: +ubuntu-23.10 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1502,38 +1451,8 @@ ubuntu-23.10 amd64 no isa: matrix: - OS: ubuntu-23.10 <<: *basic_combinations - AUTO_DETECT_ISA: "False" - -ubuntu-23.10 amd64 avx512: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 30 minutes - interruptible: false - tags: ["${AMD64_AVX512_TAG}"] - parallel: - matrix: - - OS: ubuntu-23.10 - <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" - -ubuntu-23.10 arm no isa: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 30 minutes - interruptible: false - tags: ["${ARM64_TAG}"] - parallel: - matrix: - - OS: ubuntu-23.10 - <<: *basic_combinations - AUTO_DETECT_ISA: "False" -ubuntu-23.10 arm neon: +ubuntu-23.10 arm native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1545,9 +1464,8 @@ ubuntu-23.10 arm neon: matrix: - OS: ubuntu-23.10 <<: *basic_combinations - AUTO_DETECT_ISA: "True" -ubuntu-22.04 amd64 no isa: +ubuntu-22.04 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1559,7 +1477,6 @@ ubuntu-22.04 amd64 no isa: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - AUTO_DETECT_ISA: "False" ubuntu-22.04 amd64 avx512: extends: .build_and_unit @@ -1573,10 +1490,9 @@ ubuntu-22.04 amd64 avx512: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 -ubuntu-22.04 arm no isa: +ubuntu-22.04 arm native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1588,7 +1504,6 @@ ubuntu-22.04 arm no isa: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - AUTO_DETECT_ISA: "False" ubuntu-22.04 arm neon: extends: .build_and_unit @@ -1602,9 +1517,9 @@ ubuntu-22.04 arm neon: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" + ARCH: armv8.2-a+crypto+fp16+dotprod -ubuntu-20.04 amd64 no isa: +ubuntu-20.04 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1616,22 +1531,6 @@ ubuntu-20.04 amd64 no isa: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - AUTO_DETECT_ISA: "False" - -ubuntu-20.04 amd64 avx2: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 240 minutes - interruptible: false - tags: ["${AMD64_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" ubuntu-20.04 amd64 avx512: extends: .build_and_unit @@ -1645,10 +1544,9 @@ ubuntu-20.04 amd64 avx512: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 -ubuntu-20.04 arm no isa: +ubuntu-20.04 arm native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1660,7 +1558,6 @@ ubuntu-20.04 arm no isa: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - AUTO_DETECT_ISA: "False" ubuntu-20.04 arm neon: extends: .build_and_unit @@ -1674,9 +1571,9 @@ ubuntu-20.04 arm neon: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - AUTO_DETECT_ISA: "True" + ARCH: armv8.2-a+crypto+fp16+dotprod -rhel-8 amd64 no isa: +rhel-8 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1688,7 +1585,6 @@ rhel-8 amd64 no isa: matrix: - OS: rhel-8 <<: *basic_combinations - AUTO_DETECT_ISA: "False" rhel-8 amd64 avx512: extends: .build_and_unit @@ -1702,10 +1598,9 @@ rhel-8 amd64 avx512: matrix: - OS: rhel-8 <<: *basic_combinations - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 -rhel-8 arm no isa: +rhel-8 arm native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ @@ -1717,7 +1612,6 @@ rhel-8 arm no isa: matrix: - OS: rhel-8 <<: *basic_combinations - AUTO_DETECT_ISA: "False" rhel-8 arm neon: extends: .build_and_unit @@ -1731,7 +1625,7 @@ rhel-8 arm neon: matrix: - OS: rhel-8 <<: *basic_combinations - AUTO_DETECT_ISA: "True" + ARCH: armv8.2-a+crypto+fp16+dotprod # DPDK @@ -1755,8 +1649,7 @@ ubuntu-20.04 amd64 avx2 dpdk: - OS: ubuntu-20.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3", "23.11"] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 ubuntu-20.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1771,8 +1664,7 @@ ubuntu-20.04 amd64 avx512 dpdk: - OS: ubuntu-20.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3", "23.11"] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 ubuntu-22.04 amd64 avx2 dpdk: extends: .build_and_unit @@ -1787,8 +1679,7 @@ ubuntu-22.04 amd64 avx2 dpdk: - OS: ubuntu-22.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 ubuntu-22.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1803,8 +1694,7 @@ ubuntu-22.04 amd64 avx512 dpdk: - OS: ubuntu-22.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx512", "23.11_avx512"] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 ubuntu-23.10 amd64 avx2 dpdk: extends: .build_and_unit @@ -1819,8 +1709,7 @@ ubuntu-23.10 amd64 avx2 dpdk: - OS: ubuntu-23.10 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 ubuntu-23.10 amd64 avx512 dpdk: extends: .build_and_unit @@ -1835,8 +1724,7 @@ ubuntu-23.10 amd64 avx512 dpdk: - OS: ubuntu-23.10 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx512", "23.11_avx512"] - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 ubuntu-24.04 amd64 avx2 dpdk: extends: .build_and_unit @@ -1851,8 +1739,7 @@ ubuntu-24.04 amd64 avx2 dpdk: - OS: ubuntu-24.04 <<: *basic_combinations_dpdk DPDK_VERSION: "23.11_avx2" - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "False" + ARCH: x86-64-v3 ubuntu-24.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1867,8 +1754,7 @@ ubuntu-24.04 amd64 avx512 dpdk: - OS: ubuntu-24.04 <<: *basic_combinations_dpdk DPDK_VERSION: "23.11_avx512" - AUTO_DETECT_ISA: "True" - ENABLE_AVX512: "True" + ARCH: x86-64-v4 ############# # Run check # @@ -2000,8 +1886,7 @@ basic avx512 dpdk: ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" DPDK_VERSION: "23.11_avx512" - AUTO_DETECT_ISA: "False" - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v4" + ARCH: x86-64-v4 FORCE_DEBUG_INFO: "True" ASSERT_LEVEL: MINIMAL tags: ["${AMD64_AVX512_TAG}"] @@ -2027,7 +1912,6 @@ custom build: interruptible: false # Web jobs are standalone variables: ENABLE_ZEROMQ: "" - AUTO_DETECT_ISA: "" tags: ["${INFRASTRUCTURE_TAG}"] after_script: - *build_after_script diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index 8a08195a6a..9e3326984a 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -310,34 +310,31 @@ srsran image split72: matrix: # AMD AVX2 - SUFFIX: release_avx2 - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 - SUFFIX: release_with_debug_avx2 - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 # AMD AVX512 - SUFFIX: release_avx512 - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: x86-64-v4 TAG: amd64-avx2-avx512 PLATFORM: amd64 - SUFFIX: release_with_debug_avx512 - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: x86-64-v4 TAG: amd64-avx2-avx512 PLATFORM: amd64 # ARM - SUFFIX: release_arm - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 - SUFFIX: release_with_debug_arm - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 @@ -351,23 +348,21 @@ srsran image split8: matrix: # AMD AVX2 - SUFFIX: release_avx2 - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 - SUFFIX: release_with_debug_avx2 - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 # ARM - SUFFIX: release_arm - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off ARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 - SUFFIX: release_with_debug_arm - EXTRA_CMAKE_ARGS: -DAUTO_DETECT_ISA=Off -DFORCE_DEBUG_INFO=On + EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On ARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index 848a2b9e66..fe5ed3e64a 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -58,7 +58,7 @@ build trx driver: rm -Rf build mkdir build cd build - cmake -DENABLE_TRX_DRIVER=True -DTRX_DRIVER_DIR=${CI_PROJECT_DIR}/amarisoft/trx_uhd-linux -DENABLE_EXPORT=True -DENABLE_UHD=False -DENABLE_ZEROMQ=True -DAUTO_DETECT_ISA=False -DCMAKE_CXX_FLAGS="-march=x86-64-v3" .. + cmake -DENABLE_TRX_DRIVER=True -DTRX_DRIVER_DIR=${CI_PROJECT_DIR}/amarisoft/trx_uhd-linux -DENABLE_EXPORT=True -DENABLE_UHD=False -DENABLE_ZEROMQ=True -DARCH=x86-64-v3 .. make -j${KUBERNETES_CPU_REQUEST} trx_srsran_test } - | diff --git a/.gitlab/run_viavi_pipeline.py b/.gitlab/run_viavi_pipeline.py index ff7ed6b21e..483733404e 100644 --- a/.gitlab/run_viavi_pipeline.py +++ b/.gitlab/run_viavi_pipeline.py @@ -53,7 +53,7 @@ def main(): TESTMODE = "none" MAKE_ARGS = "-j6" - BUILD_ARGS = '-DCMAKE_BUILD_TYPE=Release -DFORCE_DEBUG_INFO=True -DENABLE_UHD=False -DENABLE_DPDK=True -DENABLE_ZEROMQ=False -DAUTO_DETECT_ISA=False -DCMAKE_CXX_FLAGS="-march=x86-64-v4"' + BUILD_ARGS = '-DCMAKE_BUILD_TYPE=Release -DFORCE_DEBUG_INFO=True -DENABLE_UHD=False -DENABLE_DPDK=True -DENABLE_ZEROMQ=False -DARCH="x86-64-v4"' DPDK_VERSION = "23.11_avx512" TESTBED = "viavi" diff --git a/docker/Dockerfile b/docker/Dockerfile index 0e21015913..bf905dff72 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -53,7 +53,7 @@ RUN if [ -z "$NUM_CORES" ]; then NUM_CORES=$(nproc); fi && \ -m "-j${NUM_CORES} install" \ -DBUILD_TESTS=True \ -DENABLE_${LIB_UPPER}=On \ - -DCMAKE_CXX_FLAGS="-march=${ARCH}" \ + -DARCH=${ARCH} \ -DCMAKE_INSTALL_PREFIX=/opt/srs \ ${EXTRA_CMAKE_ARGS} /src From dd17a412614d97cc95d34f6653103c9fd60d80b9 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Wed, 31 Jul 2024 11:23:59 +0200 Subject: [PATCH 037/407] cmake: updated options to MARCH and MTUNE --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2343f4efc3..ac6a39ded0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,13 +311,13 @@ endif (ENABLE_DPDK) ######################################################################## # Instruction Set Architecture setup ######################################################################## -set(ARCH "native" CACHE STRING "Compiler march flag. Default value is 'native'") -set(TUNE "generic" CACHE STRING "Compiler mtune flag. Default value is 'generic'") -message(STATUS "ARCH value is ${ARCH}") -message(STATUS "TUNE value is ${TUNE}") +set(MARCH "native" CACHE STRING "Compiler march flag. Default value is 'native'") +set(MTUNE "generic" CACHE STRING "Compiler mtune flag. Default value is 'generic'") +message(STATUS "ARCH value is ${MARCH}") +message(STATUS "TUNE value is ${MTUNE}") # Append march and mtune to the compilation flags. -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${ARCH} -mtune=${TUNE}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${MARCH} -mtune=${MTUNE}") ######################################################################## # Compiler launcher setup From df061404e58b9202c884320e1a9d314959944e50 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 31 Jul 2024 11:33:44 +0200 Subject: [PATCH 038/407] ci: updated options to MARCH and MTUNE --- .github/workflows/docker.yml | 18 +++--- .gitlab-ci.yml | 2 +- .gitlab/ci/build.yml | 116 +++++++++++++++++----------------- .gitlab/ci/docker.yml | 22 +++---- .gitlab/ci/trx.yml | 2 +- .gitlab/run_viavi_pipeline.py | 2 +- docker/Dockerfile | 10 +-- 7 files changed, 86 insertions(+), 86 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 45f9edf59c..6440c0ca50 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,7 +17,7 @@ jobs: - TAGNAME: "" REPOSITORY: metrics-server EXTRA_CMAKE_ARGS: "" - ARCH: "" + MARCH: "" PLATFORM: amd64 LIB: "" LIB_VERSION: "" @@ -27,7 +27,7 @@ jobs: - TAGNAME: "" REPOSITORY: grafana EXTRA_CMAKE_ARGS: "" - ARCH: "" + MARCH: "" PLATFORM: amd64 LIB: "" LIB_VERSION: "" @@ -37,7 +37,7 @@ jobs: # AMD AVX2 - TAGNAME: split72_release_avx2 REPOSITORY: srsran-project - ARCH: x86-64-v3 + MARCH: x86-64-v3 PLATFORM: amd64 LIB: dpdk LIB_VERSION: "23.11" @@ -46,7 +46,7 @@ jobs: - TAGNAME: split72_release_with_debug_avx2 REPOSITORY: srsran-project EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: x86-64-v3 + MARCH: x86-64-v3 PLATFORM: amd64 LIB: dpdk LIB_VERSION: "23.11" @@ -55,7 +55,7 @@ jobs: # AMD AVX512 - TAGNAME: split72_release_avx512 REPOSITORY: srsran-project - ARCH: x86-64-v4 + MARCH: x86-64-v4 PLATFORM: amd64 LIB: dpdk LIB_VERSION: "23.11" @@ -64,7 +64,7 @@ jobs: - TAGNAME: split72_release_with_debug_avx512 REPOSITORY: srsran-project EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: x86-64-v4 + MARCH: x86-64-v4 PLATFORM: amd64 LIB: dpdk LIB_VERSION: "23.11" @@ -74,7 +74,7 @@ jobs: # AMD AVX2 - TAGNAME: split8_release_avx2 REPOSITORY: srsran-project - ARCH: x86-64-v3 + MARCH: x86-64-v3 PLATFORM: amd64 LIB: uhd LIB_VERSION: "4.6.0.0" @@ -83,7 +83,7 @@ jobs: - TAGNAME: split8_release_with_debug_avx2 REPOSITORY: srsran-project EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: x86-64-v3 + MARCH: x86-64-v3 PLATFORM: amd64 LIB: uhd LIB_VERSION: "4.6.0.0" @@ -142,4 +142,4 @@ jobs: NAME="${{ env.NAME }}" LIB=${{ matrix.LIB }} LIB_VERSION=${{ matrix.LIB_VERSION }} - ARCH=${{ matrix.ARCH }} \ No newline at end of file + MARCH=${{ matrix.MARCH }} \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a1df13aa68..04cb9e0e65 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -191,7 +191,7 @@ full-code-format: export CXX=/usr/bin/clang++ mkdir -p build cd build || exit - cmake -DASSERT_LEVEL=PARANOID -DARCH=x86-64-v3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTS=False .. + cmake -DASSERT_LEVEL=PARANOID -DMARCH=x86-64-v3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTS=False .. make srsran_build_info # needed to generate hashes.h - | monitor_child_process() { diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 3c779bbdf1..8224648a5b 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -76,12 +76,12 @@ variables: ################ .cache_build_set: &cache_build_set - - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${ARCH} + - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${MARCH} paths: [ccache] policy: push .cache_build_get: &cache_build_get - - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${ARCH} + - key: ${OS}-${COMPILER}-${BUILD_TYPE}-${MARCH} paths: [ccache] policy: pull-push @@ -112,8 +112,8 @@ variables: ENABLE_GCOV: "" # Empty for cmake default ENABLE_WERROR: "" # Empty for cmake default FORCE_DEBUG_INFO: "" # Empty for cmake default - ARCH: "" - TUNE: "" + MARCH: "" + MTUNE: "" # TEST TEST_EXECUTION_TIMEOUT: 0 # CI @@ -172,11 +172,11 @@ variables: if [ -n "${ENABLE_GCOV}" ]; then BUILD_CMD="${BUILD_CMD} -DENABLE_GCOV=${ENABLE_GCOV}" fi - if [ -n "${ARCH}" ]; then - BUILD_CMD="${BUILD_CMD} -DARCH=${ARCH}" + if [ -n "${MARCH}" ]; then + BUILD_CMD="${BUILD_CMD} -DMARCH=${MARCH}" fi - if [ -n "${TUNE}" ]; then - BUILD_CMD="${BUILD_CMD} -DTUNE=${TUNE}" + if [ -n "${MTUNE}" ]; then + BUILD_CMD="${BUILD_CMD} -DTUNE=${MTUNE}" fi if [ -n "${ENABLE_WERROR}" ]; then BUILD_CMD="${BUILD_CMD} -DENABLE_WERROR=${ENABLE_WERROR}" @@ -362,7 +362,7 @@ variables: ASSERT_LEVEL: PARANOID TEST_MODE: coverage ENABLE_GCOV: "True" - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke relwithdeb: @@ -373,7 +373,7 @@ variables: BUILD_TYPE: RelWithDebInfo ASSERT_LEVEL: PARANOID TEST_MODE: default - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke tsan: @@ -385,7 +385,7 @@ variables: ASSERT_LEVEL: PARANOID ENABLE_TSAN: "True" TEST_MODE: tsan - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke rhel: @@ -396,7 +396,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke archlinux: @@ -408,7 +408,7 @@ variables: BUILD_TYPE: Debug ASSERT_LEVEL: PARANOID TEST_MODE: default - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke dpdk: @@ -422,7 +422,7 @@ variables: ENABLE_DPDK: "True" ASSERT_LEVEL: PARANOID DPDK_VERSION: "23.11_avx2" - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke valgrind: @@ -433,7 +433,7 @@ variables: BUILD_TYPE: Debug ASSERT_LEVEL: PARANOID TEST_MODE: valgrind - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] .smoke avx512: @@ -444,7 +444,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX512_TAG}"] .smoke arm: @@ -455,7 +455,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - ARCH: armv8-a + MARCH: armv8-a tags: ["${ARM64_TAG}"] .smoke arm neon: @@ -466,7 +466,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod tags: ["${ARM64_TAG}"] # Combinations to use in schedules matrix @@ -902,7 +902,7 @@ smoke asan: ASSERT_LEVEL: PARANOID ENABLE_ASAN: "True" TEST_MODE: asan - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] # Packaging @@ -923,12 +923,12 @@ package: KUBERNETES_MEMORY_LIMIT: 12Gi DEB_BUILD_OPTIONS: parallel=${KUBERNETES_CPU_LIMIT} MAKEFLAGS: -j${KUBERNETES_CPU_LIMIT} - extraopts: -DARCH=x86-64-v3 + extraopts: -DMARCH=x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - OS_VERSION: "20.04" - extraopts: -DARCH=x86-64 + extraopts: -DMARCH=x86-64 - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" @@ -978,7 +978,7 @@ export on amd64: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - ARCH: x86-64-v3 + MARCH: x86-64-v3 export on amd64 avx512: extends: export on amd64 @@ -986,7 +986,7 @@ export on amd64 avx512: parallel: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - ARCH: x86-64-v4 + MARCH: x86-64-v4 # Build + unit tests combinations @@ -1002,7 +1002,7 @@ ubuntu-24.04 amd64 avx2: matrix: - OS: ubuntu-24.04 <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-24.04 amd64 avx512: extends: .build_and_unit @@ -1016,7 +1016,7 @@ ubuntu-24.04 amd64 avx512: matrix: - OS: ubuntu-24.04 <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-23.10 amd64 avx2: extends: .build_and_unit @@ -1030,7 +1030,7 @@ ubuntu-23.10 amd64 avx2: matrix: - OS: ubuntu-23.10 <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-23.10 amd64 avx512: extends: .build_and_unit @@ -1044,7 +1044,7 @@ ubuntu-23.10 amd64 avx512: matrix: - OS: ubuntu-23.10 <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-22.04 amd64 avx2: extends: .build_and_unit @@ -1058,7 +1058,7 @@ ubuntu-22.04 amd64 avx2: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-20.04 amd64 avx2: extends: .build_and_unit @@ -1072,7 +1072,7 @@ ubuntu-20.04 amd64 avx2: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 rhel-8 amd64 avx2: extends: .build_and_unit @@ -1086,7 +1086,7 @@ rhel-8 amd64 avx2: matrix: - OS: rhel-8 <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 # Basic ARM NO_ISA / NEON @@ -1102,7 +1102,7 @@ ubuntu-24.04 arm neon: matrix: - OS: ubuntu-24.04 <<: *basic_combinations - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod ubuntu-23.10 arm neon: extends: .build_and_unit @@ -1116,7 +1116,7 @@ ubuntu-23.10 arm neon: matrix: - OS: ubuntu-23.10 <<: *basic_combinations - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod # Basic DPDK @@ -1132,7 +1132,7 @@ ubuntu dpdk: ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" ASSERT_LEVEL: PARANOID - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: @@ -1177,7 +1177,7 @@ archlinux amd64 avx2: - OS: archlinux-latest ENABLE_WERROR: "False" <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 archlinux amd64 avx512: extends: .build_and_unit @@ -1190,7 +1190,7 @@ archlinux amd64 avx512: - OS: archlinux-latest ENABLE_WERROR: "False" <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 debian 12 amd64 native: extends: .build_and_unit @@ -1219,7 +1219,7 @@ debian 12 amd64 avx2: - OS: debian-12 ENABLE_WERROR: "False" <<: *basic_combinations - ARCH: x86-64-v3 + MARCH: x86-64-v3 debian 12 amd64 avx512: extends: .build_and_unit @@ -1234,7 +1234,7 @@ debian 12 amd64 avx512: - OS: debian-12 ENABLE_WERROR: "False" <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 debian 11 amd64 native: extends: .build_and_unit @@ -1263,7 +1263,7 @@ debian 11 amd64 avx2: - OS: debian-11 ENABLE_WERROR: "False" <<: *basic_combinations - ARCH: x86-64-v2 + MARCH: x86-64-v2 debian 11 amd64 avx512: extends: .build_and_unit @@ -1278,7 +1278,7 @@ debian 11 amd64 avx512: - OS: debian-11 ENABLE_WERROR: "False" <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 ########## # Weekly # @@ -1345,13 +1345,13 @@ sanitizers amd64 native: sanitizers amd64 avx2: extends: .weekly sanitizers variables: - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] sanitizers amd64 avx512: extends: .weekly sanitizers variables: - ARCH: x86-64-v4 + MARCH: x86-64-v4 tags: ["${AMD64_AVX512_TAG}"] parallel: matrix: @@ -1381,7 +1381,7 @@ sanitizers arm native: sanitizers arm neon: extends: .weekly sanitizers variables: - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod tags: ["${ARM64_TAG}"] # UHD Alternatives @@ -1394,7 +1394,7 @@ build uhd alt: variables: TEST_MODE: none ASSERT_LEVEL: PARANOID - ARCH: x86-64-v3 + MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: @@ -1490,7 +1490,7 @@ ubuntu-22.04 amd64 avx512: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-22.04 arm native: extends: .build_and_unit @@ -1517,7 +1517,7 @@ ubuntu-22.04 arm neon: matrix: - OS: ubuntu-22.04 <<: *basic_combinations - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod ubuntu-20.04 amd64 native: extends: .build_and_unit @@ -1544,7 +1544,7 @@ ubuntu-20.04 amd64 avx512: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-20.04 arm native: extends: .build_and_unit @@ -1571,7 +1571,7 @@ ubuntu-20.04 arm neon: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod rhel-8 amd64 native: extends: .build_and_unit @@ -1598,7 +1598,7 @@ rhel-8 amd64 avx512: matrix: - OS: rhel-8 <<: *basic_combinations - ARCH: x86-64-v4 + MARCH: x86-64-v4 rhel-8 arm native: extends: .build_and_unit @@ -1625,7 +1625,7 @@ rhel-8 arm neon: matrix: - OS: rhel-8 <<: *basic_combinations - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod # DPDK @@ -1649,7 +1649,7 @@ ubuntu-20.04 amd64 avx2 dpdk: - OS: ubuntu-20.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3", "23.11"] - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-20.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1664,7 +1664,7 @@ ubuntu-20.04 amd64 avx512 dpdk: - OS: ubuntu-20.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3", "23.11"] - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-22.04 amd64 avx2 dpdk: extends: .build_and_unit @@ -1679,7 +1679,7 @@ ubuntu-22.04 amd64 avx2 dpdk: - OS: ubuntu-22.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-22.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1694,7 +1694,7 @@ ubuntu-22.04 amd64 avx512 dpdk: - OS: ubuntu-22.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx512", "23.11_avx512"] - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-23.10 amd64 avx2 dpdk: extends: .build_and_unit @@ -1709,7 +1709,7 @@ ubuntu-23.10 amd64 avx2 dpdk: - OS: ubuntu-23.10 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-23.10 amd64 avx512 dpdk: extends: .build_and_unit @@ -1724,7 +1724,7 @@ ubuntu-23.10 amd64 avx512 dpdk: - OS: ubuntu-23.10 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3_avx512", "23.11_avx512"] - ARCH: x86-64-v4 + MARCH: x86-64-v4 ubuntu-24.04 amd64 avx2 dpdk: extends: .build_and_unit @@ -1739,7 +1739,7 @@ ubuntu-24.04 amd64 avx2 dpdk: - OS: ubuntu-24.04 <<: *basic_combinations_dpdk DPDK_VERSION: "23.11_avx2" - ARCH: x86-64-v3 + MARCH: x86-64-v3 ubuntu-24.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1754,7 +1754,7 @@ ubuntu-24.04 amd64 avx512 dpdk: - OS: ubuntu-24.04 <<: *basic_combinations_dpdk DPDK_VERSION: "23.11_avx512" - ARCH: x86-64-v4 + MARCH: x86-64-v4 ############# # Run check # @@ -1886,7 +1886,7 @@ basic avx512 dpdk: ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" DPDK_VERSION: "23.11_avx512" - ARCH: x86-64-v4 + MARCH: x86-64-v4 FORCE_DEBUG_INFO: "True" ASSERT_LEVEL: MINIMAL tags: ["${AMD64_AVX512_TAG}"] diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index 9e3326984a..4c6cb89716 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -295,7 +295,7 @@ grafana server image latest: - | export NAME="srsran-project" export VERSION="${SPLIT}_${SUFFIX}" - export BUILD_ARGS="LIB=${LIB};LIB_VERSION=${LIB_VERSION};ARCH=${ARCH};NUM_CORES=${KUBERNETES_CPU_LIMIT};EXTRA_CMAKE_ARGS=\"${EXTRA_CMAKE_ARGS}\"" + export BUILD_ARGS="LIB=${LIB};LIB_VERSION=${LIB_VERSION};MARCH=${MARCH};NUM_CORES=${KUBERNETES_CPU_LIMIT};EXTRA_CMAKE_ARGS=\"${EXTRA_CMAKE_ARGS}\"" needs: - job: gnb docker compose optional: true @@ -310,32 +310,32 @@ srsran image split72: matrix: # AMD AVX2 - SUFFIX: release_avx2 - ARCH: x86-64-v3 + MARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 - SUFFIX: release_with_debug_avx2 EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: x86-64-v3 + MARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 # AMD AVX512 - SUFFIX: release_avx512 - ARCH: x86-64-v4 + MARCH: x86-64-v4 TAG: amd64-avx2-avx512 PLATFORM: amd64 - SUFFIX: release_with_debug_avx512 EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: x86-64-v4 + MARCH: x86-64-v4 TAG: amd64-avx2-avx512 PLATFORM: amd64 # ARM - SUFFIX: release_arm - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 - SUFFIX: release_with_debug_arm EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 @@ -348,21 +348,21 @@ srsran image split8: matrix: # AMD AVX2 - SUFFIX: release_avx2 - ARCH: x86-64-v3 + MARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 - SUFFIX: release_with_debug_avx2 EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: x86-64-v3 + MARCH: x86-64-v3 TAG: amd64-avx2 PLATFORM: amd64 # ARM - SUFFIX: release_arm - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 - SUFFIX: release_with_debug_arm EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - ARCH: armv8.2-a+crypto+fp16+dotprod + MARCH: armv8.2-a+crypto+fp16+dotprod TAG: arm64 PLATFORM: arm64 diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index fe5ed3e64a..df7a47e7d9 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -58,7 +58,7 @@ build trx driver: rm -Rf build mkdir build cd build - cmake -DENABLE_TRX_DRIVER=True -DTRX_DRIVER_DIR=${CI_PROJECT_DIR}/amarisoft/trx_uhd-linux -DENABLE_EXPORT=True -DENABLE_UHD=False -DENABLE_ZEROMQ=True -DARCH=x86-64-v3 .. + cmake -DENABLE_TRX_DRIVER=True -DTRX_DRIVER_DIR=${CI_PROJECT_DIR}/amarisoft/trx_uhd-linux -DENABLE_EXPORT=True -DENABLE_UHD=False -DENABLE_ZEROMQ=True -DMARCH=x86-64-v3 .. make -j${KUBERNETES_CPU_REQUEST} trx_srsran_test } - | diff --git a/.gitlab/run_viavi_pipeline.py b/.gitlab/run_viavi_pipeline.py index 483733404e..2612f9c97b 100644 --- a/.gitlab/run_viavi_pipeline.py +++ b/.gitlab/run_viavi_pipeline.py @@ -53,7 +53,7 @@ def main(): TESTMODE = "none" MAKE_ARGS = "-j6" - BUILD_ARGS = '-DCMAKE_BUILD_TYPE=Release -DFORCE_DEBUG_INFO=True -DENABLE_UHD=False -DENABLE_DPDK=True -DENABLE_ZEROMQ=False -DARCH="x86-64-v4"' + BUILD_ARGS = '-DCMAKE_BUILD_TYPE=Release -DFORCE_DEBUG_INFO=True -DENABLE_UHD=False -DENABLE_DPDK=True -DENABLE_ZEROMQ=False -DMARCH="x86-64-v4"' DPDK_VERSION = "23.11_avx512" TESTBED = "viavi" diff --git a/docker/Dockerfile b/docker/Dockerfile index bf905dff72..966d09e63a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -11,14 +11,14 @@ # OS_VERSION Ubuntu OS version # LIB uhd or dpdk (lowercase) # LIB_VERSION UHD or DPDK version number -# ARCH gcc/clang compatible arch +# MARCH gcc/clang compatible arch # NUM_CORES Number or empty for all # EXTRA_CMAKE_ARGS Extra flags for srsRAN Project ARG OS_VERSION=24.04 ARG LIB=uhd ARG LIB_VERSION=4.6.0.0 -ARG ARCH=native +ARG MARCH=native ARG NUM_CORES="" ################## @@ -38,11 +38,11 @@ RUN /src/docker/scripts/install_dependencies.sh build && \ /src/docker/scripts/install_${LIB}_dependencies.sh build ARG LIB_VERSION -ARG ARCH +ARG MARCH ARG NUM_CORES # Compile UHD/DPDK -RUN /src/docker/scripts/build_${LIB}.sh ${LIB_VERSION} ${ARCH} ${NUM_CORES} +RUN /src/docker/scripts/build_${LIB}.sh ${LIB_VERSION} ${MARCH} ${NUM_CORES} # Compile srsRAN Project and install it in the OS ARG EXTRA_CMAKE_ARGS="" @@ -53,7 +53,7 @@ RUN if [ -z "$NUM_CORES" ]; then NUM_CORES=$(nproc); fi && \ -m "-j${NUM_CORES} install" \ -DBUILD_TESTS=True \ -DENABLE_${LIB_UPPER}=On \ - -DARCH=${ARCH} \ + -DMARCH=${MARCH} \ -DCMAKE_INSTALL_PREFIX=/opt/srs \ ${EXTRA_CMAKE_ARGS} /src From 82736988734580a70b9a753c3be7f951fd561b95 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 22 Jul 2024 15:40:48 +0200 Subject: [PATCH 039/407] phy: integrate transform precoding in PUSCH processor phy: integrate transform precoding in PUSCH processor --- .../channel_processors/pusch/formatters.h | 15 +- .../pusch/pusch_processor.h | 51 ++- .../signal_processors/dmrs_pusch_estimator.h | 51 ++- .../signal_processor_factories.h | 7 +- lib/fapi_adaptor/phy/messages/pusch.cpp | 21 +- .../pusch/pusch_processor_impl.cpp | 70 +++- .../pusch/pusch_processor_validator_impl.cpp | 36 +- .../low_papr_sequence_generator_impl.cpp | 46 ++- .../low_papr_sequence_generator_impl.h | 5 + .../dmrs_pusch_estimator_impl.cpp | 44 +- .../dmrs_pusch_estimator_impl.h | 11 +- .../signal_processor_factories.cpp | 29 +- lib/phy/upper/upper_phy_factories.cpp | 12 +- .../pusch/pusch_processor_benchmark.cpp | 23 +- .../channel_processors/pxsch_bler_test.cpp | 44 +- .../pxsch_bler_test_factories.cpp | 8 +- .../phy/messages/ul_pusch_pdu_test.cpp | 18 +- .../pusch/pusch_processor_test_data.h | 56 +-- .../pusch/pusch_processor_test_data.tar.gz | 4 +- .../pusch/pusch_processor_unittest.cpp | 48 ++- .../pusch/pusch_processor_validator_test.cpp | 81 ++-- .../pusch/pusch_processor_vectortest.cpp | 8 +- .../dmrs_pusch_estimator_test.cpp | 31 +- .../dmrs_pusch_estimator_test_data.h | 386 +++++++++--------- .../dmrs_pusch_estimator_test_data.tar.gz | 4 +- 25 files changed, 672 insertions(+), 437 deletions(-) diff --git a/include/srsran/phy/upper/channel_processors/pusch/formatters.h b/include/srsran/phy/upper/channel_processors/pusch/formatters.h index 85e135bc63..2d9a2c5629 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/formatters.h +++ b/include/srsran/phy/upper/channel_processors/pusch/formatters.h @@ -143,10 +143,6 @@ struct formatter { helper.format_if_verbose(ctx, "n_id={}", pdu.n_id); helper.format_if_verbose(ctx, "dmrs_mask={}", pdu.dmrs_symbol_mask); - helper.format_if_verbose(ctx, "n_scr_id={}", pdu.scrambling_id); - helper.format_if_verbose(ctx, "n_scid={}", pdu.n_scid); - helper.format_if_verbose(ctx, "n_cdm_g_wd={}", pdu.nof_cdm_groups_without_data); - helper.format_if_verbose(ctx, "dmrs_type={}", (pdu.dmrs == srsran::dmrs_type::TYPE1) ? 1 : 2); helper.format_if_verbose(ctx, "tbs_lbrm={}bytes", pdu.tbs_lbrm); helper.format_if_verbose(ctx, "slot={}", pdu.slot); helper.format_if_verbose(ctx, "cp={}", pdu.cp.to_string()); @@ -154,6 +150,17 @@ struct formatter { helper.format_if_verbose(ctx, "ports={}", srsran::span(pdu.rx_ports)); helper.format_if_verbose(ctx, "dc_position={}", pdu.dc_position); + if (std::holds_alternative(pdu.dmrs)) { + const auto& dmrs_config = std::get(pdu.dmrs); + helper.format_if_verbose(ctx, "n_scr_id={}", dmrs_config.scrambling_id); + helper.format_if_verbose(ctx, "n_scid={}", dmrs_config.n_scid); + helper.format_if_verbose(ctx, "n_cdm_g_wd={}", dmrs_config.nof_cdm_groups_without_data); + helper.format_if_verbose(ctx, "dmrs_type={}", (dmrs_config.dmrs == srsran::dmrs_type::TYPE1) ? 1 : 2); + } else { + const auto& dmrs_config = std::get(pdu.dmrs); + helper.format_if_verbose(ctx, "n_rs_id={}", dmrs_config.n_rs_id); + } + return ctx.out(); } }; diff --git a/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h b/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h index b360c18639..0918e3402a 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h +++ b/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h @@ -21,6 +21,7 @@ #include "srsran/ran/slot_point.h" #include "srsran/ran/uci/uci_constants.h" #include "srsran/ran/uci/uci_part2_size_description.h" +#include namespace srsran { @@ -69,6 +70,37 @@ class pusch_processor float beta_offset_csi_part2; }; + /// Collects the DM-RS parameters. + struct dmrs_configuration { + /// Indicates the DMRS type. + dmrs_type dmrs; + /// \brief Parameter \f$N^{n_{SCID}}_{ID}\f$ TS 38.211 section 6.4.1.1.1. + /// + /// It is equal to: + /// - {0,1, … ,65535} given by the higher-layer parameters scramblingID0 and scramblingID1, + /// - \f$N^{cell}_{ID}\f$ otherwise. + unsigned scrambling_id; + /// \brief Parameter \f$n_{SCID}\f$ from TS 38.211 section 6.4.1.1.1. + /// + /// It is equal to: + /// - \c true or \c false according DM-RS sequence initialization field, in the DCI associated with the PUSCH + /// transmission if DCI format 0_1 is used, + /// - \c false otherwise. + bool n_scid; + /// Number of DMRS CDM groups without data. + unsigned nof_cdm_groups_without_data; + }; + + /// Collects the DM-RS parameters when transform precoding is enabled. + struct dmrs_transform_precoding_configuration { + /// \brief Parameter \f$n^{RS}_{ID}\f$ TS 38.211 section 6.4.1.1.2. + /// + /// It is equal to: + /// - {0,1, … ,1007} given by the higher-layer parameters nPUSCH-Identity, or + /// - \f$N^{cell}_{ID}\f$. + unsigned n_rs_id; + }; + /// \brief Describes the PUSCH processing parameters. /// /// For a valid PUSCH transmission the codeword, the UCI information or both must be present. @@ -103,23 +135,8 @@ class pusch_processor static_vector rx_ports; /// Indicates which symbol in the slot transmit DMRS. symbol_slot_mask dmrs_symbol_mask; - /// Indicates the DMRS type. - dmrs_type dmrs; - /// \brief Parameter \f$N^{n_{SCID}}_{ID}\f$ TS 38.211 section 6.4.1.1.1. - /// - /// It is equal to: - /// - {0,1, … ,65535} given by the higher-layer parameters scramblingID0 and scramblingID1, - /// - \f$N^{cell}_{ID}\f$ otherwise. - unsigned scrambling_id; - /// \brief Parameter \f$n_{SCID}\f$ from TS 38.211 section 6.4.1.1.1. - /// - /// It is equal to: - /// - \c true or \c false according DM-RS sequence initialization field, in the DCI associated with the PUSCH - /// transmission if DCI format 0_1 is used, - /// - \c false otherwise. - bool n_scid; - /// Number of DMRS CDM groups without data. - unsigned nof_cdm_groups_without_data; + /// DM-RS configuration. + std::variant dmrs; /// Frequency domain allocation. rb_allocation freq_alloc; /// Time domain allocation start symbol index (0...12). diff --git a/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h b/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h index 673e5277d1..84c0125b75 100644 --- a/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h +++ b/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h @@ -19,6 +19,7 @@ #include "srsran/ran/cyclic_prefix.h" #include "srsran/ran/slot_point.h" #include "srsran/ran/subcarrier_spacing.h" +#include namespace srsran { @@ -28,16 +29,30 @@ class resource_grid_reader; class dmrs_pusch_estimator { public: - /// Parameters required to receive the demodulation reference signals described in 3GPP TS38.211 Section 6.4.1.1. - struct configuration { - /// Slot context for sequence initialization. - slot_point slot; + /// Parameters for pseudo-random sequence. + struct pseudo_random_sequence_configuration { /// DL DM-RS configuration type. dmrs_type type; + /// Number of transmit layers. + unsigned nof_tx_layers; /// PUSCH DM-RS scrambling ID. unsigned scrambling_id; /// DM-RS sequence initialization (parameter \f$n_{SCID}\f$ in the TS). bool n_scid; + }; + + /// Parameters for pseudo-random sequence. + struct low_papr_sequence_configuration { + /// Reference signal sequence identifier [0..1007]. + unsigned n_rs_id; + }; + + /// Parameters required to receive the demodulation reference signals described in 3GPP TS38.211 Section 6.4.1.1. + struct configuration { + /// Slot context for sequence initialization. + slot_point slot; + /// Sequence generator configuration. + std::variant sequence_config; /// \brif DM-RS amplitude scaling factor. /// /// Parameter \f$\beta _{\textup{PUSCH}}^{\textup{DMRS}}\f$ as per TS38.211 Section 6.4.1.1.3. It must be set @@ -57,10 +72,34 @@ class dmrs_pusch_estimator unsigned first_symbol = 0; /// Number of OFDM symbols for which the channel should be estimated. unsigned nof_symbols = 0; - /// Number of transmit layers. - unsigned nof_tx_layers = 0; /// List of receive ports. static_vector rx_ports; + + /// \brief Gets the number of transmit layers. + /// + /// The number of transmit layers when low-PAPR sequences are used is always one. Otherwise, it is given in the + /// sequence configuration. + unsigned get_nof_tx_layers() const + { + if (std::holds_alternative(sequence_config)) { + return std::get(sequence_config).nof_tx_layers; + } + + return 1; + } + + /// \brief Gets the DM-RS type. + /// + /// The DM-RS type is always 1 when low-PAPR sequences are used. Otherwise, it is given in the sequence + /// configuration. + dmrs_type get_dmrs_type() const + { + if (std::holds_alternative(sequence_config)) { + return std::get(sequence_config).type; + } + + return dmrs_type::TYPE1; + } }; /// Default destructor. diff --git a/include/srsran/phy/upper/signal_processors/signal_processor_factories.h b/include/srsran/phy/upper/signal_processors/signal_processor_factories.h index 39727e3622..b868ab2168 100644 --- a/include/srsran/phy/upper/signal_processors/signal_processor_factories.h +++ b/include/srsran/phy/upper/signal_processors/signal_processor_factories.h @@ -69,9 +69,10 @@ class dmrs_pusch_estimator_factory virtual std::unique_ptr create() = 0; }; -std::shared_ptr -create_dmrs_pusch_estimator_factory_sw(std::shared_ptr prg_factory, - std::shared_ptr ch_estimator_factory); +std::shared_ptr create_dmrs_pusch_estimator_factory_sw( + std::shared_ptr prg_factory, + std::shared_ptr low_papr_sequence_gen_factory, + std::shared_ptr ch_estimator_factory); class nzp_csi_rs_generator_factory { diff --git a/lib/fapi_adaptor/phy/messages/pusch.cpp b/lib/fapi_adaptor/phy/messages/pusch.cpp index fdb570371d..0f2fb9b7ba 100644 --- a/lib/fapi_adaptor/phy/messages/pusch.cpp +++ b/lib/fapi_adaptor/phy/messages/pusch.cpp @@ -121,14 +121,19 @@ void srsran::fapi_adaptor::convert_pusch_fapi_to_phy(uplink_processor::pusch_pdu proc_pdu.dmrs_symbol_mask.set(i, ((static_cast(fapi_pdu.ul_dmrs_symb_pos >> i) & 1U) == 1U)); } - proc_pdu.dmrs = - fapi_pdu.dmrs_type == fapi::dmrs_cfg_type::type_1 ? dmrs_type::options::TYPE1 : dmrs_type::options::TYPE2; - proc_pdu.scrambling_id = fapi_pdu.pusch_dmrs_scrambling_id; - proc_pdu.n_scid = fapi_pdu.nscid; - proc_pdu.nof_cdm_groups_without_data = fapi_pdu.num_dmrs_cdm_grps_no_data; - proc_pdu.start_symbol_index = fapi_pdu.start_symbol_index; - proc_pdu.nof_symbols = fapi_pdu.nr_of_symbols; - proc_pdu.tbs_lbrm = fapi_pdu.pusch_maintenance_v3.tb_size_lbrm_bytes; + if (fapi_pdu.transform_precoding) { + proc_pdu.dmrs = pusch_processor::dmrs_transform_precoding_configuration{.n_rs_id = fapi_pdu.pusch_dmrs_identity}; + } else { + proc_pdu.dmrs = pusch_processor::dmrs_configuration{ + .dmrs = + fapi_pdu.dmrs_type == fapi::dmrs_cfg_type::type_1 ? dmrs_type::options::TYPE1 : dmrs_type::options::TYPE2, + .scrambling_id = fapi_pdu.pusch_dmrs_scrambling_id, + .n_scid = (fapi_pdu.nscid != 0), + .nof_cdm_groups_without_data = fapi_pdu.num_dmrs_cdm_grps_no_data}; + } + proc_pdu.start_symbol_index = fapi_pdu.start_symbol_index; + proc_pdu.nof_symbols = fapi_pdu.nr_of_symbols; + proc_pdu.tbs_lbrm = fapi_pdu.pusch_maintenance_v3.tb_size_lbrm_bytes; if (fapi_pdu.tx_direct_current_location < 3300) { proc_pdu.dc_position = static_cast(fapi_pdu.tx_direct_current_location); diff --git a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp index 76cf4b2d68..c4d7b848cd 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp @@ -11,11 +11,13 @@ #include "pusch_processor_impl.h" #include "pusch_decoder_buffer_dummy.h" #include "pusch_processor_notifier_adaptor.h" +#include "srsran/phy/upper/channel_processors/pusch/formatters.h" #include "srsran/phy/upper/channel_processors/pusch/pusch_codeword_buffer.h" #include "srsran/phy/upper/channel_processors/pusch/pusch_decoder_buffer.h" #include "srsran/phy/upper/unique_rx_buffer.h" #include "srsran/ran/pusch/ulsch_info.h" #include "srsran/ran/sch/sch_dmrs_power.h" +#include "srsran/ran/transform_precoding/transform_precoding_helpers.h" #include "srsran/ran/uci/uci_formatters.h" #include "srsran/ran/uci/uci_part2_size_calculator.h" @@ -130,6 +132,24 @@ void pusch_processor_impl::process(span data, overlap_dc = rb_mask.test(dc_position_prb); } + bool enable_transform_precoding = false; + unsigned scrambling_id = 0; + unsigned n_rs_id = 0; + bool n_scid = 0; + unsigned nof_cdm_groups_without_data = 2; + dmrs_type dmrs_type = srsran::dmrs_type::TYPE1; + if (std::holds_alternative(pdu.dmrs)) { + const auto& dmrs_config = std::get(pdu.dmrs); + scrambling_id = dmrs_config.scrambling_id; + n_scid = dmrs_config.n_scid; + nof_cdm_groups_without_data = dmrs_config.nof_cdm_groups_without_data; + dmrs_type = dmrs_config.dmrs; + } else { + const auto& dmrs_config = std::get(pdu.dmrs); + enable_transform_precoding = true; + n_rs_id = dmrs_config.n_rs_id; + } + // Get UL-SCH information as if there was no CSI Part 2 in the PUSCH. ulsch_configuration ulsch_config; ulsch_config.tbs = units::bytes(data.size()).to_bits(); @@ -144,26 +164,28 @@ void pusch_processor_impl::process(span data, ulsch_config.nof_rb = nof_rb; ulsch_config.start_symbol_index = pdu.start_symbol_index; ulsch_config.nof_symbols = pdu.nof_symbols; - ulsch_config.dmrs_type = pdu.dmrs == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2; - ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; - ulsch_config.nof_cdm_groups_without_data = pdu.nof_cdm_groups_without_data; + ulsch_config.dmrs_type = dmrs_type == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2; + ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; + ulsch_config.nof_cdm_groups_without_data = nof_cdm_groups_without_data; ulsch_config.nof_layers = pdu.nof_tx_layers; ulsch_config.contains_dc = overlap_dc; ulsch_information info = get_ulsch_information(ulsch_config); // Estimate channel. dmrs_pusch_estimator::configuration ch_est_config; - ch_est_config.slot = pdu.slot; - ch_est_config.type = pdu.dmrs; - ch_est_config.scrambling_id = pdu.scrambling_id; - ch_est_config.n_scid = pdu.n_scid; - ch_est_config.scaling = convert_dB_to_amplitude(-get_sch_to_dmrs_ratio_dB(pdu.nof_cdm_groups_without_data)); - ch_est_config.c_prefix = pdu.cp; - ch_est_config.symbols_mask = pdu.dmrs_symbol_mask; - ch_est_config.rb_mask = rb_mask; - ch_est_config.first_symbol = pdu.start_symbol_index; - ch_est_config.nof_symbols = pdu.nof_symbols; - ch_est_config.nof_tx_layers = pdu.nof_tx_layers; + ch_est_config.slot = pdu.slot; + if (enable_transform_precoding) { + ch_est_config.sequence_config = dmrs_pusch_estimator::low_papr_sequence_configuration{.n_rs_id = n_rs_id}; + } else { + ch_est_config.sequence_config = dmrs_pusch_estimator::pseudo_random_sequence_configuration{ + .type = dmrs_type, .nof_tx_layers = pdu.nof_tx_layers, .scrambling_id = scrambling_id, .n_scid = n_scid}; + } + ch_est_config.scaling = convert_dB_to_amplitude(-get_sch_to_dmrs_ratio_dB(nof_cdm_groups_without_data)); + ch_est_config.c_prefix = pdu.cp; + ch_est_config.symbols_mask = pdu.dmrs_symbol_mask; + ch_est_config.rb_mask = rb_mask; + ch_est_config.first_symbol = pdu.start_symbol_index; + ch_est_config.nof_symbols = pdu.nof_symbols; ch_est_config.rx_ports.assign(pdu.rx_ports.begin(), pdu.rx_ports.end()); dependencies.get_estimator().estimate(ch_estimate, grid, ch_est_config); @@ -197,7 +219,7 @@ void pusch_processor_impl::process(span data, demux_config.start_symbol_index = pdu.start_symbol_index; demux_config.nof_symbols = pdu.nof_symbols; demux_config.nof_harq_ack_rvd = info.nof_harq_ack_rvd.value(); - demux_config.dmrs = pdu.dmrs; + demux_config.dmrs = dmrs_type; demux_config.dmrs_symbol_mask = ulsch_config.dmrs_symbol_mask; demux_config.nof_cdm_groups_without_data = ulsch_config.nof_cdm_groups_without_data; demux_config.nof_harq_ack_bits = ulsch_config.nof_harq_ack_bits.value(); @@ -275,11 +297,11 @@ void pusch_processor_impl::process(span data, demod_config.start_symbol_index = pdu.start_symbol_index; demod_config.nof_symbols = pdu.nof_symbols; demod_config.dmrs_symb_pos = pdu.dmrs_symbol_mask; - demod_config.dmrs_config_type = pdu.dmrs; - demod_config.nof_cdm_groups_without_data = pdu.nof_cdm_groups_without_data; + demod_config.dmrs_config_type = dmrs_type; + demod_config.nof_cdm_groups_without_data = nof_cdm_groups_without_data; demod_config.n_id = pdu.n_id; demod_config.nof_tx_layers = pdu.nof_tx_layers; - demod_config.enable_transform_precoding = false; + demod_config.enable_transform_precoding = enable_transform_precoding; demod_config.rx_ports = pdu.rx_ports; dependencies.get_demodulator().demodulate( demodulator_buffer, notifier_adaptor.get_demodulator_notifier(), grid, ch_estimate, demod_config); @@ -296,8 +318,16 @@ void pusch_processor_impl::assert_pdu(const pusch_processor::pdu_t& pdu, const c pdu.bwp_start_rb, pdu.bwp_size_rb, ch_estimate.capacity().nof_prb); - srsran_assert(pdu.dmrs == dmrs_type::TYPE1, "Only DM-RS Type 1 is currently supported."); - srsran_assert(pdu.nof_cdm_groups_without_data == 2, "Only two CDM groups without data are currently supported."); + if (std::holds_alternative(pdu.dmrs)) { + const auto& dmrs = std::get(pdu.dmrs); + srsran_assert(dmrs.dmrs == dmrs_type::TYPE1, "Only DM-RS Type 1 is currently supported."); + srsran_assert(dmrs.nof_cdm_groups_without_data == 2, "Only two CDM groups without data are currently supported."); + } else { + srsran_assert(pdu.nof_tx_layers == 1, "Transform precoding is only possible with one layer."); + srsran_assert(pdu.freq_alloc.is_contiguous(), "Transform precoding is only possible with contiguous allocations."); + srsran_assert(is_transform_precoding_nof_prb_valid(pdu.freq_alloc.get_nof_rb()), + "Transform precoding is only possible with a valid number of PRB."); + } srsran_assert(nof_tx_layers_range.contains(pdu.nof_tx_layers), "The number of transmit layers (i.e., {}) is out of the range {}.", pdu.nof_tx_layers, diff --git a/lib/phy/upper/channel_processors/pusch/pusch_processor_validator_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_processor_validator_impl.cpp index 7b31068645..3475b8f45c 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_processor_validator_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_processor_validator_impl.cpp @@ -10,6 +10,7 @@ #include "pusch_processor_validator_impl.h" #include "pusch_processor_impl.h" +#include "srsran/ran/transform_precoding/transform_precoding_helpers.h" using namespace srsran; @@ -105,14 +106,33 @@ bool pusch_processor_validator_impl::is_valid(const pusch_processor::pdu_t& pdu) return false; } - // Only DM-RS Type 1 is supported. - if (pdu.dmrs != dmrs_type::TYPE1) { - return false; - } - - // Only two CDM groups without data is supported. - if (pdu.nof_cdm_groups_without_data != 2) { - return false; + // Check if transform precoding is enabled. + if (std::holds_alternative(pdu.dmrs)) { + const pusch_processor::dmrs_configuration& dmrs_config = std::get(pdu.dmrs); + // Only DM-RS Type 1 is supported. + if (dmrs_config.dmrs != dmrs_type::TYPE1) { + return false; + } + + // Only two CDM groups without data is supported. + if (dmrs_config.nof_cdm_groups_without_data != 2) { + return false; + } + } else { + // Number of layers must be one. + if (pdu.nof_tx_layers != 1) { + return false; + } + + // Frequency allocation must be contiguous. + if (!pdu.freq_alloc.is_contiguous()) { + return false; + } + + // Number of PRB must be valid. + if (!is_transform_precoding_nof_prb_valid(pdu.freq_alloc.get_nof_rb())) { + return false; + } } // DC position is outside the channel estimate dimensions. diff --git a/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.cpp b/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.cpp index 2f04c3b8ec..b5dd5d8783 100644 --- a/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.cpp +++ b/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.cpp @@ -18,11 +18,13 @@ using namespace srsran; -// Sequence sizes used in PUCCH Format 1 and SRS. +// Sequence sizes used in PUCCH Format 1, SRS and PUSCH with transform precoding. const std::set low_papr_sequence_generator_impl::sequence_sizes = { - 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 204, 216, 228, 240, - 252, 264, 276, 288, 312, 324, 336, 360, 384, 396, 408, 432, 456, 480, 504, 528, 552, 576, 624, 648, - 672, 720, 768, 792, 816, 864, 912, 960, 1008, 1056, 1104, 1152, 1248, 1296, 1344, 1440, 1536, 1584, 1632}; + 6, 12, 18, 24, 30, 36, 48, 54, 60, 72, 84, 90, 96, 108, 120, 132, 144, + 150, 156, 162, 168, 180, 192, 204, 216, 228, 240, 252, 264, 270, 276, 288, 300, 312, + 324, 336, 360, 384, 396, 408, 432, 450, 456, 480, 486, 504, 528, 540, 552, 576, 600, + 624, 648, 672, 720, 750, 768, 792, 810, 816, 864, 900, 912, 960, 972, 1008, 1056, 1080, + 1104, 1152, 1200, 1248, 1296, 1344, 1350, 1440, 1458, 1500, 1536, 1584, 1620, 1632}; const std::array, low_papr_sequence_generator_impl::NOF_ZC_SEQ> low_papr_sequence_generator_impl::phi_M_sc_6 = { @@ -140,9 +142,25 @@ static unsigned get_N_zc(unsigned M_zc) return prime_lower_than(M_zc); } + if (M_zc == 30) { + return 31; + } + return 4; } +span low_papr_sequence_generator_impl::phi_M_sc_30(unsigned u) +{ + static constexpr unsigned M_zc = 30; + static constexpr unsigned N_zc = 31; + span r_uv_arg = span(temp_r_uv_arg).first(30); + for (unsigned n = 0; n != M_zc; ++n) { + r_uv_arg[n] = -static_cast(((u + 1L) * (n + 1L) * (n + 2L)) % (2 * N_zc)); + } + + return r_uv_arg; +} + span low_papr_sequence_generator_impl::r_uv_arg_mprb(unsigned u, unsigned v, unsigned M_zc) { // Select temporary argument. @@ -165,13 +183,25 @@ span low_papr_sequence_generator_impl::r_uv_arg(unsigned u, unsigned { if (M_zc == 6) { return phi_M_sc_6[u]; - } else if (M_zc == 12) { + } + + if (M_zc == 12) { return phi_M_sc_12[u]; - } else if (M_zc == 18) { + } + + if (M_zc == 18) { return phi_M_sc_18[u]; - } else if (M_zc == 24) { + } + + if (M_zc == 24) { return phi_M_sc_24[u]; - } else if (M_zc >= 36) { + } + + if (M_zc == 30) { + return phi_M_sc_30(u); + } + + if (M_zc >= 36) { return r_uv_arg_mprb(u, v, M_zc); } diff --git a/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h b/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h index bb93938ee9..817f75f2c4 100644 --- a/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h +++ b/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h @@ -48,6 +48,11 @@ class low_papr_sequence_generator_impl : public low_papr_sequence_generator /// Defines Phi values for M_sc=24 Table 5.2.2.2-4 in TS 38.211. static const std::array, NOF_ZC_SEQ> phi_M_sc_24; + /// \brief Gets argument for the sequence \f$r^{(\alpha, \beta)}_{u,v}(n)\f$ for base sequences of length 30. + /// + /// \param[in] u Sequence group index {0, 29}. + span phi_M_sc_30(unsigned u); + /// \brief Gets argument for the sequence \f$r^{(\alpha, \beta)}_{u,v}(n)\f$ for base sequences of length 36 or /// larger. /// diff --git a/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.cpp b/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.cpp index 33e0bf5690..570191ce3a 100644 --- a/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.cpp +++ b/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.cpp @@ -60,15 +60,16 @@ void dmrs_pusch_estimator_impl::estimate(channel_estimate& estimate, const resource_grid_reader& grid, const configuration& config) { - unsigned nof_tx_layers = config.nof_tx_layers; - unsigned nof_rx_ports = config.rx_ports.size(); + dmrs_type type = config.get_dmrs_type(); + unsigned nof_tx_layers = config.get_nof_tx_layers(); + unsigned nof_rx_ports = config.rx_ports.size(); // Select the DM-RS pattern for this PUSCH transmission. span coordinates = span(temp_pattern).first(nof_tx_layers); // Prepare DM-RS symbol buffer dimensions. re_measurement_dimensions dims; - dims.nof_subc = config.rb_mask.count() * config.type.nof_dmrs_per_rb(); + dims.nof_subc = config.rb_mask.count() * type.nof_dmrs_per_rb(); dims.nof_symbols = config.symbols_mask.count(); dims.nof_slices = nof_tx_layers; @@ -101,13 +102,24 @@ void dmrs_pusch_estimator_impl::sequence_generation(span sequenc unsigned symbol, const configuration& config) const { + // Generate low-PAPR sequence. + if (std::holds_alternative(config.sequence_config)) { + const auto& sequence_config = std::get(config.sequence_config); + unsigned sequence_group = sequence_config.n_rs_id % 30; + low_paper_sequence_gen->generate(sequence, sequence_group, 0, 0, 1); + return; + } + + // Generate pseudo-random sequence. + const auto& sequence_config = std::get(config.sequence_config); + // Get signal amplitude. float amplitude = M_SQRT1_2; // Extract parameters to calculate the PRG initial state. unsigned nslot = config.slot.slot_index(); - unsigned nidnscid = config.scrambling_id; - unsigned nscid = config.n_scid ? 1 : 0; + unsigned nidnscid = sequence_config.scrambling_id; + unsigned nscid = sequence_config.n_scid ? 1 : 0; unsigned nsymb = get_nsymb_per_slot(cyclic_prefix::NORMAL); // Calculate initial sequence state. @@ -118,13 +130,16 @@ void dmrs_pusch_estimator_impl::sequence_generation(span sequenc // Generate sequence. dmrs_sequence_generate( - sequence, *prg, amplitude, DMRS_REF_POINT_K_TO_POINT_A, config.type.nof_dmrs_per_rb(), config.rb_mask); + sequence, *prg, amplitude, DMRS_REF_POINT_K_TO_POINT_A, sequence_config.type.nof_dmrs_per_rb(), config.rb_mask); } void dmrs_pusch_estimator_impl::generate(dmrs_symbol_list& symbols, span mask, const configuration& cfg) { + dmrs_type type = cfg.get_dmrs_type(); + unsigned nof_tx_layers = cfg.get_nof_tx_layers(); + // For each symbol in the transmission generate DMRS for layer 0. for (unsigned ofdm_symbol_index = cfg.first_symbol, ofdm_symbol_end = cfg.first_symbol + cfg.nof_symbols, @@ -136,19 +151,6 @@ void dmrs_pusch_estimator_impl::generate(dmrs_symbol_list& symbols, continue; } - // Extract parameters to calculate the PRG initial state. - unsigned nslot = cfg.slot.slot_index(); - unsigned nidnscid = cfg.scrambling_id; - unsigned nscid = cfg.n_scid ? 1 : 0; - unsigned nsymb = get_nsymb_per_slot(cyclic_prefix::NORMAL); - - // Calculate initial sequence state. - unsigned c_init = - ((nsymb * nslot + ofdm_symbol_index + 1) * (2 * nidnscid + 1) * pow2(17) + (2 * nidnscid + nscid)) % pow2(31); - - // Initialize sequence. - prg->init(c_init); - // Select a view to the DM-RS symbols for this OFDM symbol and layer 0. span dmrs_symbols = symbols.get_symbol(dmrs_symbol_index, 0); @@ -160,9 +162,9 @@ void dmrs_pusch_estimator_impl::generate(dmrs_symbol_list& symbols, } // For each layer... - for (unsigned i_layer = 0; i_layer != cfg.nof_tx_layers; ++i_layer) { + for (unsigned i_layer = 0; i_layer != nof_tx_layers; ++i_layer) { // Select layer parameters. - const parameters& params = (cfg.type == dmrs_type::TYPE1) ? params_type1[i_layer] : params_type2[i_layer]; + const parameters& params = (type == dmrs_type::TYPE1) ? params_type1[i_layer] : params_type2[i_layer]; // Skip copy for layer 0. if (i_layer != 0) { diff --git a/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.h b/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.h index 096e830e5e..9b74a7b756 100644 --- a/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.h +++ b/lib/phy/upper/signal_processors/dmrs_pusch_estimator_impl.h @@ -13,6 +13,7 @@ #pragma once +#include "srsran/phy/upper/sequence_generators/low_papr_sequence_generator.h" #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" #include "srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h" #include "srsran/phy/upper/signal_processors/port_channel_estimator.h" @@ -25,11 +26,13 @@ class dmrs_pusch_estimator_impl : public dmrs_pusch_estimator using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; /// Constructor - sets the channel estimator. - explicit dmrs_pusch_estimator_impl(std::unique_ptr prg_, - std::unique_ptr ch_est) : - prg(std::move(prg_)), ch_estimator(std::move(ch_est)) + explicit dmrs_pusch_estimator_impl(std::unique_ptr prg_, + std::unique_ptr tp_sequence_generator_, + std::unique_ptr ch_est) : + prg(std::move(prg_)), low_paper_sequence_gen(std::move(tp_sequence_generator_)), ch_estimator(std::move(ch_est)) { srsran_assert(prg, "Invalid PRG."); + srsran_assert(low_paper_sequence_gen, "Invalid sequence generator."); srsran_assert(ch_estimator, "Invalid port channel estimator."); } @@ -57,6 +60,8 @@ class dmrs_pusch_estimator_impl : public dmrs_pusch_estimator /// Pseudo-random generator. std::unique_ptr prg; + /// Sequence generator for transform precoding. + std::unique_ptr low_paper_sequence_gen; /// Antenna port channel estimator. std::unique_ptr ch_estimator; /// Buffer for DM-RS symbols. diff --git a/lib/phy/upper/signal_processors/signal_processor_factories.cpp b/lib/phy/upper/signal_processors/signal_processor_factories.cpp index 2d37af1014..a57a2c89b9 100644 --- a/lib/phy/upper/signal_processors/signal_processor_factories.cpp +++ b/lib/phy/upper/signal_processors/signal_processor_factories.cpp @@ -129,23 +129,30 @@ class dmrs_pucch_estimator_sw_factory : public dmrs_pucch_estimator_factory class dmrs_pusch_estimator_factory_sw : public dmrs_pusch_estimator_factory { public: - dmrs_pusch_estimator_factory_sw(std::shared_ptr prg_factory_, - std::shared_ptr ch_estimator_factory_) : - prg_factory(std::move(prg_factory_)), ch_estimator_factory(std::move(ch_estimator_factory_)) + dmrs_pusch_estimator_factory_sw(std::shared_ptr prg_factory_, + std::shared_ptr low_papr_gen_factory_, + std::shared_ptr ch_estimator_factory_) : + prg_factory(std::move(prg_factory_)), + low_papr_gen_factory(std::move(low_papr_gen_factory_)), + ch_estimator_factory(std::move(ch_estimator_factory_)) { srsran_assert(prg_factory, "Invalid PRG factory."); + srsran_assert(low_papr_gen_factory, "Invalid low-PAPR generator factory."); srsran_assert(ch_estimator_factory, "Invalid channel estimator factory."); } std::unique_ptr create() override { return std::make_unique( - prg_factory->create(), ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::filter)); + prg_factory->create(), + low_papr_gen_factory->create(), + ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::filter)); } private: - std::shared_ptr prg_factory; - std::shared_ptr ch_estimator_factory; + std::shared_ptr prg_factory; + std::shared_ptr low_papr_gen_factory; + std::shared_ptr ch_estimator_factory; }; class nzp_csi_rs_generator_factory_sw : public nzp_csi_rs_generator_factory @@ -283,11 +290,13 @@ srsran::create_dmrs_pucch_estimator_factory_sw(std::shared_ptr(prg_factory, lpc_factory, ch_estimator_factory); } -std::shared_ptr -srsran::create_dmrs_pusch_estimator_factory_sw(std::shared_ptr prg_factory, - std::shared_ptr ch_estimator_factory) +std::shared_ptr srsran::create_dmrs_pusch_estimator_factory_sw( + std::shared_ptr prg_factory, + std::shared_ptr low_papr_sequence_gen_factory, + std::shared_ptr ch_estimator_factory) { - return std::make_shared(std::move(prg_factory), std::move(ch_estimator_factory)); + return std::make_shared( + std::move(prg_factory), std::move(low_papr_sequence_gen_factory), std::move(ch_estimator_factory)); } std::shared_ptr diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 8c6d4fae45..6dd57b19bd 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -370,8 +370,15 @@ static std::shared_ptr create_ul_processor_factory(con report_fatal_error_if_not(ta_estimator_factory, "Invalid TA estimator factory."); std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); - std::shared_ptr ch_estimator_factory = + report_error_if_not(prg_factory, "Invalid pseudo-random sequence generator factory."); + + std::shared_ptr ch_estimator_factory = create_port_channel_estimator_factory_sw(ta_estimator_factory); + report_error_if_not(prg_factory, "Invalid channel estimator factory."); + + std::shared_ptr low_papr_sequence_gen_factory = + create_low_papr_sequence_generator_sw_factory(); + report_error_if_not(low_papr_sequence_gen_factory, "Invalid low-PAPR sequence generator factory."); std::shared_ptr equalizer_factory = create_channel_equalizer_generic_factory(); report_error_if_not(equalizer_factory, "Invalid equalizer factory."); @@ -422,7 +429,8 @@ static std::shared_ptr create_ul_processor_factory(con (config.log_level == srslog::basic_levels::debug); pusch_processor_factory_sw_configuration pusch_config; - pusch_config.estimator_factory = create_dmrs_pusch_estimator_factory_sw(prg_factory, ch_estimator_factory); + pusch_config.estimator_factory = + create_dmrs_pusch_estimator_factory_sw(prg_factory, low_papr_sequence_gen_factory, ch_estimator_factory); pusch_config.demodulator_factory = create_pusch_demodulator_factory_sw(equalizer_factory, precoding_factory, demodulation_factory, diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp index 5d715aa4ea..379a67d7aa 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp @@ -384,14 +384,15 @@ static std::vector generate_test_cases(const test_profile& profi config.nof_tx_layers = nof_layers; config.rx_ports.resize(profile.nof_rx_ports); std::iota(config.rx_ports.begin(), config.rx_ports.end(), 0); - config.dmrs_symbol_mask = dmrs_symbol_mask; - config.dmrs = dmrs; - config.scrambling_id = 0; - config.nof_cdm_groups_without_data = nof_cdm_groups_without_data; - config.freq_alloc = rb_allocation::make_type1(config.bwp_start_rb, nof_prb); - config.start_symbol_index = 0; - config.nof_symbols = profile.nof_symbols; - config.tbs_lbrm = tbs_lbrm_default; + config.dmrs_symbol_mask = dmrs_symbol_mask; + config.dmrs = pusch_processor::dmrs_configuration{.dmrs = dmrs, + .scrambling_id = 0, + .n_scid = false, + .nof_cdm_groups_without_data = nof_cdm_groups_without_data}; + config.freq_alloc = rb_allocation::make_type1(config.bwp_start_rb, nof_prb); + config.start_symbol_index = 0; + config.nof_symbols = profile.nof_symbols; + config.tbs_lbrm = tbs_lbrm_default; test_case_set.emplace_back(std::tuple(config, tbs)); } @@ -503,6 +504,10 @@ static pusch_processor_factory& get_pusch_processor_factory() std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); TESTASSERT(prg_factory); + std::shared_ptr low_papr_sequence_gen_factory = + create_low_papr_sequence_generator_sw_factory(); + TESTASSERT(low_papr_sequence_gen_factory); + // Create demodulator mapper factory. std::shared_ptr chan_modulation_factory = create_channel_modulation_sw_factory(); TESTASSERT(chan_modulation_factory); @@ -531,7 +536,7 @@ static pusch_processor_factory& get_pusch_processor_factory() // Create DM-RS for PUSCH channel estimator. std::shared_ptr dmrs_pusch_chan_estimator_factory = - create_dmrs_pusch_estimator_factory_sw(prg_factory, port_chan_estimator_factory); + create_dmrs_pusch_estimator_factory_sw(prg_factory, low_papr_sequence_gen_factory, port_chan_estimator_factory); TESTASSERT(dmrs_pusch_chan_estimator_factory); // Create channel equalizer factory. diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp index ebf9b3b694..563e13dffd 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp @@ -263,28 +263,28 @@ class pxsch_bler_test std::iota(rx_ports.begin(), rx_ports.end(), 0U); // Prepare PUSCH processor configuration. - pusch_config.context = std::nullopt; - pusch_config.slot = slot_point(to_numerology_value(scs), 0); - pusch_config.rnti = rnti; - pusch_config.bwp_size_rb = bwp_size_rb; - pusch_config.bwp_start_rb = bwp_start_rb; - pusch_config.cp = cp; - pusch_config.mcs_descr = mcs_descr; - pusch_config.codeword = {rv, ldpc_base_graph, true}; - pusch_config.uci = {}; - pusch_config.n_id = n_id; - pusch_config.nof_tx_layers = nof_layers; - pusch_config.rx_ports = rx_ports; - pusch_config.dmrs_symbol_mask = dmrs_symbol_mask; - pusch_config.dmrs = dmrs; - pusch_config.scrambling_id = scrambling_id; - pusch_config.n_scid = n_scid; - pusch_config.nof_cdm_groups_without_data = nof_cdm_groups_without_data; - pusch_config.freq_alloc = freq_alloc; - pusch_config.start_symbol_index = 0; - pusch_config.nof_symbols = nof_ofdm_symbols; - pusch_config.tbs_lbrm = tbs_lbrm_default; - pusch_config.dc_position = {}; + pusch_config.context = std::nullopt; + pusch_config.slot = slot_point(to_numerology_value(scs), 0); + pusch_config.rnti = rnti; + pusch_config.bwp_size_rb = bwp_size_rb; + pusch_config.bwp_start_rb = bwp_start_rb; + pusch_config.cp = cp; + pusch_config.mcs_descr = mcs_descr; + pusch_config.codeword = {rv, ldpc_base_graph, true}; + pusch_config.uci = {}; + pusch_config.n_id = n_id; + pusch_config.nof_tx_layers = nof_layers; + pusch_config.rx_ports = rx_ports; + pusch_config.dmrs_symbol_mask = dmrs_symbol_mask; + pusch_config.dmrs = pusch_processor::dmrs_configuration{.dmrs = dmrs, + .scrambling_id = scrambling_id, + .n_scid = n_scid, + .nof_cdm_groups_without_data = nof_cdm_groups_without_data}; + pusch_config.freq_alloc = freq_alloc; + pusch_config.start_symbol_index = 0; + pusch_config.nof_symbols = nof_ofdm_symbols; + pusch_config.tbs_lbrm = tbs_lbrm_default; + pusch_config.dc_position = {}; if (enable_dc_position) { pusch_config.dc_position = {bwp_size_rb * NRE / 2}; diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp index 6321df01e3..687194d767 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp @@ -86,6 +86,10 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto create_pseudo_random_generator_sw_factory(); report_fatal_error_if_not(pseudo_random_gen_factory, "Failed to create factory."); + std::shared_ptr low_papr_sequence_gen_factory = + create_low_papr_sequence_generator_sw_factory(); + report_fatal_error_if_not(low_papr_sequence_gen_factory, "Failed to create factory."); + std::shared_ptr ta_est_factory = create_time_alignment_estimator_dft_factory(dft_proc_factory); report_fatal_error_if_not(ta_est_factory, "Failed to create factory."); @@ -94,8 +98,8 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto create_port_channel_estimator_factory_sw(ta_est_factory); report_fatal_error_if_not(chan_estimator_factory, "Failed to create factory."); - std::shared_ptr chan_est_factory = - create_dmrs_pusch_estimator_factory_sw(pseudo_random_gen_factory, chan_estimator_factory); + std::shared_ptr chan_est_factory = create_dmrs_pusch_estimator_factory_sw( + pseudo_random_gen_factory, low_papr_sequence_gen_factory, chan_estimator_factory); report_fatal_error_if_not(chan_est_factory, "Failed to create factory."); std::shared_ptr eq_factory = diff --git a/tests/unittests/fapi_adaptor/phy/messages/ul_pusch_pdu_test.cpp b/tests/unittests/fapi_adaptor/phy/messages/ul_pusch_pdu_test.cpp index e11257be0a..0f711e3a92 100644 --- a/tests/unittests/fapi_adaptor/phy/messages/ul_pusch_pdu_test.cpp +++ b/tests/unittests/fapi_adaptor/phy/messages/ul_pusch_pdu_test.cpp @@ -64,12 +64,18 @@ TEST(fapi_phy_ul_pusch_adaptor_test, valid_pdu_pass) for (unsigned i = 0; i != 14; ++i) { ASSERT_EQ(((fapi_pdu.ul_dmrs_symb_pos >> i) & 1U) == 1U, phy_pdu.dmrs_symbol_mask.test(i)); } - ASSERT_EQ(dmrs_type((fapi_pdu.dmrs_type == fapi::dmrs_cfg_type::type_1) ? dmrs_type::options::TYPE1 - : dmrs_type::options::TYPE2), - phy_pdu.dmrs); - ASSERT_EQ(fapi_pdu.pusch_dmrs_scrambling_id, phy_pdu.scrambling_id); - ASSERT_EQ(fapi_pdu.nscid, phy_pdu.n_scid); - ASSERT_EQ(fapi_pdu.num_dmrs_cdm_grps_no_data, phy_pdu.nof_cdm_groups_without_data); + if (fapi_pdu.transform_precoding) { + const auto& dmrs_config = std::get(phy_pdu.dmrs); + ASSERT_EQ(fapi_pdu.pusch_dmrs_identity, dmrs_config.n_rs_id); + } else { + const auto& dmrs_config = std::get(phy_pdu.dmrs); + ASSERT_EQ(dmrs_type((fapi_pdu.dmrs_type == fapi::dmrs_cfg_type::type_1) ? dmrs_type::options::TYPE1 + : dmrs_type::options::TYPE2), + dmrs_config.dmrs); + ASSERT_EQ(fapi_pdu.pusch_dmrs_scrambling_id, dmrs_config.scrambling_id); + ASSERT_EQ(fapi_pdu.nscid, dmrs_config.n_scid); + ASSERT_EQ(fapi_pdu.num_dmrs_cdm_grps_no_data, dmrs_config.nof_cdm_groups_without_data); + } ASSERT_EQ(fapi_pdu.pusch_maintenance_v3.tb_size_lbrm_bytes, phy_pdu.tbs_lbrm); // RB allocation. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.h b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.h index 3a6fa2af6f..8ad931fb4c 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 17-05-2024 (seed 0): +// This file was generated using the following MATLAB class on 24-07-2024 (seed 0): // + "srsPUSCHProcessorUnittest.m" #include "../../../support/resource_grid_test_doubles.h" @@ -39,33 +39,33 @@ using csi_part2_size = uci_part2_size_description; static const std::vector pusch_processor_test_data = { // clang-format off - {{252, 14, {std::nullopt, {0, 6}, 62751, 4, 248, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 273.5}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 988, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 63608, 1, 2, rb_allocation::make_type1(3, 1), 0, 14, units::bytes(159749), 290}}, {"test_data/pusch_processor_test_input_grid0.dat"}, {"test_data/pusch_processor_test_tb0.dat"}, {"test_data/pusch_processor_test_harq0.dat"}, {"test_data/pusch_processor_test_csi10.dat"}, {"test_data/pusch_processor_test_csi20.dat"}}, - {{89, 14, {std::nullopt, {0, 4}, 59265, 11, 78, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 622.2}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 477, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 17721, 0, 2, rb_allocation::make_type1(1, 7), 0, 14, units::bytes(159749), 128}}, {"test_data/pusch_processor_test_input_grid1.dat"}, {"test_data/pusch_processor_test_tb1.dat"}, {"test_data/pusch_processor_test_harq1.dat"}, {"test_data/pusch_processor_test_csi11.dat"}, {"test_data/pusch_processor_test_csi21.dat"}}, - {{252, 14, {std::nullopt, {0, 9}, 18537, 91, 161, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 489.5}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 768, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 9013, 1, 2, rb_allocation::make_type1(58, 15), 0, 14, units::bytes(159749), 986}}, {"test_data/pusch_processor_test_input_grid2.dat"}, {"test_data/pusch_processor_test_tb2.dat"}, {"test_data/pusch_processor_test_harq2.dat"}, {"test_data/pusch_processor_test_csi12.dat"}, {"test_data/pusch_processor_test_csi22.dat"}}, - {{135, 14, {std::nullopt, {0, 5}, 1930, 37, 98, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 617.3}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 766, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 57047, 0, 2, rb_allocation::make_type1(22, 12), 0, 14, units::bytes(159749), 430}}, {"test_data/pusch_processor_test_input_grid3.dat"}, {"test_data/pusch_processor_test_tb3.dat"}, {"test_data/pusch_processor_test_harq3.dat"}, {"test_data/pusch_processor_test_csi13.dat"}, {"test_data/pusch_processor_test_csi23.dat"}}, - {{265, 14, {std::nullopt, {0, 6}, 51985, 20, 245, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 224}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 66, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 64072, 1, 2, rb_allocation::make_type1(13, 7), 0, 14, units::bytes(159749), 454}}, {"test_data/pusch_processor_test_input_grid4.dat"}, {"test_data/pusch_processor_test_tb4.dat"}, {"test_data/pusch_processor_test_harq4.dat"}, {"test_data/pusch_processor_test_csi14.dat"}, {"test_data/pusch_processor_test_csi24.dat"}}, - {{203, 14, {std::nullopt, {0, 0}, 1510, 188, 15, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 429.6}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 781, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 32346, 0, 2, rb_allocation::make_type1(30, 19), 0, 14, units::bytes(159749), 504}}, {"test_data/pusch_processor_test_input_grid5.dat"}, {"test_data/pusch_processor_test_tb5.dat"}, {"test_data/pusch_processor_test_harq5.dat"}, {"test_data/pusch_processor_test_csi15.dat"}, {"test_data/pusch_processor_test_csi25.dat"}}, - {{87, 14, {std::nullopt, {0, 5}, 56992, 8, 79, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 282.9}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 406, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 53925, 1, 2, rb_allocation::make_type1(0, 7), 0, 14, units::bytes(159749), 154}}, {"test_data/pusch_processor_test_input_grid6.dat"}, {"test_data/pusch_processor_test_tb6.dat"}, {"test_data/pusch_processor_test_harq6.dat"}, {"test_data/pusch_processor_test_csi16.dat"}, {"test_data/pusch_processor_test_csi26.dat"}}, - {{160, 14, {std::nullopt, {0, 5}, 26138, 137, 23, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 632.9}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 705, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 63724, 1, 2, rb_allocation::make_type1(48, 25), 0, 14, units::bytes(159749), 614}}, {"test_data/pusch_processor_test_input_grid7.dat"}, {"test_data/pusch_processor_test_tb7.dat"}, {"test_data/pusch_processor_test_harq7.dat"}, {"test_data/pusch_processor_test_csi17.dat"}, {"test_data/pusch_processor_test_csi27.dat"}}, - {{256, 14, {std::nullopt, {0, 6}, 50177, 254, 2, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 584.7}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 172, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 54691, 1, 2, rb_allocation::make_type1(177, 20), 0, 14, units::bytes(159749), 2326}}, {"test_data/pusch_processor_test_input_grid8.dat"}, {"test_data/pusch_processor_test_tb8.dat"}, {"test_data/pusch_processor_test_harq8.dat"}, {"test_data/pusch_processor_test_csi18.dat"}, {"test_data/pusch_processor_test_csi28.dat"}}, - {{187, 14, {std::nullopt, {0, 3}, 53876, 85, 102, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 173.9}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 881, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 38581, 1, 2, rb_allocation::make_type1(48, 9), 0, 14, units::bytes(159749), 735}}, {"test_data/pusch_processor_test_input_grid9.dat"}, {"test_data/pusch_processor_test_tb9.dat"}, {"test_data/pusch_processor_test_harq9.dat"}, {"test_data/pusch_processor_test_csi19.dat"}, {"test_data/pusch_processor_test_csi29.dat"}}, - {{255, 14, {std::nullopt, {0, 4}, 43187, 180, 75, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 332.2}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 399, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 33286, 0, 2, rb_allocation::make_type1(53, 14), 0, 14, units::bytes(159749), 831}}, {"test_data/pusch_processor_test_input_grid10.dat"}, {"test_data/pusch_processor_test_tb10.dat"}, {"test_data/pusch_processor_test_harq10.dat"}, {"test_data/pusch_processor_test_csi110.dat"}, {"test_data/pusch_processor_test_csi210.dat"}}, - {{90, 14, {std::nullopt, {0, 2}, 38882, 5, 85, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 120}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 220, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 6139, 1, 2, rb_allocation::make_type1(1, 3), 0, 14, units::bytes(159749), 100}}, {"test_data/pusch_processor_test_input_grid11.dat"}, {"test_data/pusch_processor_test_tb11.dat"}, {"test_data/pusch_processor_test_harq11.dat"}, {"test_data/pusch_processor_test_csi111.dat"}, {"test_data/pusch_processor_test_csi211.dat"}}, - {{109, 14, {std::nullopt, {0, 1}, 19909, 48, 61, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 332.2}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 78, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 46285, 0, 2, rb_allocation::make_type1(42, 6), 0, 14, units::bytes(159749), 572}}, {"test_data/pusch_processor_test_input_grid12.dat"}, {"test_data/pusch_processor_test_tb12.dat"}, {"test_data/pusch_processor_test_harq12.dat"}, {"test_data/pusch_processor_test_csi112.dat"}, {"test_data/pusch_processor_test_csi212.dat"}}, - {{224, 14, {std::nullopt, {0, 3}, 35168, 10, 214, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 636}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 152, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 39247, 1, 2, rb_allocation::make_type1(4, 6), 0, 14, units::bytes(159749), 278}}, {"test_data/pusch_processor_test_input_grid13.dat"}, {"test_data/pusch_processor_test_tb13.dat"}, {"test_data/pusch_processor_test_harq13.dat"}, {"test_data/pusch_processor_test_csi113.dat"}, {"test_data/pusch_processor_test_csi213.dat"}}, - {{236, 14, {std::nullopt, {0, 8}, 59485, 6, 230, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 530.5}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 377, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 3853, 1, 2, rb_allocation::make_type1(0, 6), 0, 14, units::bytes(159749), 293}}, {"test_data/pusch_processor_test_input_grid14.dat"}, {"test_data/pusch_processor_test_tb14.dat"}, {"test_data/pusch_processor_test_harq14.dat"}, {"test_data/pusch_processor_test_csi114.dat"}, {"test_data/pusch_processor_test_csi214.dat"}}, - {{271, 14, {std::nullopt, {0, 0}, 14457, 91, 180, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 144.2}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 593, 1, {0}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 48920, 1, 2, rb_allocation::make_type1(62, 10), 0, 14, units::bytes(159749), 939}}, {"test_data/pusch_processor_test_input_grid15.dat"}, {"test_data/pusch_processor_test_tb15.dat"}, {"test_data/pusch_processor_test_harq15.dat"}, {"test_data/pusch_processor_test_csi115.dat"}, {"test_data/pusch_processor_test_csi215.dat"}}, - {{251, 14, {std::nullopt, {0, 2}, 15199, 15, 236, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 685.1}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 230, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 42267, 1, 2, rb_allocation::make_type1(7, 8), 0, 14, units::bytes(159749), 358}}, {"test_data/pusch_processor_test_input_grid16.dat"}, {"test_data/pusch_processor_test_tb16.dat"}, {"test_data/pusch_processor_test_harq16.dat"}, {"test_data/pusch_processor_test_csi116.dat"}, {"test_data/pusch_processor_test_csi216.dat"}}, - {{114, 14, {std::nullopt, {0, 0}, 2620, 33, 81, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 609}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 643, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 27593, 1, 2, rb_allocation::make_type1(10, 20), 0, 14, units::bytes(159749), 264}}, {"test_data/pusch_processor_test_input_grid17.dat"}, {"test_data/pusch_processor_test_tb17.dat"}, {"test_data/pusch_processor_test_harq17.dat"}, {"test_data/pusch_processor_test_csi117.dat"}, {"test_data/pusch_processor_test_csi217.dat"}}, - {{269, 14, {std::nullopt, {0, 10}, 48952, 77, 192, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 193.4}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 544, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 42474, 1, 2, rb_allocation::make_type1(12, 24), 0, 14, units::bytes(159749), 516}}, {"test_data/pusch_processor_test_input_grid18.dat"}, {"test_data/pusch_processor_test_tb18.dat"}, {"test_data/pusch_processor_test_harq18.dat"}, {"test_data/pusch_processor_test_csi118.dat"}, {"test_data/pusch_processor_test_csi218.dat"}}, - {{214, 14, {std::nullopt, {0, 10}, 12637, 11, 203, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 394.2}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 307, 1, {0, 1}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 59111, 0, 2, rb_allocation::make_type1(0, 11), 0, 14, units::bytes(159749), 260}}, {"test_data/pusch_processor_test_input_grid19.dat"}, {"test_data/pusch_processor_test_tb19.dat"}, {"test_data/pusch_processor_test_harq19.dat"}, {"test_data/pusch_processor_test_csi119.dat"}, {"test_data/pusch_processor_test_csi219.dat"}}, - {{166, 14, {std::nullopt, {0, 1}, 58544, 90, 76, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 672.5}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 672, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 54081, 1, 2, rb_allocation::make_type1(4, 20), 0, 14, units::bytes(159749), 147}}, {"test_data/pusch_processor_test_input_grid20.dat"}, {"test_data/pusch_processor_test_tb20.dat"}, {"test_data/pusch_processor_test_harq20.dat"}, {"test_data/pusch_processor_test_csi120.dat"}, {"test_data/pusch_processor_test_csi220.dat"}}, - {{139, 14, {std::nullopt, {0, 7}, 64559, 102, 37, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 670.7}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 561, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 29399, 0, 2, rb_allocation::make_type1(52, 21), 0, 14, units::bytes(159749), 796}}, {"test_data/pusch_processor_test_input_grid21.dat"}, {"test_data/pusch_processor_test_tb21.dat"}, {"test_data/pusch_processor_test_harq21.dat"}, {"test_data/pusch_processor_test_csi121.dat"}, {"test_data/pusch_processor_test_csi221.dat"}}, - {{59, 14, {std::nullopt, {0, 1}, 954, 47, 12, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 133.2}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 30, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 24382, 0, 2, rb_allocation::make_type1(3, 25), 0, 14, units::bytes(159749), 320}}, {"test_data/pusch_processor_test_input_grid22.dat"}, {"test_data/pusch_processor_test_tb22.dat"}, {"test_data/pusch_processor_test_harq22.dat"}, {"test_data/pusch_processor_test_csi122.dat"}, {"test_data/pusch_processor_test_csi222.dat"}}, - {{272, 14, {std::nullopt, {0, 7}, 65180, 20, 252, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 448}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 583, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 41316, 0, 2, rb_allocation::make_type1(4, 16), 0, 14, units::bytes(159749), 428}}, {"test_data/pusch_processor_test_input_grid23.dat"}, {"test_data/pusch_processor_test_tb23.dat"}, {"test_data/pusch_processor_test_harq23.dat"}, {"test_data/pusch_processor_test_csi123.dat"}, {"test_data/pusch_processor_test_csi223.dat"}}, - {{266, 14, {std::nullopt, {0, 3}, 29028, 90, 176, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 515.6}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 951, 1, {0}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 40660, 1, 2, rb_allocation::make_type1(20, 19), 0, 14, units::bytes(159749), 483}}, {"test_data/pusch_processor_test_input_grid24.dat"}, {"test_data/pusch_processor_test_tb24.dat"}, {"test_data/pusch_processor_test_harq24.dat"}, {"test_data/pusch_processor_test_csi124.dat"}, {"test_data/pusch_processor_test_csi224.dat"}}, - {{222, 14, {std::nullopt, {0, 7}, 13563, 135, 87, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 601.8}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 75, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 59544, 0, 2, rb_allocation::make_type1(25, 19), 0, 14, units::bytes(159749), 549}}, {"test_data/pusch_processor_test_input_grid25.dat"}, {"test_data/pusch_processor_test_tb25.dat"}, {"test_data/pusch_processor_test_harq25.dat"}, {"test_data/pusch_processor_test_csi125.dat"}, {"test_data/pusch_processor_test_csi225.dat"}}, - {{187, 14, {std::nullopt, {0, 7}, 27683, 19, 168, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 624.4}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 268, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 17324, 1, 2, rb_allocation::make_type1(2, 17), 0, 14, units::bytes(159749), 389}}, {"test_data/pusch_processor_test_input_grid26.dat"}, {"test_data/pusch_processor_test_tb26.dat"}, {"test_data/pusch_processor_test_harq26.dat"}, {"test_data/pusch_processor_test_csi126.dat"}, {"test_data/pusch_processor_test_csi226.dat"}}, + {{270, 14, {std::nullopt, {0, 6}, 62751, 270, 0, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 273.5}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 988, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 63608, 1, 2}), rb_allocation::make_type1(246, 12), 0, 14, units::bytes(159749), 3068}}, {"test_data/pusch_processor_test_input_grid0.dat"}, {"test_data/pusch_processor_test_tb0.dat"}, {"test_data/pusch_processor_test_harq0.dat"}, {"test_data/pusch_processor_test_csi10.dat"}, {"test_data/pusch_processor_test_csi20.dat"}}, + {{166, 14, {std::nullopt, {0, 5}, 18185, 150, 16, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 255.5}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 713, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 62811, 1, 2}), rb_allocation::make_type1(43, 5), 0, 14, units::bytes(159749), 577}}, {"test_data/pusch_processor_test_input_grid1.dat"}, {"test_data/pusch_processor_test_tb1.dat"}, {"test_data/pusch_processor_test_harq1.dat"}, {"test_data/pusch_processor_test_csi11.dat"}, {"test_data/pusch_processor_test_csi21.dat"}}, + {{262, 14, {std::nullopt, {0, 1}, 25020, 250, 12, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 492.6}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 122, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 3719, 0, 2}), rb_allocation::make_type1(44, 4), 0, 14, units::bytes(159749), 580}}, {"test_data/pusch_processor_test_input_grid2.dat"}, {"test_data/pusch_processor_test_tb2.dat"}, {"test_data/pusch_processor_test_harq2.dat"}, {"test_data/pusch_processor_test_csi12.dat"}, {"test_data/pusch_processor_test_csi22.dat"}}, + {{270, 14, {std::nullopt, {0, 9}, 25841, 270, 0, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 701.9}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 1002, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({952}), rb_allocation::make_type1(137, 24), 0, 14, units::bytes(159749), 1909}}, {"test_data/pusch_processor_test_input_grid3.dat"}, {"test_data/pusch_processor_test_tb3.dat"}, {"test_data/pusch_processor_test_harq3.dat"}, {"test_data/pusch_processor_test_csi13.dat"}, {"test_data/pusch_processor_test_csi23.dat"}}, + {{75, 14, {std::nullopt, {0, 6}, 3512, 50, 25, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 350.6}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 488, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({713}), rb_allocation::make_type1(28, 6), 0, 14, units::bytes(159749), 419}}, {"test_data/pusch_processor_test_input_grid4.dat"}, {"test_data/pusch_processor_test_tb4.dat"}, {"test_data/pusch_processor_test_harq4.dat"}, {"test_data/pusch_processor_test_csi14.dat"}, {"test_data/pusch_processor_test_csi24.dat"}}, + {{205, 14, {std::nullopt, {0, 8}, 3244, 150, 55, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 675}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 262, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({545}), rb_allocation::make_type1(1, 72), 0, 14, units::bytes(159749), 666}}, {"test_data/pusch_processor_test_input_grid5.dat"}, {"test_data/pusch_processor_test_tb5.dat"}, {"test_data/pusch_processor_test_harq5.dat"}, {"test_data/pusch_processor_test_csi15.dat"}, {"test_data/pusch_processor_test_csi25.dat"}}, + {{268, 14, {std::nullopt, {0, 8}, 45438, 150, 118, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 313.8}, {{0, ldpc_base_graph_type::BG2, true}}, {0, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 854, 1, {0}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 11957, 1, 2}), rb_allocation::make_type1(119, 27), 0, 14, units::bytes(159749), 1812}}, {"test_data/pusch_processor_test_input_grid6.dat"}, {"test_data/pusch_processor_test_tb6.dat"}, {"test_data/pusch_processor_test_harq6.dat"}, {"test_data/pusch_processor_test_csi16.dat"}, {"test_data/pusch_processor_test_csi26.dat"}}, + {{106, 14, {std::nullopt, {0, 9}, 17009, 75, 31, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 529.3}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 741, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 10611, 0, 2}), rb_allocation::make_type1(0, 40), 0, 14, units::bytes(159749), 216}}, {"test_data/pusch_processor_test_input_grid7.dat"}, {"test_data/pusch_processor_test_tb7.dat"}, {"test_data/pusch_processor_test_harq7.dat"}, {"test_data/pusch_processor_test_csi17.dat"}, {"test_data/pusch_processor_test_csi27.dat"}}, + {{164, 14, {std::nullopt, {0, 2}, 18950, 100, 64, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 547.1}, {{0, ldpc_base_graph_type::BG1, true}}, {0, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 182, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({526}), rb_allocation::make_type1(60, 30), 0, 14, units::bytes(159749), 1087}}, {"test_data/pusch_processor_test_input_grid8.dat"}, {"test_data/pusch_processor_test_tb8.dat"}, {"test_data/pusch_processor_test_harq8.dat"}, {"test_data/pusch_processor_test_csi18.dat"}, {"test_data/pusch_processor_test_csi28.dat"}}, + {{220, 14, {std::nullopt, {0, 6}, 53339, 200, 20, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 309}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 475, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 48193, 0, 2}), rb_allocation::make_type1(126, 64), 0, 14, units::bytes(159749), 1665}}, {"test_data/pusch_processor_test_input_grid9.dat"}, {"test_data/pusch_processor_test_tb9.dat"}, {"test_data/pusch_processor_test_harq9.dat"}, {"test_data/pusch_processor_test_csi19.dat"}, {"test_data/pusch_processor_test_csi29.dat"}}, + {{270, 14, {std::nullopt, {0, 5}, 55742, 270, 0, cyclic_prefix::NORMAL, {modulation_scheme::QAM16, 396.7}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 369, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({101}), rb_allocation::make_type1(145, 16), 0, 14, units::bytes(159749), 1871}}, {"test_data/pusch_processor_test_input_grid10.dat"}, {"test_data/pusch_processor_test_tb10.dat"}, {"test_data/pusch_processor_test_harq10.dat"}, {"test_data/pusch_processor_test_csi110.dat"}, {"test_data/pusch_processor_test_csi210.dat"}}, + {{212, 14, {std::nullopt, {0, 9}, 8736, 75, 137, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 289.8}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 788, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({779}), rb_allocation::make_type1(43, 2), 0, 14, units::bytes(159749), 669}}, {"test_data/pusch_processor_test_input_grid11.dat"}, {"test_data/pusch_processor_test_tb11.dat"}, {"test_data/pusch_processor_test_harq11.dat"}, {"test_data/pusch_processor_test_csi111.dat"}, {"test_data/pusch_processor_test_csi211.dat"}}, + {{260, 14, {std::nullopt, {0, 6}, 40820, 250, 10, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 379.3}, {{0, ldpc_base_graph_type::BG2, true}}, {1, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 277, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 36427, 1, 2}), rb_allocation::make_type1(239, 8), 0, 14, units::bytes(159749), 2957}}, {"test_data/pusch_processor_test_input_grid12.dat"}, {"test_data/pusch_processor_test_tb12.dat"}, {"test_data/pusch_processor_test_harq12.dat"}, {"test_data/pusch_processor_test_csi112.dat"}, {"test_data/pusch_processor_test_csi212.dat"}}, + {{261, 14, {std::nullopt, {0, 6}, 19164, 200, 61, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 596.4}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 563, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({28}), rb_allocation::make_type1(150, 18), 0, 14, units::bytes(159749), 1966}}, {"test_data/pusch_processor_test_input_grid13.dat"}, {"test_data/pusch_processor_test_tb13.dat"}, {"test_data/pusch_processor_test_harq13.dat"}, {"test_data/pusch_processor_test_csi113.dat"}, {"test_data/pusch_processor_test_csi213.dat"}}, + {{215, 14, {std::nullopt, {0, 9}, 5745, 150, 65, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 460.4}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 680, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({794}), rb_allocation::make_type1(94, 10), 0, 14, units::bytes(159749), 1196}}, {"test_data/pusch_processor_test_input_grid14.dat"}, {"test_data/pusch_processor_test_tb14.dat"}, {"test_data/pusch_processor_test_harq14.dat"}, {"test_data/pusch_processor_test_csi114.dat"}, {"test_data/pusch_processor_test_csi214.dat"}}, + {{262, 14, {std::nullopt, {0, 10}, 5694, 50, 212, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 583}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 342, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({433}), rb_allocation::make_type1(15, 9), 0, 14, units::bytes(159749), 408}}, {"test_data/pusch_processor_test_input_grid15.dat"}, {"test_data/pusch_processor_test_tb15.dat"}, {"test_data/pusch_processor_test_harq15.dat"}, {"test_data/pusch_processor_test_csi115.dat"}, {"test_data/pusch_processor_test_csi215.dat"}}, + {{153, 14, {std::nullopt, {0, 10}, 18699, 150, 3, cyclic_prefix::NORMAL, {modulation_scheme::QAM256, 476.1}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 217, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 57562, 1, 2}), rb_allocation::make_type1(22, 40), 0, 14, units::bytes(159749), 370}}, {"test_data/pusch_processor_test_input_grid16.dat"}, {"test_data/pusch_processor_test_tb16.dat"}, {"test_data/pusch_processor_test_harq16.dat"}, {"test_data/pusch_processor_test_csi116.dat"}, {"test_data/pusch_processor_test_csi216.dat"}}, + {{270, 14, {std::nullopt, {0, 5}, 7638, 270, 0, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 491}, {{0, ldpc_base_graph_type::BG1, true}}, {1, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 240, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({370}), rb_allocation::make_type1(104, 120), 0, 14, units::bytes(159749), 1321}}, {"test_data/pusch_processor_test_input_grid17.dat"}, {"test_data/pusch_processor_test_tb17.dat"}, {"test_data/pusch_processor_test_harq17.dat"}, {"test_data/pusch_processor_test_csi117.dat"}, {"test_data/pusch_processor_test_csi217.dat"}}, + {{244, 14, {std::nullopt, {0, 10}, 734, 200, 44, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 400.4}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 420, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 31645, 1, 2}), rb_allocation::make_type1(49, 125), 0, 14, units::bytes(159749), 918}}, {"test_data/pusch_processor_test_input_grid18.dat"}, {"test_data/pusch_processor_test_tb18.dat"}, {"test_data/pusch_processor_test_harq18.dat"}, {"test_data/pusch_processor_test_csi118.dat"}, {"test_data/pusch_processor_test_csi218.dat"}}, + {{160, 14, {std::nullopt, {0, 10}, 43076, 50, 110, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 404.5}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 55, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 48427, 0, 2}), rb_allocation::make_type1(19, 24), 0, 14, units::bytes(159749), 384}}, {"test_data/pusch_processor_test_input_grid19.dat"}, {"test_data/pusch_processor_test_tb19.dat"}, {"test_data/pusch_processor_test_harq19.dat"}, {"test_data/pusch_processor_test_csi119.dat"}, {"test_data/pusch_processor_test_csi219.dat"}}, + {{215, 14, {std::nullopt, {0, 2}, 5816, 200, 15, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 333.9}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 0, csi_part2_size(0), 1, 20, 6.25, 6.25}, 817, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 2426, 1, 2}), rb_allocation::make_type1(121, 24), 0, 14, units::bytes(159749), 1663}}, {"test_data/pusch_processor_test_input_grid20.dat"}, {"test_data/pusch_processor_test_tb20.dat"}, {"test_data/pusch_processor_test_harq20.dat"}, {"test_data/pusch_processor_test_csi120.dat"}, {"test_data/pusch_processor_test_csi220.dat"}}, + {{270, 14, {std::nullopt, {0, 9}, 25893, 270, 0, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 202.6}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 219, 1, {0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 42298, 0, 2}), rb_allocation::make_type1(178, 32), 0, 14, units::bytes(159749), 2307}}, {"test_data/pusch_processor_test_input_grid21.dat"}, {"test_data/pusch_processor_test_tb21.dat"}, {"test_data/pusch_processor_test_harq21.dat"}, {"test_data/pusch_processor_test_csi121.dat"}, {"test_data/pusch_processor_test_csi221.dat"}}, + {{229, 14, {std::nullopt, {0, 0}, 60852, 75, 154, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 233}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 666, 1, {0, 1}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({714}), rb_allocation::make_type1(22, 30), 0, 14, units::bytes(159749), 753}}, {"test_data/pusch_processor_test_input_grid22.dat"}, {"test_data/pusch_processor_test_tb22.dat"}, {"test_data/pusch_processor_test_harq22.dat"}, {"test_data/pusch_processor_test_csi122.dat"}, {"test_data/pusch_processor_test_csi222.dat"}}, + {{136, 14, {std::nullopt, {0, 10}, 13534, 75, 61, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 628.9}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 4, csi_part2_size(0), 1, 20, 6.25, 6.25}, 119, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 32918, 0, 2}), rb_allocation::make_type1(5, 40), 0, 14, units::bytes(159749), 148}}, {"test_data/pusch_processor_test_input_grid23.dat"}, {"test_data/pusch_processor_test_tb23.dat"}, {"test_data/pusch_processor_test_harq23.dat"}, {"test_data/pusch_processor_test_csi123.dat"}, {"test_data/pusch_processor_test_csi223.dat"}}, + {{163, 14, {std::nullopt, {0, 7}, 55250, 150, 13, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 447.5}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 617, 1, {0}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_configuration({dmrs_type::TYPE1, 49311, 1, 2}), rb_allocation::make_type1(80, 64), 0, 14, units::bytes(159749), 1422}}, {"test_data/pusch_processor_test_input_grid24.dat"}, {"test_data/pusch_processor_test_tb24.dat"}, {"test_data/pusch_processor_test_harq24.dat"}, {"test_data/pusch_processor_test_csi124.dat"}, {"test_data/pusch_processor_test_csi224.dat"}}, + {{268, 14, {std::nullopt, {0, 6}, 22625, 100, 168, cyclic_prefix::NORMAL, {modulation_scheme::QAM64, 715.2}, {{0, ldpc_base_graph_type::BG1, true}}, {10, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 332, 1, {0, 1}, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({855}), rb_allocation::make_type1(66, 32), 0, 14, units::bytes(159749), 1016}}, {"test_data/pusch_processor_test_input_grid25.dat"}, {"test_data/pusch_processor_test_tb25.dat"}, {"test_data/pusch_processor_test_harq25.dat"}, {"test_data/pusch_processor_test_csi125.dat"}, {"test_data/pusch_processor_test_csi225.dat"}}, + {{177, 14, {std::nullopt, {0, 1}, 65076, 75, 102, cyclic_prefix::NORMAL, {modulation_scheme::QPSK, 314.5}, {{0, ldpc_base_graph_type::BG2, true}}, {10, 5, csi_part2_size(1), 1, 20, 6.25, 6.25}, 614, 1, {0, 1, 2, 3}, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, pusch_processor::dmrs_transform_precoding_configuration({425}), rb_allocation::make_type1(8, 27), 0, 14, units::bytes(159749), 473}}, {"test_data/pusch_processor_test_input_grid26.dat"}, {"test_data/pusch_processor_test_tb26.dat"}, {"test_data/pusch_processor_test_harq26.dat"}, {"test_data/pusch_processor_test_csi126.dat"}, {"test_data/pusch_processor_test_csi226.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.tar.gz index 7ab353419c..e4d0b95daf 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73196136d2ef317079c8a16156ea4301f1623d9621ceaea9a5129a31e6f99b8a -size 1396756 +oid sha256:883da082acb554fba1e785062cae5230038f8efe406bc53987ba2b736bcd98a9 +size 3253087 diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp index 8872620b66..480554877e 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp @@ -188,15 +188,15 @@ class PuschProcessorFixture : public ::testing::TestWithParam(pdu.dmrs); + unsigned nof_dmrs_per_prb = + dmrs_config.dmrs.nof_dmrs_per_rb() * dmrs_config.nof_cdm_groups_without_data * nof_dmrs_symbols; // Calculate the mnumber of data RE per PRB. unsigned nof_re_per_prb = NRE * pdu.nof_symbols - nof_dmrs_per_prb; @@ -336,9 +338,9 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) ulsch_config.nof_rb = rb_mask.count(); ulsch_config.start_symbol_index = pdu.start_symbol_index; ulsch_config.nof_symbols = pdu.nof_symbols; - ulsch_config.dmrs_type = pdu.dmrs == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2; - ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; - ulsch_config.nof_cdm_groups_without_data = pdu.nof_cdm_groups_without_data; + ulsch_config.dmrs_type = dmrs_config.dmrs == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2; + ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; + ulsch_config.nof_cdm_groups_without_data = dmrs_config.nof_cdm_groups_without_data; ulsch_config.nof_layers = pdu.nof_tx_layers; ulsch_config.contains_dc = false; ulsch_information ulsch_info = get_ulsch_information(ulsch_config); @@ -377,19 +379,21 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) // Assert channel estimator inputs. ASSERT_EQ(1, estimator_spy->get_entries().size()); const dmrs_pusch_estimator_spy::entry_t& estimator_entry = estimator_spy->get_entries().front(); + const auto& dmrs_sequence_config = + std::get(estimator_entry.config.sequence_config); ASSERT_EQ(&rg_spy, estimator_entry.grid); ASSERT_EQ(pdu.slot, estimator_entry.config.slot); - ASSERT_EQ(pdu.dmrs, estimator_entry.config.type); - ASSERT_EQ(pdu.scrambling_id, estimator_entry.config.scrambling_id); - ASSERT_EQ(pdu.n_scid, estimator_entry.config.n_scid); - ASSERT_EQ(convert_dB_to_amplitude(-get_sch_to_dmrs_ratio_dB(pdu.nof_cdm_groups_without_data)), + ASSERT_EQ(dmrs_config.dmrs, dmrs_sequence_config.type); + ASSERT_EQ(dmrs_config.scrambling_id, dmrs_sequence_config.scrambling_id); + ASSERT_EQ(dmrs_config.n_scid, dmrs_sequence_config.n_scid); + ASSERT_EQ(convert_dB_to_amplitude(-get_sch_to_dmrs_ratio_dB(dmrs_config.nof_cdm_groups_without_data)), estimator_entry.config.scaling); ASSERT_EQ(pdu.cp, estimator_entry.config.c_prefix); ASSERT_EQ(pdu.dmrs_symbol_mask, estimator_entry.config.symbols_mask); ASSERT_EQ(rb_mask, estimator_entry.config.rb_mask); ASSERT_EQ(pdu.start_symbol_index, estimator_entry.config.first_symbol); ASSERT_EQ(pdu.nof_symbols, estimator_entry.config.nof_symbols); - ASSERT_EQ(pdu.nof_tx_layers, estimator_entry.config.nof_tx_layers); + ASSERT_EQ(pdu.nof_tx_layers, dmrs_sequence_config.nof_tx_layers); ASSERT_EQ(span(pdu.rx_ports), span(estimator_entry.config.rx_ports)); // Assert demodulator inputs. @@ -403,8 +407,8 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) ASSERT_EQ(pdu.start_symbol_index, demodulator_entry.config.start_symbol_index); ASSERT_EQ(pdu.nof_symbols, demodulator_entry.config.nof_symbols); ASSERT_EQ(pdu.dmrs_symbol_mask, demodulator_entry.config.dmrs_symb_pos); - ASSERT_EQ(pdu.dmrs, demodulator_entry.config.dmrs_config_type); - ASSERT_EQ(pdu.nof_cdm_groups_without_data, demodulator_entry.config.nof_cdm_groups_without_data); + ASSERT_EQ(dmrs_config.dmrs, demodulator_entry.config.dmrs_config_type); + ASSERT_EQ(dmrs_config.nof_cdm_groups_without_data, demodulator_entry.config.nof_cdm_groups_without_data); ASSERT_EQ(pdu.n_id, demodulator_entry.config.n_id); ASSERT_EQ(pdu.nof_tx_layers, demodulator_entry.config.nof_tx_layers); ASSERT_EQ(false, demodulator_entry.config.enable_transform_precoding); @@ -421,9 +425,9 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) ASSERT_EQ(pdu.start_symbol_index, demux_entry.config.start_symbol_index); ASSERT_EQ(pdu.nof_symbols, demux_entry.config.nof_symbols); ASSERT_EQ(ulsch_info.nof_harq_ack_rvd.value(), demux_entry.config.nof_harq_ack_rvd); - ASSERT_EQ(pdu.dmrs, demux_entry.config.dmrs); + ASSERT_EQ(dmrs_config.dmrs, demux_entry.config.dmrs); ASSERT_EQ(pdu.dmrs_symbol_mask, demux_entry.config.dmrs_symbol_mask); - ASSERT_EQ(pdu.nof_cdm_groups_without_data, demux_entry.config.nof_cdm_groups_without_data); + ASSERT_EQ(dmrs_config.nof_cdm_groups_without_data, demux_entry.config.nof_cdm_groups_without_data); // Assert decoder inputs only if the codeword is present. if (pdu.codeword.has_value()) { diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp index 899d699dce..9df1ba336d 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp @@ -24,27 +24,28 @@ namespace { /// Maximum number of layers the PUSCH processor supports. static constexpr unsigned max_supported_nof_layers = 2; -const pusch_processor::pdu_t base_pdu = {std::nullopt, - {0, 9}, - 8323, - 25, - 0, - cyclic_prefix::NORMAL, - {modulation_scheme::PI_2_BPSK, 0.1}, - {{0, ldpc_base_graph_type::BG2, true}}, - {0, 1, uci_part2_size_description(1), 1, 20, 6.25, 6.25}, - 935, - 1, - {0, 1, 2, 3}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, - dmrs_type::TYPE1, - 35840, - 1, - 2, - rb_allocation::make_type1(15, 1), - 0, - 14, - units::bytes(ldpc::MAX_CODEBLOCK_SIZE / 8)}; +const pusch_processor::pdu_t base_pdu = {.context = std::nullopt, + .slot = {0, 9}, + .rnti = 8323, + .bwp_size_rb = 25, + .bwp_start_rb = 0, + .cp = cyclic_prefix::NORMAL, + .mcs_descr = {modulation_scheme::PI_2_BPSK, 0.1}, + .codeword = {{0, ldpc_base_graph_type::BG2, true}}, + .uci = {0, 1, uci_part2_size_description(1), 1, 20, 6.25, 6.25}, + .n_id = 935, + .nof_tx_layers = 1, + .rx_ports = {0, 1, 2, 3}, + .dmrs_symbol_mask = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, + .dmrs = pusch_processor::dmrs_configuration{.dmrs = dmrs_type::TYPE1, + .scrambling_id = 0, + .n_scid = false, + .nof_cdm_groups_without_data = 2}, + .freq_alloc = rb_allocation::make_type1(15, 1), + .start_symbol_index = 0, + .nof_symbols = 14, + .tbs_lbrm = units::bytes(ldpc::MAX_CODEBLOCK_SIZE / 8), + .dc_position = std::nullopt}; // namespace struct test_case_t { std::function get_pdu; @@ -128,14 +129,14 @@ const std::vector pusch_processor_validator_test_data = { }, R"(The DM-RS symbol mask size \(i\.e\., 14\) must be the same as the number of symbols allocated to the transmission within the slot \(i\.e\., 15\)\.)"}, {[] { - pusch_processor::pdu_t pdu = base_pdu; - pdu.dmrs = dmrs_type::TYPE2; + pusch_processor::pdu_t pdu = base_pdu; + std::get(pdu.dmrs).dmrs = dmrs_type::TYPE2; return pdu; }, R"(Only DM-RS Type 1 is currently supported\.)"}, {[] { - pusch_processor::pdu_t pdu = base_pdu; - pdu.nof_cdm_groups_without_data = 1; + pusch_processor::pdu_t pdu = base_pdu; + std::get(pdu.dmrs).nof_cdm_groups_without_data = 1; return pdu; }, R"(Only two CDM groups without data are currently supported\.)"}, @@ -151,6 +152,29 @@ const std::vector pusch_processor_validator_test_data = { return pdu; }, R"(DC position \(i\.e\., 3300\) is out of range \[0\.\.3300\)\.)"}, + {[] { + pusch_processor::pdu_t pdu = base_pdu; + pdu.dmrs = pusch_processor::dmrs_transform_precoding_configuration{.n_rs_id = 0}; + pdu.nof_tx_layers = 2; + return pdu; + }, + R"(Transform precoding is only possible with one layer\.)"}, + {[] { + pusch_processor::pdu_t pdu = base_pdu; + pdu.dmrs = pusch_processor::dmrs_transform_precoding_configuration{.n_rs_id = 0}; + pdu.freq_alloc = rb_allocation::make_custom({0, 2}); + return pdu; + }, + R"(Transform precoding is only possible with contiguous allocations\.)"}, + {[] { + pusch_processor::pdu_t pdu = base_pdu; + pdu.dmrs = pusch_processor::dmrs_transform_precoding_configuration{.n_rs_id = 0}; + pdu.freq_alloc = rb_allocation::make_type1(0, 7); + pdu.nof_tx_layers = 1; + return pdu; + }, + R"(Transform precoding is only possible with a valid number of PRB\.)"}, + }; class PuschProcessorFixture : public ::testing::TestWithParam @@ -169,6 +193,11 @@ class PuschProcessorFixture : public ::testing::TestWithParam std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); ASSERT_NE(prg_factory, nullptr); + // Create low-PAPR sequence generator. + std::shared_ptr low_papr_sequence_gen_factory = + create_low_papr_sequence_generator_sw_factory(); + ASSERT_NE(low_papr_sequence_gen_factory, nullptr); + // Create demodulator mapper factory. std::shared_ptr chan_modulation_factory = create_channel_modulation_sw_factory(); ASSERT_NE(chan_modulation_factory, nullptr); @@ -210,7 +239,7 @@ class PuschProcessorFixture : public ::testing::TestWithParam // Create DM-RS for PUSCH channel estimator. std::shared_ptr dmrs_pusch_chan_estimator_factory = - create_dmrs_pusch_estimator_factory_sw(prg_factory, port_chan_estimator_factory); + create_dmrs_pusch_estimator_factory_sw(prg_factory, low_papr_sequence_gen_factory, port_chan_estimator_factory); ASSERT_NE(dmrs_pusch_chan_estimator_factory, nullptr); // Create channel equalizer factory. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp index fa271dd20c..ca0ae90299 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp @@ -195,6 +195,12 @@ class PuschProcessorFixture : public ::testing::TestWithParam low_papr_sequence_gen_factory = + create_low_papr_sequence_generator_sw_factory(); + if (!low_papr_sequence_gen_factory) { + return nullptr; + } // Create demodulator mapper factory. std::shared_ptr chan_modulation_factory = create_channel_modulation_sw_factory(); @@ -237,7 +243,7 @@ class PuschProcessorFixture : public ::testing::TestWithParam dmrs_pusch_chan_estimator_factory = - create_dmrs_pusch_estimator_factory_sw(prg_factory, port_chan_estimator_factory); + create_dmrs_pusch_estimator_factory_sw(prg_factory, low_papr_sequence_gen_factory, port_chan_estimator_factory); if (!dmrs_pusch_chan_estimator_factory) { return nullptr; } diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp index 1f72a26403..49e192560e 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp @@ -23,19 +23,17 @@ namespace srsran { std::ostream& operator<<(std::ostream& os, dmrs_pusch_estimator::configuration config) { fmt::print(os, - "slot={}; type={}; scrambling_id={}; n_scid={}; scaling={:.3f}; cp={}; dmrs_pos={}; f_alloc={}; " - "t_alloc={}:{}; tx_layers={}; rx_ports={};", + "slot={}; type={}; scaling={:.3f}; cp={}; dmrs_pos={}; f_alloc={}; " + "t_alloc={}:{}; tx_layers={}; rx_ports=[{}];", config.slot, - config.type == dmrs_type::TYPE1 ? "1" : "2", - config.scrambling_id, - config.n_scid, + config.get_dmrs_type() == dmrs_type::TYPE1 ? "1" : "2", config.scaling, config.c_prefix.to_string(), config.symbols_mask, config.rb_mask, config.first_symbol, config.nof_symbols, - config.nof_tx_layers, + config.get_nof_tx_layers(), span(config.rx_ports)); return os; } @@ -74,6 +72,11 @@ class DmrsPuschEstimatorFixture : public ::testing::TestWithParam std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); ASSERT_TRUE(prg_factory); + // Create low-PAPR sequence generator. + std::shared_ptr low_papr_sequence_gen_factory_factory = + create_low_papr_sequence_generator_sw_factory(); + ASSERT_TRUE(low_papr_sequence_gen_factory_factory); + std::shared_ptr dft_factory = create_dft_processor_factory_fftw_slow(); if (!dft_factory) { dft_factory = create_dft_processor_factory_generic(); @@ -90,8 +93,8 @@ class DmrsPuschEstimatorFixture : public ::testing::TestWithParam ASSERT_TRUE(port_estimator_factory); // Create estimator factory. - std::shared_ptr estimator_factory = - create_dmrs_pusch_estimator_factory_sw(prg_factory, port_estimator_factory); + std::shared_ptr estimator_factory = create_dmrs_pusch_estimator_factory_sw( + prg_factory, low_papr_sequence_gen_factory_factory, port_estimator_factory); ASSERT_TRUE(estimator_factory); // Create actual channel estimator. @@ -123,11 +126,11 @@ TEST_P(DmrsPuschEstimatorFixture, Creation) // The current estimator does not support Type2 DM-RS. // As well, the MIMO case must be double-checked. - if ((config.type == dmrs_type::TYPE2) || (config.nof_tx_layers > 1)) { + if ((config.get_dmrs_type() == dmrs_type::TYPE2) || (config.get_nof_tx_layers() > 1)) { GTEST_SKIP() << "Configuration not supported yet, skipping."; } - ASSERT_EQ(config.rx_ports.size(), config.nof_tx_layers) + ASSERT_EQ(config.rx_ports.size(), config.get_nof_tx_layers()) << "This simulation assumes an equal number of Rx ports and Tx layers."; // Prepare channel estimate (just to be sure, reset all entries). @@ -135,7 +138,7 @@ TEST_P(DmrsPuschEstimatorFixture, Creation) ch_estimate_dims.nof_prb = config.rb_mask.size(); ch_estimate_dims.nof_symbols = config.nof_symbols + config.first_symbol; ch_estimate_dims.nof_rx_ports = config.rx_ports.size(); - ch_estimate_dims.nof_tx_layers = config.nof_tx_layers; + ch_estimate_dims.nof_tx_layers = config.get_nof_tx_layers(); channel_estimate ch_est(ch_estimate_dims); @@ -154,7 +157,7 @@ TEST_P(DmrsPuschEstimatorFixture, Creation) ASSERT_EQ(ch_estimate_dims.nof_prb, config.rb_mask.size()) << "Wrong number of PRBs."; ASSERT_EQ(ch_estimate_dims.nof_symbols, config.nof_symbols + config.first_symbol) << "Wrong number of symbols."; ASSERT_EQ(ch_estimate_dims.nof_rx_ports, config.rx_ports.size()) << "Wrong number of Rx ports."; - ASSERT_EQ(ch_estimate_dims.nof_tx_layers, config.nof_tx_layers) << "Wrong number of Tx layers."; + ASSERT_EQ(ch_estimate_dims.nof_tx_layers, config.get_nof_tx_layers()) << "Wrong number of Tx layers."; for (unsigned i_port = 0; i_port != ch_estimate_dims.nof_rx_ports; ++i_port) { for (unsigned i_layer = 0; i_layer != ch_estimate_dims.nof_tx_layers; ++i_layer) { @@ -221,7 +224,7 @@ TEST_P(DmrsPuschEstimatorFixture, Average) // The current estimator does not support Type2 DM-RS. // As well, the MIMO case must be double-checked. - if ((config.type == dmrs_type::TYPE2) || (config.nof_tx_layers > 1)) { + if ((config.get_dmrs_type() == dmrs_type::TYPE2) || (config.get_nof_tx_layers() > 1)) { GTEST_SKIP() << "Configuration not supported yet, skipping."; } @@ -242,7 +245,7 @@ TEST_P(DmrsPuschEstimatorFixture, Average) ASSERT_EQ(ch_estimate_dims.nof_prb, config.rb_mask.size()) << "Wrong number of PRBs."; ASSERT_EQ(ch_estimate_dims.nof_symbols, config.nof_symbols + config.first_symbol) << "Wrong number of symbols."; ASSERT_EQ(ch_estimate_dims.nof_rx_ports, config.rx_ports.size()) << "Wrong number of Rx ports."; - ASSERT_EQ(ch_estimate_dims.nof_tx_layers, config.nof_tx_layers) << "Wrong number of Tx layers."; + ASSERT_EQ(ch_estimate_dims.nof_tx_layers, config.get_nof_tx_layers()) << "Wrong number of Tx layers."; // Assert that the channel estimates are correct. ASSERT_TRUE(are_estimates_ok(expected_estimates, ch_est)); diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.h b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.h index 1c765e709b..18791f4e5c 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.h +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 27-06-2024 (seed 0): +// This file was generated using the following MATLAB class on 24-07-2024 (seed 0): // + "srsPUSCHdmrsUnittest.m" #include "../../support/resource_grid_test_doubles.h" @@ -32,198 +32,198 @@ struct test_case_t { static const std::vector dmrs_pusch_estimator_test_data = { // clang-format off - {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_type::TYPE1, 608, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output0.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates0.dat"}}, - {test_label::ch_estimation, {{0, 0, 3, 0}, dmrs_type::TYPE1, 451, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.76911, 2.3038, {"test_data/dmrs_pusch_estimator_test_output1.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates1.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 122, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output2.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates2.dat"}}, - {test_label::ch_estimation, {{0, 0, 6, 0}, dmrs_type::TYPE2, 447, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.67663, 1.6049, {"test_data/dmrs_pusch_estimator_test_output3.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates3.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE1, 871, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output4.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates4.dat"}}, - {test_label::ch_estimation, {{0, 0, 6, 0}, dmrs_type::TYPE1, 771, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.6349, 0.13555, {"test_data/dmrs_pusch_estimator_test_output5.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates5.dat"}}, - {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_type::TYPE2, 98, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output6.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates6.dat"}}, - {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_type::TYPE2, 745, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.1826, 0.15905, {"test_data/dmrs_pusch_estimator_test_output7.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates7.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 173, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output8.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates8.dat"}}, - {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 332, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.92309, 3.3483, {"test_data/dmrs_pusch_estimator_test_output9.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates9.dat"}}, - {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_type::TYPE2, 634, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output10.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates10.dat"}}, - {test_label::ch_estimation, {{0, 0, 6, 0}, dmrs_type::TYPE2, 555, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.7598, 0.17851, {"test_data/dmrs_pusch_estimator_test_output11.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates11.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE1, 970, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output12.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates12.dat"}}, - {test_label::ch_estimation, {{0, 0, 3, 0}, dmrs_type::TYPE1, 395, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.97644, 3.3272, {"test_data/dmrs_pusch_estimator_test_output13.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates13.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 931, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output14.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates14.dat"}}, - {test_label::ch_estimation, {{0, 0, 7, 0}, dmrs_type::TYPE2, 698, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 4.2175, 1.9907, {"test_data/dmrs_pusch_estimator_test_output15.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates15.dat"}}, - {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_type::TYPE1, 293, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output16.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates16.dat"}}, - {test_label::ch_estimation, {{0, 0, 1, 0}, dmrs_type::TYPE1, 243, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.0158, 0.064939, {"test_data/dmrs_pusch_estimator_test_output17.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates17.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE2, 280, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output18.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates18.dat"}}, - {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_type::TYPE2, 691, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.4503, 1.1225, {"test_data/dmrs_pusch_estimator_test_output19.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates19.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 31, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output20.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates20.dat"}}, - {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 642, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.8527, 0.046855, {"test_data/dmrs_pusch_estimator_test_output21.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates21.dat"}}, - {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_type::TYPE2, 360, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output22.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates22.dat"}}, - {test_label::ch_estimation, {{0, 0, 3, 0}, dmrs_type::TYPE2, 407, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.0562, 0.19079, {"test_data/dmrs_pusch_estimator_test_output23.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates23.dat"}}, - {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_type::TYPE1, 39, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output24.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates24.dat"}}, - {test_label::ch_estimation, {{0, 0, 0, 0}, dmrs_type::TYPE1, 21, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.1731, 0.1735, {"test_data/dmrs_pusch_estimator_test_output25.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates25.dat"}}, - {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_type::TYPE2, 459, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output26.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates26.dat"}}, - {test_label::ch_estimation, {{0, 0, 5, 0}, dmrs_type::TYPE2, 959, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.86057, 0.33335, {"test_data/dmrs_pusch_estimator_test_output27.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates27.dat"}}, - {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_type::TYPE1, 859, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output28.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates28.dat"}}, - {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 260, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.98032, 0.081573, {"test_data/dmrs_pusch_estimator_test_output29.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates29.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE2, 302, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output30.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates30.dat"}}, - {test_label::ch_estimation, {{0, 0, 5, 0}, dmrs_type::TYPE2, 652, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.0497, 0.24208, {"test_data/dmrs_pusch_estimator_test_output31.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates31.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE1, 174, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output32.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates32.dat"}}, - {test_label::ch_estimation, {{0, 0, 2, 0}, dmrs_type::TYPE1, 544, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 3.5262, 0.098301, {"test_data/dmrs_pusch_estimator_test_output33.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates33.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE2, 33, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output34.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates34.dat"}}, - {test_label::ch_estimation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 757, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.6045, 0.16356, {"test_data/dmrs_pusch_estimator_test_output35.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates35.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE1, 772, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output36.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates36.dat"}}, - {test_label::ch_estimation, {{0, 0, 5, 0}, dmrs_type::TYPE1, 645, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 6.2959, 0.057159, {"test_data/dmrs_pusch_estimator_test_output37.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates37.dat"}}, - {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_type::TYPE2, 151, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output38.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates38.dat"}}, - {test_label::ch_estimation, {{0, 0, 6, 0}, dmrs_type::TYPE2, 795, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.293, 0.078485, {"test_data/dmrs_pusch_estimator_test_output39.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates39.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 677, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output40.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates40.dat"}}, - {test_label::ch_estimation, {{0, 0, 2, 0}, dmrs_type::TYPE1, 342, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 4.2206, 0.065534, {"test_data/dmrs_pusch_estimator_test_output41.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates41.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE2, 743, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output42.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates42.dat"}}, - {test_label::ch_estimation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 91, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.7139, 0.10157, {"test_data/dmrs_pusch_estimator_test_output43.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates43.dat"}}, - {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_type::TYPE1, 704, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output44.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates44.dat"}}, - {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 599, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 12.6425, 0.045464, {"test_data/dmrs_pusch_estimator_test_output45.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates45.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 722, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output46.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates46.dat"}}, - {test_label::ch_estimation, {{0, 0, 7, 0}, dmrs_type::TYPE2, 864, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.9731, 0.40699, {"test_data/dmrs_pusch_estimator_test_output47.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates47.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 300, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output48.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates48.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 169, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output49.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates49.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE1, 998, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output50.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates50.dat"}}, - {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_type::TYPE2, 324, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output51.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates51.dat"}}, - {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_type::TYPE1, 783, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output52.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates52.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE2, 755, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output53.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates53.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE1, 681, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output54.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates54.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE2, 519, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output55.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates55.dat"}}, - {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_type::TYPE1, 982, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output56.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates56.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE2, 439, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output57.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates57.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 408, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output58.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates58.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE2, 303, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output59.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates59.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 741, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output60.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates60.dat"}}, - {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_type::TYPE2, 796, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output61.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates61.dat"}}, - {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_type::TYPE1, 904, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output62.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates62.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE2, 90, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output63.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates63.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 145, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output64.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates64.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE2, 893, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output65.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates65.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 118, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output66.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates66.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE2, 762, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output67.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates67.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE1, 189, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output68.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates68.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE2, 671, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output69.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates69.dat"}}, - {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_type::TYPE1, 318, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output70.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates70.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE2, 624, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output71.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates71.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE1, 111, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output72.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates72.dat"}}, - {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_type::TYPE2, 126, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output73.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates73.dat"}}, - {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_type::TYPE1, 240, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output74.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates74.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE2, 815, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output75.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates75.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 823, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output76.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates76.dat"}}, - {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_type::TYPE2, 797, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output77.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates77.dat"}}, - {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_type::TYPE1, 761, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output78.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates78.dat"}}, - {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_type::TYPE2, 591, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output79.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates79.dat"}}, - {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_type::TYPE1, 422, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output80.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates80.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE2, 474, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output81.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates81.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE1, 837, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output82.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates82.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE2, 870, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output83.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates83.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 748, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output84.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates84.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE2, 531, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output85.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates85.dat"}}, - {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_type::TYPE1, 401, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output86.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates86.dat"}}, - {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_type::TYPE2, 164, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output87.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates87.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE1, 305, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output88.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates88.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE2, 34, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output89.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates89.dat"}}, - {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_type::TYPE1, 5, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output90.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates90.dat"}}, - {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_type::TYPE2, 947, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output91.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates91.dat"}}, - {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_type::TYPE1, 880, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output92.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates92.dat"}}, - {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_type::TYPE2, 264, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output93.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates93.dat"}}, - {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_type::TYPE1, 719, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output94.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates94.dat"}}, - {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_type::TYPE2, 833, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output95.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates95.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_type::TYPE1, 751, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output96.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates96.dat"}}, - {test_label::ch_estimation, {{1, 0, 9, 0}, dmrs_type::TYPE1, 731, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.0692, 0.18748, {"test_data/dmrs_pusch_estimator_test_output97.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates97.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_type::TYPE2, 788, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output98.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates98.dat"}}, - {test_label::ch_estimation, {{1, 0, 8, 0}, dmrs_type::TYPE2, 839, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.80329, 0.50725, {"test_data/dmrs_pusch_estimator_test_output99.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates99.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_type::TYPE1, 418, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output100.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates100.dat"}}, - {test_label::ch_estimation, {{1, 0, 3, 0}, dmrs_type::TYPE1, 672, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.4286, 0.092791, {"test_data/dmrs_pusch_estimator_test_output101.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates101.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_type::TYPE2, 517, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output102.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates102.dat"}}, - {test_label::ch_estimation, {{1, 0, 2, 0}, dmrs_type::TYPE2, 943, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.4976, 0.15389, {"test_data/dmrs_pusch_estimator_test_output103.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates103.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_type::TYPE1, 335, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output104.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates104.dat"}}, - {test_label::ch_estimation, {{1, 0, 0, 0}, dmrs_type::TYPE1, 120, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.91711, 2.8254, {"test_data/dmrs_pusch_estimator_test_output105.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates105.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_type::TYPE2, 270, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output106.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates106.dat"}}, - {test_label::ch_estimation, {{1, 0, 1, 0}, dmrs_type::TYPE2, 389, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.1917, 1.0793, {"test_data/dmrs_pusch_estimator_test_output107.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates107.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_type::TYPE1, 876, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output108.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates108.dat"}}, - {test_label::ch_estimation, {{1, 0, 8, 0}, dmrs_type::TYPE1, 766, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 8.3399, 0.050134, {"test_data/dmrs_pusch_estimator_test_output109.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates109.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 1}, dmrs_type::TYPE2, 518, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output110.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates110.dat"}}, - {test_label::ch_estimation, {{1, 0, 0, 1}, dmrs_type::TYPE2, 850, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.8542, 0.77624, {"test_data/dmrs_pusch_estimator_test_output111.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates111.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_type::TYPE1, 803, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output112.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates112.dat"}}, - {test_label::ch_estimation, {{1, 0, 0, 0}, dmrs_type::TYPE1, 227, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.6579, 0.098135, {"test_data/dmrs_pusch_estimator_test_output113.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates113.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_type::TYPE2, 159, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output114.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates114.dat"}}, - {test_label::ch_estimation, {{1, 0, 6, 0}, dmrs_type::TYPE2, 592, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.1488, 0.10751, {"test_data/dmrs_pusch_estimator_test_output115.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates115.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_type::TYPE1, 840, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output116.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates116.dat"}}, - {test_label::ch_estimation, {{1, 0, 4, 0}, dmrs_type::TYPE1, 235, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.8549, 0.070351, {"test_data/dmrs_pusch_estimator_test_output117.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates117.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE2, 804, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output118.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates118.dat"}}, - {test_label::ch_estimation, {{1, 0, 9, 1}, dmrs_type::TYPE2, 709, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 2.7142, 0.092385, {"test_data/dmrs_pusch_estimator_test_output119.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates119.dat"}}, - {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_type::TYPE1, 54, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output120.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates120.dat"}}, - {test_label::ch_estimation, {{1, 0, 8, 1}, dmrs_type::TYPE1, 505, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 4.6345, 0.19408, {"test_data/dmrs_pusch_estimator_test_output121.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates121.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_type::TYPE2, 487, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output122.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates122.dat"}}, - {test_label::ch_estimation, {{1, 0, 3, 1}, dmrs_type::TYPE2, 962, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.67799, 0.98827, {"test_data/dmrs_pusch_estimator_test_output123.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates123.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_type::TYPE1, 375, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output124.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates124.dat"}}, - {test_label::ch_estimation, {{1, 0, 1, 1}, dmrs_type::TYPE1, 635, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.94173, 0.092907, {"test_data/dmrs_pusch_estimator_test_output125.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates125.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_type::TYPE2, 648, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output126.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates126.dat"}}, - {test_label::ch_estimation, {{1, 0, 1, 1}, dmrs_type::TYPE2, 147, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.4733, 0.16004, {"test_data/dmrs_pusch_estimator_test_output127.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates127.dat"}}, - {test_label::dmrs_creation, {{1, 0, 3, 0}, dmrs_type::TYPE1, 660, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output128.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates128.dat"}}, - {test_label::ch_estimation, {{1, 0, 3, 1}, dmrs_type::TYPE1, 930, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 6.6929, 0.11868, {"test_data/dmrs_pusch_estimator_test_output129.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates129.dat"}}, - {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_type::TYPE2, 868, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output130.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates130.dat"}}, - {test_label::ch_estimation, {{1, 0, 5, 0}, dmrs_type::TYPE2, 878, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.4074, 0.53698, {"test_data/dmrs_pusch_estimator_test_output131.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates131.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_type::TYPE1, 2, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output132.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates132.dat"}}, - {test_label::ch_estimation, {{1, 0, 3, 0}, dmrs_type::TYPE1, 789, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 11.5322, 0.12059, {"test_data/dmrs_pusch_estimator_test_output133.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates133.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 1}, dmrs_type::TYPE2, 357, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output134.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates134.dat"}}, - {test_label::ch_estimation, {{1, 0, 5, 0}, dmrs_type::TYPE2, 95, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0.96259, 0.075334, {"test_data/dmrs_pusch_estimator_test_output135.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates135.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_type::TYPE1, 869, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output136.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates136.dat"}}, - {test_label::ch_estimation, {{1, 0, 2, 0}, dmrs_type::TYPE1, 165, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 8.6284, 0.069862, {"test_data/dmrs_pusch_estimator_test_output137.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates137.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 1}, dmrs_type::TYPE2, 801, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output138.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates138.dat"}}, - {test_label::ch_estimation, {{1, 0, 9, 1}, dmrs_type::TYPE2, 319, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.2288, 0.38694, {"test_data/dmrs_pusch_estimator_test_output139.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates139.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_type::TYPE1, 690, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output140.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates140.dat"}}, - {test_label::ch_estimation, {{1, 0, 9, 1}, dmrs_type::TYPE1, 738, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.3296, 0.045955, {"test_data/dmrs_pusch_estimator_test_output141.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates141.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 0}, dmrs_type::TYPE2, 879, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output142.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates142.dat"}}, - {test_label::ch_estimation, {{1, 0, 9, 0}, dmrs_type::TYPE2, 135, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 1, {0}}, 1.0064, 0.32709, {"test_data/dmrs_pusch_estimator_test_output143.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates143.dat"}}, - {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_type::TYPE1, 593, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output144.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates144.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_type::TYPE2, 268, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output145.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates145.dat"}}, - {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_type::TYPE1, 67, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output146.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates146.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_type::TYPE2, 529, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output147.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates147.dat"}}, - {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_type::TYPE1, 15, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output148.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates148.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_type::TYPE2, 881, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output149.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates149.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_type::TYPE1, 673, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output150.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates150.dat"}}, - {test_label::dmrs_creation, {{1, 0, 4, 1}, dmrs_type::TYPE2, 1007, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output151.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates151.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE1, 139, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output152.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates152.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_type::TYPE2, 134, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output153.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates153.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_type::TYPE1, 650, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output154.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates154.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 1}, dmrs_type::TYPE2, 598, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output155.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates155.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE1, 68, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output156.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates156.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 1}, dmrs_type::TYPE2, 309, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output157.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates157.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE1, 541, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output158.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates158.dat"}}, - {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_type::TYPE2, 831, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output159.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates159.dat"}}, - {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_type::TYPE1, 114, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output160.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates160.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 1}, dmrs_type::TYPE2, 463, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output161.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates161.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE1, 955, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output162.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates162.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_type::TYPE2, 424, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output163.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates163.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_type::TYPE1, 910, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output164.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates164.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE2, 583, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output165.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates165.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_type::TYPE1, 368, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output166.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates166.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_type::TYPE2, 10, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 2, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output167.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates167.dat"}}, - {test_label::dmrs_creation, {{1, 0, 5, 0}, dmrs_type::TYPE1, 912, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output168.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates168.dat"}}, - {test_label::dmrs_creation, {{1, 0, 5, 1}, dmrs_type::TYPE2, 398, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output169.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates169.dat"}}, - {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_type::TYPE1, 100, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output170.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates170.dat"}}, - {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_type::TYPE2, 53, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output171.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates171.dat"}}, - {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_type::TYPE1, 974, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output172.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates172.dat"}}, - {test_label::dmrs_creation, {{1, 0, 5, 1}, dmrs_type::TYPE2, 950, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output173.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates173.dat"}}, - {test_label::dmrs_creation, {{1, 0, 4, 1}, dmrs_type::TYPE1, 104, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output174.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates174.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 1}, dmrs_type::TYPE2, 898, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output175.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates175.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_type::TYPE1, 674, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output176.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates176.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 1}, dmrs_type::TYPE2, 334, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output177.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates177.dat"}}, - {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_type::TYPE1, 577, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output178.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates178.dat"}}, - {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_type::TYPE2, 295, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output179.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates179.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_type::TYPE1, 882, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output180.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates180.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_type::TYPE2, 175, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output181.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates181.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_type::TYPE1, 901, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output182.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates182.dat"}}, - {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_type::TYPE2, 217, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output183.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates183.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_type::TYPE1, 359, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output184.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates184.dat"}}, - {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_type::TYPE2, 29, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output185.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates185.dat"}}, - {test_label::dmrs_creation, {{1, 0, 4, 0}, dmrs_type::TYPE1, 320, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output186.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates186.dat"}}, - {test_label::dmrs_creation, {{1, 0, 5, 1}, dmrs_type::TYPE2, 949, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output187.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates187.dat"}}, - {test_label::dmrs_creation, {{1, 0, 4, 0}, dmrs_type::TYPE1, 725, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output188.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates188.dat"}}, - {test_label::dmrs_creation, {{1, 0, 1, 0}, dmrs_type::TYPE2, 460, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output189.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates189.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_type::TYPE1, 705, 1, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output190.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates190.dat"}}, - {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_type::TYPE2, 688, 0, 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, 4, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output191.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates191.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 608, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output0.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates0.dat"}}, + {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({451}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.9465, 0.52235, {"test_data/dmrs_pusch_estimator_test_output1.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates1.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 122, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output2.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates2.dat"}}, + {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 447, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 3.3457, 0.33756, {"test_data/dmrs_pusch_estimator_test_output3.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates3.dat"}}, + {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 871, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output4.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates4.dat"}}, + {test_label::ch_estimation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 771, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.9366, 0.11496, {"test_data/dmrs_pusch_estimator_test_output5.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates5.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 98, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output6.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates6.dat"}}, + {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 745, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 1, 13, {0}}, 2.4351, 0.36186, {"test_data/dmrs_pusch_estimator_test_output7.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates7.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({173}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output8.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates8.dat"}}, + {test_label::ch_estimation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 332, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 5.7753, 0.14026, {"test_data/dmrs_pusch_estimator_test_output9.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates9.dat"}}, + {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 634, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output10.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates10.dat"}}, + {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 555, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.2645, 1.2435, {"test_data/dmrs_pusch_estimator_test_output11.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates11.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 970, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output12.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates12.dat"}}, + {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({395}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 4.8782, 0.056555, {"test_data/dmrs_pusch_estimator_test_output13.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates13.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 931, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output14.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates14.dat"}}, + {test_label::ch_estimation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 698, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.97842, 0.66087, {"test_data/dmrs_pusch_estimator_test_output15.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates15.dat"}}, + {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({293}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output16.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates16.dat"}}, + {test_label::ch_estimation, {{0, 0, 3, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({243}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.0029, 3.4051, {"test_data/dmrs_pusch_estimator_test_output17.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates17.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 280, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output18.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates18.dat"}}, + {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 691, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.6223, 1.6816, {"test_data/dmrs_pusch_estimator_test_output19.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates19.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({31}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output20.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates20.dat"}}, + {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({642}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.2734, 0.060133, {"test_data/dmrs_pusch_estimator_test_output21.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates21.dat"}}, + {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 360, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output22.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates22.dat"}}, + {test_label::ch_estimation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 407, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.93748, 3.0032, {"test_data/dmrs_pusch_estimator_test_output23.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates23.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 39, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output24.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates24.dat"}}, + {test_label::ch_estimation, {{0, 0, 0, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({21}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.098, 0.17702, {"test_data/dmrs_pusch_estimator_test_output25.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates25.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 459, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output26.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates26.dat"}}, + {test_label::ch_estimation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 959, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.72978, 0.38736, {"test_data/dmrs_pusch_estimator_test_output27.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates27.dat"}}, + {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 859, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output28.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates28.dat"}}, + {test_label::ch_estimation, {{0, 0, 1, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({260}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 4.6651, 0.12499, {"test_data/dmrs_pusch_estimator_test_output29.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates29.dat"}}, + {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 302, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output30.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates30.dat"}}, + {test_label::ch_estimation, {{0, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 652, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.3128, 0.14515, {"test_data/dmrs_pusch_estimator_test_output31.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates31.dat"}}, + {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 174, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output32.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates32.dat"}}, + {test_label::ch_estimation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 544, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, 1, 13, {0}}, 2.1542, 0.10421, {"test_data/dmrs_pusch_estimator_test_output33.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates33.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 33, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output34.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates34.dat"}}, + {test_label::ch_estimation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 757, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 2.0293, 0.5088, {"test_data/dmrs_pusch_estimator_test_output35.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates35.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({772}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output36.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates36.dat"}}, + {test_label::ch_estimation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 645, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 1, 13, {0}}, 2.6669, 1.8549, {"test_data/dmrs_pusch_estimator_test_output37.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates37.dat"}}, + {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 151, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output38.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates38.dat"}}, + {test_label::ch_estimation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 795, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.2841, 0.91712, {"test_data/dmrs_pusch_estimator_test_output39.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates39.dat"}}, + {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({677}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output40.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates40.dat"}}, + {test_label::ch_estimation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 342, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {0}}, 2.6114, 0.03151, {"test_data/dmrs_pusch_estimator_test_output41.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates41.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 743, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output42.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates42.dat"}}, + {test_label::ch_estimation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 91, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.0449, 0.30783, {"test_data/dmrs_pusch_estimator_test_output43.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates43.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 704, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output44.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates44.dat"}}, + {test_label::ch_estimation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 599, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.97899, 1.071, {"test_data/dmrs_pusch_estimator_test_output45.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates45.dat"}}, + {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 722, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output46.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates46.dat"}}, + {test_label::ch_estimation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 864, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.95938, 2.2528, {"test_data/dmrs_pusch_estimator_test_output47.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates47.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 300, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output48.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates48.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 169, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output49.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates49.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 998, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output50.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates50.dat"}}, + {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 324, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output51.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates51.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 783, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output52.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates52.dat"}}, + {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 755, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output53.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates53.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 681, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output54.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates54.dat"}}, + {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 519, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output55.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates55.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 982, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output56.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates56.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 439, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output57.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates57.dat"}}, + {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 408, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output58.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates58.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 303, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output59.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates59.dat"}}, + {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 741, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output60.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates60.dat"}}, + {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 796, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output61.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates61.dat"}}, + {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 904, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output62.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates62.dat"}}, + {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 90, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output63.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates63.dat"}}, + {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 145, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output64.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates64.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 893, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output65.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates65.dat"}}, + {test_label::dmrs_creation, {{0, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 118, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output66.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates66.dat"}}, + {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 762, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output67.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates67.dat"}}, + {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 189, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output68.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates68.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 671, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output69.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates69.dat"}}, + {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 318, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output70.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates70.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 624, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output71.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates71.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 111, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output72.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates72.dat"}}, + {test_label::dmrs_creation, {{0, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 126, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output73.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates73.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 240, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output74.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates74.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 815, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output75.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates75.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 823, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output76.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates76.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 797, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output77.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates77.dat"}}, + {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 761, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output78.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates78.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 591, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output79.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates79.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 422, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output80.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates80.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 474, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output81.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates81.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 837, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output82.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates82.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 870, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output83.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates83.dat"}}, + {test_label::dmrs_creation, {{0, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 748, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output84.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates84.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 531, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output85.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates85.dat"}}, + {test_label::dmrs_creation, {{0, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 401, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output86.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates86.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 164, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output87.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates87.dat"}}, + {test_label::dmrs_creation, {{0, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 305, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output88.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates88.dat"}}, + {test_label::dmrs_creation, {{0, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 34, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output89.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates89.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 5, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output90.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates90.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 947, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output91.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates91.dat"}}, + {test_label::dmrs_creation, {{0, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 880, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output92.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates92.dat"}}, + {test_label::dmrs_creation, {{0, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 264, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output93.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates93.dat"}}, + {test_label::dmrs_creation, {{0, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 719, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output94.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates94.dat"}}, + {test_label::dmrs_creation, {{0, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 833, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output95.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates95.dat"}}, + {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 751, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output96.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates96.dat"}}, + {test_label::ch_estimation, {{1, 0, 7, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({731}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.037, 1.2697, {"test_data/dmrs_pusch_estimator_test_output97.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates97.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 788, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output98.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates98.dat"}}, + {test_label::ch_estimation, {{1, 0, 0, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 839, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {0}}, 0.8681, 0.34639, {"test_data/dmrs_pusch_estimator_test_output99.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates99.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 418, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output100.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates100.dat"}}, + {test_label::ch_estimation, {{1, 0, 1, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({672}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.91957, 2.6181, {"test_data/dmrs_pusch_estimator_test_output101.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates101.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 517, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output102.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates102.dat"}}, + {test_label::ch_estimation, {{1, 0, 0, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 943, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 5.7074, 0.23243, {"test_data/dmrs_pusch_estimator_test_output103.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates103.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_pusch_estimator::low_papr_sequence_configuration({335}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output104.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates104.dat"}}, + {test_label::ch_estimation, {{1, 0, 6, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 120, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 1, 13, {0}}, 1.3884, 0.35461, {"test_data/dmrs_pusch_estimator_test_output105.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates105.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 270, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output106.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates106.dat"}}, + {test_label::ch_estimation, {{1, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 389, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 2.3352, 1.3265, {"test_data/dmrs_pusch_estimator_test_output107.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates107.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_pusch_estimator::low_papr_sequence_configuration({876}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output108.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates108.dat"}}, + {test_label::ch_estimation, {{1, 0, 4, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({766}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 7.2732, 0.070514, {"test_data/dmrs_pusch_estimator_test_output109.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates109.dat"}}, + {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 518, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output110.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates110.dat"}}, + {test_label::ch_estimation, {{1, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 850, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.96544, 1.0846, {"test_data/dmrs_pusch_estimator_test_output111.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates111.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 803, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output112.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates112.dat"}}, + {test_label::ch_estimation, {{1, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 227, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.9554, 0.062057, {"test_data/dmrs_pusch_estimator_test_output113.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates113.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 159, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output114.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates114.dat"}}, + {test_label::ch_estimation, {{1, 0, 7, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 592, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.4848, 1.8813, {"test_data/dmrs_pusch_estimator_test_output115.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates115.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 840, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output116.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates116.dat"}}, + {test_label::ch_estimation, {{1, 0, 2, 1}, dmrs_pusch_estimator::low_papr_sequence_configuration({235}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, 1, 13, {0}}, 1.1396, 0.20297, {"test_data/dmrs_pusch_estimator_test_output117.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates117.dat"}}, + {test_label::dmrs_creation, {{1, 0, 2, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 804, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output118.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates118.dat"}}, + {test_label::ch_estimation, {{1, 0, 9, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 709, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {0}}, 1.3429, 0.80043, {"test_data/dmrs_pusch_estimator_test_output119.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates119.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 54, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output120.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates120.dat"}}, + {test_label::ch_estimation, {{1, 0, 9, 1}, dmrs_pusch_estimator::low_papr_sequence_configuration({505}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0.86816, 0.77282, {"test_data/dmrs_pusch_estimator_test_output121.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates121.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 487, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output122.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates122.dat"}}, + {test_label::ch_estimation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 962, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.2924, 0.91767, {"test_data/dmrs_pusch_estimator_test_output123.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates123.dat"}}, + {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 375, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output124.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates124.dat"}}, + {test_label::ch_estimation, {{1, 0, 7, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({635}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.3749, 0.091579, {"test_data/dmrs_pusch_estimator_test_output125.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates125.dat"}}, + {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 648, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output126.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates126.dat"}}, + {test_label::ch_estimation, {{1, 0, 3, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 147, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 2.7967, 4.9722, {"test_data/dmrs_pusch_estimator_test_output127.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates127.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 660, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output128.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates128.dat"}}, + {test_label::ch_estimation, {{1, 0, 0, 1}, dmrs_pusch_estimator::low_papr_sequence_configuration({930}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 1, 13, {0}}, 0.93795, 0.33432, {"test_data/dmrs_pusch_estimator_test_output129.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates129.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 868, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output130.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates130.dat"}}, + {test_label::ch_estimation, {{1, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 878, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.3622, 2.5949, {"test_data/dmrs_pusch_estimator_test_output131.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates131.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({2}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output132.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates132.dat"}}, + {test_label::ch_estimation, {{1, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 789, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 5.0279, 0.054077, {"test_data/dmrs_pusch_estimator_test_output133.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates133.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 357, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output134.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates134.dat"}}, + {test_label::ch_estimation, {{1, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 95, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.1419, 0.091295, {"test_data/dmrs_pusch_estimator_test_output135.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates135.dat"}}, + {test_label::dmrs_creation, {{1, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 869, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output136.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates136.dat"}}, + {test_label::ch_estimation, {{1, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 165, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, 1, 13, {0}}, 1.0372, 0.10309, {"test_data/dmrs_pusch_estimator_test_output137.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates137.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 801, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output138.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates138.dat"}}, + {test_label::ch_estimation, {{1, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 319, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 1.1434, 4.1561, {"test_data/dmrs_pusch_estimator_test_output139.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates139.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 0}, dmrs_pusch_estimator::low_papr_sequence_configuration({690}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output140.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates140.dat"}}, + {test_label::ch_estimation, {{1, 0, 4, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 1, 738, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 2.7964, 0.055083, {"test_data/dmrs_pusch_estimator_test_output141.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates141.dat"}}, + {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 879, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {0}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output142.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates142.dat"}}, + {test_label::ch_estimation, {{1, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 1, 135, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 1, 13, {0}}, 0.94361, 0.09039, {"test_data/dmrs_pusch_estimator_test_output143.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates143.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 593, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output144.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates144.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 268, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output145.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates145.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 67, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output146.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates146.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 529, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output147.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates147.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 15, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output148.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates148.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 881, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output149.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates149.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 673, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output150.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates150.dat"}}, + {test_label::dmrs_creation, {{1, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 1007, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output151.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates151.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 139, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output152.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates152.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 134, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output153.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates153.dat"}}, + {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 650, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output154.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates154.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 598, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output155.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates155.dat"}}, + {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 68, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output156.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates156.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 309, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output157.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates157.dat"}}, + {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 541, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output158.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates158.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 831, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output159.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates159.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 114, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output160.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates160.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 463, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output161.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates161.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 955, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output162.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates162.dat"}}, + {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 424, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output163.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates163.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 910, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output164.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates164.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 583, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output165.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates165.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 2, 368, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output166.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates166.dat"}}, + {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 2, 10, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, 1, 13, {{0, 1}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output167.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates167.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 912, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output168.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates168.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 398, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output169.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates169.dat"}}, + {test_label::dmrs_creation, {{1, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 100, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output170.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates170.dat"}}, + {test_label::dmrs_creation, {{1, 0, 8, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 53, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output171.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates171.dat"}}, + {test_label::dmrs_creation, {{1, 0, 5, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 974, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output172.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates172.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 950, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output173.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates173.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 104, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output174.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates174.dat"}}, + {test_label::dmrs_creation, {{1, 0, 4, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 898, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output175.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates175.dat"}}, + {test_label::dmrs_creation, {{1, 0, 0, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 674, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output176.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates176.dat"}}, + {test_label::dmrs_creation, {{1, 0, 7, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 334, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output177.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates177.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 577, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output178.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates178.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 295, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output179.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates179.dat"}}, + {test_label::dmrs_creation, {{1, 0, 2, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 882, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output180.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates180.dat"}}, + {test_label::dmrs_creation, {{1, 0, 5, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 175, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output181.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates181.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 901, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output182.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates182.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 217, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output183.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates183.dat"}}, + {test_label::dmrs_creation, {{1, 0, 5, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 359, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output184.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates184.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 29, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output185.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates185.dat"}}, + {test_label::dmrs_creation, {{1, 0, 9, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 320, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output186.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates186.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 949, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output187.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates187.dat"}}, + {test_label::dmrs_creation, {{1, 0, 3, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 725, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output188.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates188.dat"}}, + {test_label::dmrs_creation, {{1, 0, 8, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 460, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output189.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates189.dat"}}, + {test_label::dmrs_creation, {{1, 0, 6, 0}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE1, 4, 705, 0}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output190.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates190.dat"}}, + {test_label::dmrs_creation, {{1, 0, 1, 1}, dmrs_pusch_estimator::pseudo_random_sequence_configuration({dmrs_type::TYPE2, 4, 688, 1}), 1.4142, cyclic_prefix::NORMAL, {0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 1, 13, {{0, 1, 2, 3}}}, 0, 0, {"test_data/dmrs_pusch_estimator_test_output191.dat"}, {"test_data/dmrs_pusch_estimator_ch_estimates191.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.tar.gz b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.tar.gz index cde4b3bbef..a5a698fb41 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.tar.gz +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea7c3375180af2d41f58b4356c8b7361f2a7fe0dad06d3f9ee36f6e2ee89dacd -size 7769685 +oid sha256:8fc315101148ead87cc75a5e4cd1d1acaec6758971ed83074a7bd6e15803c3bd +size 4420888 From 893eea59839949ff82d93dcde62a38f8d72b13cc Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 30 Jul 2024 09:06:20 +0200 Subject: [PATCH 040/407] phy: review PUSCH processor related --- .../phy/upper/channel_processors/pdsch_processor.h | 4 ++-- .../channel_processors/pusch/pusch_processor.h | 14 +++++++------- .../upper/signal_processors/dmrs_pusch_estimator.h | 6 +++--- lib/fapi_adaptor/phy/messages/pusch.cpp | 2 +- .../pusch/pusch_processor_impl.cpp | 2 +- .../pusch/pusch_processor_unittest.cpp | 2 +- .../pusch/pusch_processor_validator_test.cpp | 11 +++++++---- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/include/srsran/phy/upper/channel_processors/pdsch_processor.h b/include/srsran/phy/upper/channel_processors/pdsch_processor.h index d524dd3e0a..6e1bb2a654 100644 --- a/include/srsran/phy/upper/channel_processors/pdsch_processor.h +++ b/include/srsran/phy/upper/channel_processors/pdsch_processor.h @@ -91,12 +91,12 @@ class pdsch_processor } ref_point; /// Indicates which symbol in the slot transmit DMRS. symbol_slot_mask dmrs_symbol_mask; - /// Indicates the DMRS type. + /// Indicates the DM-RS type. dmrs_type dmrs; /// \brief Parameter \f$N^{n_{SCID}}_{ID}\f$ TS 38.211 section 7.4.1.1.1. /// /// It is equal to: - /// - {0,1, … ,65535} given by the higher-layer parameters scramblingID0 and scramblingID1, + /// - {0,1, ... ,65535} given by the higher-layer parameters scramblingID0 and scramblingID1, /// - \f$N^{cell}_{ID}\f$ otherwise. unsigned scrambling_id; /// \brief Parameter \f$n_{SCID}\f$ from TS 38.211 section 7.4.1.1.1. diff --git a/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h b/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h index 0918e3402a..65fcda2b97 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h +++ b/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h @@ -72,31 +72,31 @@ class pusch_processor /// Collects the DM-RS parameters. struct dmrs_configuration { - /// Indicates the DMRS type. + /// Indicates the DM-RS type. dmrs_type dmrs; - /// \brief Parameter \f$N^{n_{SCID}}_{ID}\f$ TS 38.211 section 6.4.1.1.1. + /// \brief Parameter \f$N^{n_{SCID}}_{ID}\f$ TS38.211 Section 6.4.1.1.1. /// /// It is equal to: - /// - {0,1, … ,65535} given by the higher-layer parameters scramblingID0 and scramblingID1, + /// - a value in {0,1, ... ,65535} given by the higher-layer parameters \e scramblingID0 and \e scramblingID1, /// - \f$N^{cell}_{ID}\f$ otherwise. unsigned scrambling_id; /// \brief Parameter \f$n_{SCID}\f$ from TS 38.211 section 6.4.1.1.1. /// /// It is equal to: - /// - \c true or \c false according DM-RS sequence initialization field, in the DCI associated with the PUSCH + /// - \c true or \c false according to the DM-RS sequence initialization field, in the DCI associated with the PUSCH /// transmission if DCI format 0_1 is used, /// - \c false otherwise. bool n_scid; - /// Number of DMRS CDM groups without data. + /// Number of DM-RS CDM groups without data. unsigned nof_cdm_groups_without_data; }; /// Collects the DM-RS parameters when transform precoding is enabled. struct dmrs_transform_precoding_configuration { - /// \brief Parameter \f$n^{RS}_{ID}\f$ TS 38.211 section 6.4.1.1.2. + /// \brief Parameter \f$n^{RS}_{ID}\f$ TS38.211 Section 6.4.1.1.2. /// /// It is equal to: - /// - {0,1, … ,1007} given by the higher-layer parameters nPUSCH-Identity, or + /// - a value in {0,1, ... ,1007} given by the higher-layer parameter \e nPUSCH-Identity, or /// - \f$N^{cell}_{ID}\f$. unsigned n_rs_id; }; diff --git a/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h b/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h index 84c0125b75..e24346f6b0 100644 --- a/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h +++ b/include/srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h @@ -43,7 +43,7 @@ class dmrs_pusch_estimator /// Parameters for pseudo-random sequence. struct low_papr_sequence_configuration { - /// Reference signal sequence identifier [0..1007]. + /// Reference signal sequence identifier {0, ..., 1007}. unsigned n_rs_id; }; @@ -77,7 +77,7 @@ class dmrs_pusch_estimator /// \brief Gets the number of transmit layers. /// - /// The number of transmit layers when low-PAPR sequences are used is always one. Otherwise, it is given in the + /// The number of transmit layers when low-PAPR sequences are used is always one. Otherwise, it is specified in the /// sequence configuration. unsigned get_nof_tx_layers() const { @@ -90,7 +90,7 @@ class dmrs_pusch_estimator /// \brief Gets the DM-RS type. /// - /// The DM-RS type is always 1 when low-PAPR sequences are used. Otherwise, it is given in the sequence + /// The DM-RS type is always 1 when low-PAPR sequences are used. Otherwise, it is specified in the sequence /// configuration. dmrs_type get_dmrs_type() const { diff --git a/lib/fapi_adaptor/phy/messages/pusch.cpp b/lib/fapi_adaptor/phy/messages/pusch.cpp index 0f2fb9b7ba..cb25f09c41 100644 --- a/lib/fapi_adaptor/phy/messages/pusch.cpp +++ b/lib/fapi_adaptor/phy/messages/pusch.cpp @@ -128,7 +128,7 @@ void srsran::fapi_adaptor::convert_pusch_fapi_to_phy(uplink_processor::pusch_pdu .dmrs = fapi_pdu.dmrs_type == fapi::dmrs_cfg_type::type_1 ? dmrs_type::options::TYPE1 : dmrs_type::options::TYPE2, .scrambling_id = fapi_pdu.pusch_dmrs_scrambling_id, - .n_scid = (fapi_pdu.nscid != 0), + .n_scid = (fapi_pdu.nscid == 1), .nof_cdm_groups_without_data = fapi_pdu.num_dmrs_cdm_grps_no_data}; } proc_pdu.start_symbol_index = fapi_pdu.start_symbol_index; diff --git a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp index c4d7b848cd..cf978ec30f 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp @@ -164,7 +164,7 @@ void pusch_processor_impl::process(span data, ulsch_config.nof_rb = nof_rb; ulsch_config.start_symbol_index = pdu.start_symbol_index; ulsch_config.nof_symbols = pdu.nof_symbols; - ulsch_config.dmrs_type = dmrs_type == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2; + ulsch_config.dmrs_type = (dmrs_type == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2); ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; ulsch_config.nof_cdm_groups_without_data = nof_cdm_groups_without_data; ulsch_config.nof_layers = pdu.nof_tx_layers; diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp index 480554877e..7fe9344df1 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp @@ -338,7 +338,7 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) ulsch_config.nof_rb = rb_mask.count(); ulsch_config.start_symbol_index = pdu.start_symbol_index; ulsch_config.nof_symbols = pdu.nof_symbols; - ulsch_config.dmrs_type = dmrs_config.dmrs == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2; + ulsch_config.dmrs_type = (dmrs_config.dmrs == dmrs_type::TYPE1 ? dmrs_config_type::type1 : dmrs_config_type::type2); ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; ulsch_config.nof_cdm_groups_without_data = dmrs_config.nof_cdm_groups_without_data; ulsch_config.nof_layers = pdu.nof_tx_layers; diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp index 9df1ba336d..fa426cef8b 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp @@ -22,8 +22,11 @@ using namespace srsran; namespace { /// Maximum number of layers the PUSCH processor supports. -static constexpr unsigned max_supported_nof_layers = 2; - +constexpr unsigned max_supported_nof_layers = 2; +/// Default DM-RS symbol mask within the slot. +const symbol_slot_mask dmrs_symbol_mask = + {false, false, true, false, false, false, false, false, false, false, false, true, false, false}; +/// Default valid PUSCH processor configuration. const pusch_processor::pdu_t base_pdu = {.context = std::nullopt, .slot = {0, 9}, .rnti = 8323, @@ -36,7 +39,7 @@ const pusch_processor::pdu_t base_pdu = {.context = std::nullopt, .n_id = 935, .nof_tx_layers = 1, .rx_ports = {0, 1, 2, 3}, - .dmrs_symbol_mask = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, + .dmrs_symbol_mask = dmrs_symbol_mask, .dmrs = pusch_processor::dmrs_configuration{.dmrs = dmrs_type::TYPE1, .scrambling_id = 0, .n_scid = false, @@ -45,7 +48,7 @@ const pusch_processor::pdu_t base_pdu = {.context = std::nullopt, .start_symbol_index = 0, .nof_symbols = 14, .tbs_lbrm = units::bytes(ldpc::MAX_CODEBLOCK_SIZE / 8), - .dc_position = std::nullopt}; // namespace + .dc_position = std::nullopt}; struct test_case_t { std::function get_pdu; From dd039be5e20a559a87bd48bef77f172a6507bec7 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 1 Aug 2024 11:47:24 +0200 Subject: [PATCH 041/407] phy: fix complex BF16 add --- lib/srsvec/add.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/srsvec/add.cpp b/lib/srsvec/add.cpp index 10a22c59eb..ca38e9022e 100644 --- a/lib/srsvec/add.cpp +++ b/lib/srsvec/add.cpp @@ -143,7 +143,7 @@ void srsran::srsvec::add(span x, span y, span z srsran_srsvec_assert_size(x, y); srsran_srsvec_assert_size(x, z); - add_ccc_simd(x.data(), y.data(), z.data(), 2 * z.size()); + add_ccc_simd(x.data(), y.data(), z.data(), z.size()); } void srsran::srsvec::add(span x, span y, span z) From 8d4be09dfe711e2ec2ace5902450503df5adf1d8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 25 Jul 2024 16:04:37 +0200 Subject: [PATCH 042/407] phy: refactor PDSCH concurrent fork py: review pseudo-random generator doc --- .../pdsch_codeblock_processor.cpp | 3 + .../pdsch_processor_concurrent_impl.cpp | 134 +++++++----------- .../pdsch_processor_concurrent_impl.h | 4 +- .../pseudo_random_generator_impl.cpp | 4 +- 4 files changed, 62 insertions(+), 83 deletions(-) diff --git a/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp b/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp index 909f3b6fed..df745bde2c 100644 --- a/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp +++ b/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp @@ -20,6 +20,9 @@ pdsch_codeblock_processor::result pdsch_codeblock_processor::process(spaninit(config.c_init); + // Advance scrambling sequence to the specific codeword offset. + scrambler->advance(config.metadata.cb_specific.cw_offset); + // Prepare codeblock data. units::bits nof_used_bits = 0_bits; cb_data.resize(config.cb_size.value()); diff --git a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp index 9bf13ccd0f..4b6a5494cd 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp @@ -226,88 +226,69 @@ unsigned pdsch_processor_concurrent_impl::compute_nof_data_re(const pdu_t& confi void pdsch_processor_concurrent_impl::fork_cb_batches() { - // Minimum number of codeblocks per batch. - unsigned min_cb_batch_size = 4; + // Create a task for eack thread in the pool. + unsigned nof_cb_tasks = cb_processor_pool->capacity(); - // Calculate the number of batches. - unsigned nof_cb_batches = cb_processor_pool->capacity() * 8; - - // Limit the number of batches to ensure a minimum number of CB per batch. - unsigned max_nof_cb_batches = divide_ceil(nof_cb, min_cb_batch_size); - nof_cb_batches = std::min(nof_cb_batches, max_nof_cb_batches); - - // Calculate the actual number of CB per batch. - unsigned cb_batch_size = divide_ceil(nof_cb, nof_cb_batches); + // Limit the number of tasks to the number of codeblocks. + nof_cb_tasks = std::min(nof_cb_tasks, nof_cb); // Set number of codeblock batches. - cb_batch_counter = nof_cb_batches; - - for (unsigned i_cb_batch = 0, i_cb = 0; i_cb_batch != nof_cb_batches; ++i_cb_batch, i_cb += cb_batch_size) { - // Limit batch size for the last batch. - cb_batch_size = std::min(nof_cb - i_cb, cb_batch_size); - - // Extract scrambling initial state for the next bit. - pseudo_random_generator::state_s c_init = scrambler->get_state(); - - auto async_task = [this, cb_batch_size, c_init, i_cb]() { - trace_point process_pdsch_tp = l1_tracer.now(); - - // Select codeblock processor. - pdsch_codeblock_processor& cb_processor = cb_processor_pool->get(); - - // Save scrambling initial state. - pseudo_random_generator::state_s scrambling_state = c_init; - - // For each segment within the batch. - for (unsigned batch_i_cb = 0; batch_i_cb != cb_batch_size; ++batch_i_cb) { - // Calculate the absolute codeblock index. - unsigned absolute_i_cb = i_cb + batch_i_cb; - - // Limit the codeblock number of information bits. - units::bits nof_info_bits = std::min(cb_info_bits, tbs - cb_info_bits * absolute_i_cb); - - // Set CB processor configuration. - pdsch_codeblock_processor::configuration cb_config; - cb_config.tb_offset = cb_info_bits * absolute_i_cb; - cb_config.has_cb_crc = nof_cb > 1; - cb_config.cb_info_size = nof_info_bits; - cb_config.cb_size = segment_length; - cb_config.zero_pad = zero_pad; - cb_config.metadata = cb_metadata; - cb_config.c_init = scrambling_state; - - // Update codeblock specific metadata fields. - cb_config.metadata.cb_specific.cw_offset = cw_offset[absolute_i_cb].value(); - cb_config.metadata.cb_specific.rm_length = rm_length[absolute_i_cb].value(); - - // Process codeblock. - pdsch_codeblock_processor::result result = cb_processor.process(data, cb_config); - - // Build resource grid mapper adaptor. - resource_grid_mapper::symbol_buffer_adapter buffer(result.cb_symbols); - - // Update scrambling sequence state. - scrambling_state = result.scrambling_state; - - // Map into the resource grid. - mapper->map(buffer, allocation, reserved, precoding, re_offset[absolute_i_cb]); - } + cb_task_counter = nof_cb_tasks; + cb_counter = 0; + + auto async_task = [this]() { + trace_point process_pdsch_tp = l1_tracer.now(); + + // Select codeblock processor. + pdsch_codeblock_processor& cb_processor = cb_processor_pool->get(); + + // For each segment within the batch. + unsigned absolute_i_cb; + while ((absolute_i_cb = cb_counter.fetch_add(1)) < nof_cb) { + // Limit the codeblock number of information bits. + units::bits nof_info_bits = std::min(cb_info_bits, tbs - cb_info_bits * absolute_i_cb); + + // Set CB processor configuration. + pdsch_codeblock_processor::configuration cb_config; + cb_config.tb_offset = cb_info_bits * absolute_i_cb; + cb_config.has_cb_crc = nof_cb > 1; + cb_config.cb_info_size = nof_info_bits; + cb_config.cb_size = segment_length; + cb_config.zero_pad = zero_pad; + cb_config.metadata = cb_metadata; + cb_config.c_init = scrambler->get_state(); + + // Update codeblock specific metadata fields. + cb_config.metadata.cb_specific.cw_offset = cw_offset[absolute_i_cb].value(); + cb_config.metadata.cb_specific.rm_length = rm_length[absolute_i_cb].value(); + + // Process codeblock. + pdsch_codeblock_processor::result result = cb_processor.process(data, cb_config); + + // Build resource grid mapper adaptor. + resource_grid_mapper::symbol_buffer_adapter buffer(result.cb_symbols); + + // Map into the resource grid. + mapper->map(buffer, allocation, reserved, precoding, re_offset[absolute_i_cb]); + } - // Decrement code block batch counter. - if (cb_batch_counter.fetch_sub(1) == 1) { - // Decrement asynchronous task counter. - if (async_task_counter.fetch_sub(1) == 1) { - // Notify end of the processing. - notifier->on_finish_processing(); - } + // Decrement code block batch counter. + if (cb_task_counter.fetch_sub(1) == 1) { + // Decrement asynchronous task counter. + if (async_task_counter.fetch_sub(1) == 1) { + // Notify end of the processing. + notifier->on_finish_processing(); } + } - l1_tracer << trace_event("CB batch", process_pdsch_tp); - }; + l1_tracer << trace_event("CB batch", process_pdsch_tp); + }; + // Spawn tasks. + for (unsigned i_task = 0; i_task != nof_cb_tasks; ++i_task) { // Try to execute task asynchronously. bool successful = false; - if (nof_cb_batches != 0) { + if (nof_cb_tasks != 0) { successful = executor.execute(async_task); } @@ -315,13 +296,6 @@ void pdsch_processor_concurrent_impl::fork_cb_batches() if (!successful) { async_task(); } - - // Advance scrambling sequence for the next batch. - if (i_cb_batch != nof_cb_batches - 1) { - units::bits sequence_advance_count = - std::accumulate(rm_length.begin() + i_cb, rm_length.begin() + i_cb + cb_batch_size, units::bits(0)); - scrambler->advance(sequence_advance_count.value()); - } } } diff --git a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h index 62baadaf28..004aab7ed7 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h @@ -117,8 +117,10 @@ class pdsch_processor_concurrent_impl : public pdsch_processor static_vector cw_offset; /// Codeblock resource block offset. static_vector re_offset; + /// Codeblock counter. + std::atomic cb_counter; /// Pending code block batch counter. - std::atomic cb_batch_counter; + std::atomic cb_task_counter; /// Pending asynchronous task counter (DM-RS and CB processing). std::atomic async_task_counter; }; diff --git a/lib/phy/upper/sequence_generators/pseudo_random_generator_impl.cpp b/lib/phy/upper/sequence_generators/pseudo_random_generator_impl.cpp index f25dc46457..9beb0d544a 100644 --- a/lib/phy/upper/sequence_generators/pseudo_random_generator_impl.cpp +++ b/lib/phy/upper/sequence_generators/pseudo_random_generator_impl.cpp @@ -31,8 +31,8 @@ using namespace srsran; /// x_1(n + N_{\textup{C}}) \oplus x_2(n + N_{\textup{C}})\f$. static constexpr unsigned pseudo_random_generator_Nc = 1600; -/// Maximum number of steps that can be the state advanced using the pseudo-random generator fast advance. -static constexpr unsigned pseudo_random_state_fast_advance_max_steps = 1U << 15U; +/// Maximum number of steps that the state can be advanced using the pseudo-random generator fast advance. +static constexpr unsigned pseudo_random_state_fast_advance_max_steps = 1U << 21U; /// Sequence \f$x_1(n)\f$ initializer object. static const pseudo_random_initializer_x1 x1_init(pseudo_random_generator_Nc); From 6dfde488450f1604f461471b8a9464249d9b84fa Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 1 Aug 2024 15:05:05 +0200 Subject: [PATCH 043/407] ci: fix -march for old gcc versions --- .gitlab/ci/build.yml | 70 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 8224648a5b..4a90d971f9 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -928,7 +928,7 @@ package: parallel: matrix: - OS_VERSION: "20.04" - extraopts: -DMARCH=x86-64 + extraopts: -DMARCH=x86-64 -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" @@ -977,16 +977,22 @@ export on amd64: parallel: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] + - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v3 + - OS: ubuntu-20.04 + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" export on amd64 avx512: extends: export on amd64 tags: ["${AMD64_AVX512_TAG}"] parallel: matrix: - - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] + - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v4 + - OS: ubuntu-20.04 + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" # Build + unit tests combinations @@ -1072,7 +1078,8 @@ ubuntu-20.04 amd64 avx2: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - MARCH: x86-64-v3 + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" rhel-8 amd64 avx2: extends: .build_and_unit @@ -1148,6 +1155,8 @@ ubuntu dpdk: - OS: ubuntu-20.04 COMPILER: [gcc, clang] DPDK_VERSION: ["22.11.3", "23.11"] + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" ################### # Alternative OSs # @@ -1347,6 +1356,36 @@ sanitizers amd64 avx2: variables: MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] + parallel: + matrix: + # ubuntu-20.04 disabled due to https://bugs.launchpad.net/ubuntu/+source/gcc-9/+bug/2029910 + # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 + - OS: [ubuntu-24.04, ubuntu-23.10] + SANITIZER: tsan + COMPILER: [gcc, clang] + ENABLE_TSAN: "True" + TEST_MODE: default + - OS: ubuntu-22.04 + SANITIZER: asan + COMPILER: [gcc, clang] + ENABLE_ASAN: "True" + TEST_MODE: default + - OS: ubuntu-20.04 + SANITIZER: asan + COMPILER: [gcc, clang] + ENABLE_ASAN: "True" + TEST_MODE: default + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" + - OS: [ubuntu-24.04, ubuntu-23.10] + SANITIZER: asan + COMPILER: clang + ENABLE_ASAN: "True" + TEST_MODE: default + - OS: [ubuntu-24.04] + SANITIZER: valgrind + COMPILER: gcc + TEST_MODE: valgrind sanitizers amd64 avx512: extends: .weekly sanitizers @@ -1362,11 +1401,18 @@ sanitizers amd64 avx512: COMPILER: [gcc, clang] ENABLE_TSAN: "True" TEST_MODE: default - - OS: [ubuntu-22.04, ubuntu-20.04] + - OS: ubuntu-22.04 SANITIZER: asan COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default + - OS: ubuntu-20.04 + SANITIZER: asan + COMPILER: [gcc, clang] + ENABLE_ASAN: "True" + TEST_MODE: default + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang @@ -1410,6 +1456,8 @@ build uhd alt: - OS: ubuntu-20.04 COMPILER: [gcc, clang] UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" # Build + unit tests combinations @@ -1544,7 +1592,8 @@ ubuntu-20.04 amd64 avx512: matrix: - OS: ubuntu-20.04 <<: *basic_combinations - MARCH: x86-64-v4 + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" ubuntu-20.04 arm native: extends: .build_and_unit @@ -1649,7 +1698,8 @@ ubuntu-20.04 amd64 avx2 dpdk: - OS: ubuntu-20.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3", "23.11"] - MARCH: x86-64-v3 + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" ubuntu-20.04 amd64 avx512 dpdk: extends: .build_and_unit @@ -1664,7 +1714,8 @@ ubuntu-20.04 amd64 avx512 dpdk: - OS: ubuntu-20.04 <<: *basic_combinations_dpdk DPDK_VERSION: ["22.11.3", "23.11"] - MARCH: x86-64-v4 + MARCH: x86-64 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" ubuntu-22.04 amd64 avx2 dpdk: extends: .build_and_unit @@ -1849,7 +1900,8 @@ basic asan: interruptible: false variables: TEST_MODE: none - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" -DEXIT_TIMEOUT=15 + MARCH: x86-64-v3 + BUILD_ARGS: -DEXIT_TIMEOUT=15 tags: ["${AMD64_AVX2_TAG}"] after_script: - *build_after_script From eccf90389e9195f41e515ff57cc0eb919a71dc05 Mon Sep 17 00:00:00 2001 From: Oriol Font-Bach Date: Thu, 1 Aug 2024 14:39:50 +0000 Subject: [PATCH 044/407] ACC100 integration (through plugins and a set of dynamic libraries only available in the enterprise implementation) --- CMakeLists.txt | 15 +- apps/gnb/CMakeLists.txt | 8 + apps/units/flexible_du/du_low/CMakeLists.txt | 11 +- apps/units/flexible_du/du_low/du_low_config.h | 68 ++++ .../du_low/du_low_config_cli11_schema.cpp | 95 +++++ .../du_low/du_low_config_translator.cpp | 19 +- .../du_low/du_low_config_translator.h | 1 + .../du_low/du_low_config_validator.cpp | 32 +- .../du_low/du_low_wrapper_config_helper.cpp | 31 +- .../du_low/du_low_wrapper_config_helper.h | 1 + .../flexible_du/split_dynamic/CMakeLists.txt | 11 +- .../split_dynamic/dynamic_du_factory.cpp | 83 ++++ include/srsran/hal/dpdk/bbdev/bbdev_acc.h | 94 ++--- .../srsran/hal/dpdk/bbdev/bbdev_acc_factory.h | 37 +- .../hw_accelerator_factories.h | 31 +- .../hw_accelerator_pdsch_enc.h | 8 +- .../pusch/hw_accelerator_factories.h | 31 +- .../channel_processors/pusch/factories.h | 2 + .../srsran/phy/upper/upper_phy_factories.h | 37 +- lib/du/CMakeLists.txt | 11 +- lib/du_low/CMakeLists.txt | 11 +- lib/du_low/du_low_factory.cpp | 14 +- lib/hal/dpdk/CMakeLists.txt | 2 + lib/hal/dpdk/bbdev/CMakeLists.txt | 13 +- lib/hal/dpdk/bbdev/bbdev.cpp | 165 -------- lib/hal/dpdk/bbdev/bbdev.h | 51 --- lib/hal/dpdk/bbdev/bbdev_acc.cpp | 115 ------ lib/hal/dpdk/bbdev/bbdev_acc_factory.cpp | 24 +- lib/hal/dpdk/bbdev/bbdev_op_pool_factory.cpp | 30 -- .../dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp | 357 ------------------ lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.h | 103 ----- .../dpdk/bbdev/ldpc/bbdev_ldpc_encoder.cpp | 229 ----------- lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.h | 79 ---- .../dpdk/bbdev/plugin_bbdev_acc_factory.cpp | 151 ++++++++ lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.h | 22 ++ .../upper/channel_processors/CMakeLists.txt | 5 +- .../hw_accelerator_factories.cpp | 64 +--- .../hw_accelerator_pdsch_enc_acc100_impl.cpp | 207 ---------- .../hw_accelerator_pdsch_enc_acc100_impl.h | 142 ------- .../hw_accelerator_pdsch_enc_impl.cpp | 53 --- .../hw_accelerator_pdsch_enc_impl.h | 61 --- .../plugin_bbdev_pdsch_enc_acc_factory.cpp | 156 ++++++++ .../plugin_bbdev_pdsch_enc_acc_factory.h | 25 ++ .../channel_processors/pusch/CMakeLists.txt | 7 +- .../pusch/hw_accelerator_factories.cpp | 64 +--- .../hw_accelerator_pusch_dec_acc100_impl.cpp | 264 ------------- .../hw_accelerator_pusch_dec_acc100_impl.h | 155 -------- .../pusch/hw_accelerator_pusch_dec_impl.cpp | 60 --- .../pusch/hw_accelerator_pusch_dec_impl.h | 66 ---- .../plugin_bbdev_pusch_dec_acc_factory.cpp | 164 ++++++++ .../plugin_bbdev_pusch_dec_acc_factory.h | 25 ++ lib/phy/upper/CMakeLists.txt | 12 +- .../pdsch_encoder_hw_impl.cpp | 11 +- .../pdsch_encoder_hw_impl.h | 5 +- .../channel_processors/pusch/factories.cpp | 27 +- .../pusch/pusch_decoder_hw_impl.cpp | 106 ++++-- .../pusch/pusch_decoder_hw_impl.h | 109 +++--- lib/phy/upper/upper_phy_factories.cpp | 105 ++++-- .../pdsch_encoder_hwacc_benchmark.cpp | 15 +- .../pdsch_processor_benchmark.cpp | 24 +- .../pusch/pusch_decoder_hwacc_benchmark.cpp | 18 +- .../pusch/pusch_processor_benchmark.cpp | 41 +- .../upper/channel_processors/CMakeLists.txt | 15 +- .../channel_processors/pxsch_bler_test.cpp | 92 +++-- .../pxsch_bler_test_factories.cpp | 168 ++++++++- .../pxsch_bler_test_factories.h | 20 +- .../channel_processors/pdsch_encoder_test.cpp | 15 +- .../pdsch_processor_vectortest.cpp | 92 ++++- .../pusch/pusch_decoder_vectortest.cpp | 16 +- .../pusch/pusch_processor_vectortest.cpp | 102 ++++- 70 files changed, 1887 insertions(+), 2616 deletions(-) delete mode 100644 lib/hal/dpdk/bbdev/bbdev.cpp delete mode 100644 lib/hal/dpdk/bbdev/bbdev.h delete mode 100644 lib/hal/dpdk/bbdev/bbdev_acc.cpp delete mode 100644 lib/hal/dpdk/bbdev/bbdev_op_pool_factory.cpp delete mode 100644 lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp delete mode 100644 lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.h delete mode 100644 lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.cpp delete mode 100644 lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.h create mode 100644 lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.cpp create mode 100644 lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.h delete mode 100644 lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.cpp delete mode 100644 lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.h delete mode 100644 lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.cpp delete mode 100644 lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.h create mode 100644 lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.cpp create mode 100644 lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.h delete mode 100644 lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.cpp delete mode 100644 lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.h delete mode 100644 lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.cpp delete mode 100644 lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.h create mode 100644 lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.cpp create mode 100644 lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ac6a39ded0..e06e212261 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,16 +94,13 @@ endif () # Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. if (ENABLE_DPDK) - # Make sure that library export is disabed, as it is not compatible with hardware acceleration. - if (NOT ENABLE_EXPORT) - SET(ENABLE_PDSCH_HWACC ON CACHE BOOL "Enable PDSCH hardware-acceleration") - message(STATUS "Hardware-acceleration enabled for PDSCH.") - SET(ENABLE_PUSCH_HWACC ON CACHE BOOL "Enable PUSCH hardware-acceleration") - message(STATUS "Hardware-acceleration enabled for PUSCH.") - endif () + SET(ENABLE_PDSCH_HWACC ON CACHE BOOL "Enable PDSCH hardware-acceleration") + message(STATUS "Hardware-acceleration enabled for PDSCH.") + SET(ENABLE_PUSCH_HWACC ON CACHE BOOL "Enable PUSCH hardware-acceleration") + message(STATUS "Hardware-acceleration enabled for PUSCH.") else (ENABLE_DPDK) - unset(ENABLE_PDSCH_HWACC CACHE) - unset(ENABLE_PUSCH_HWACC CACHE) + unset(ENABLE_PDSCH_HWACC CACHE) + unset(ENABLE_PUSCH_HWACC CACHE) endif (ENABLE_DPDK) ######################################################################## diff --git a/apps/gnb/CMakeLists.txt b/apps/gnb/CMakeLists.txt index f6398d7721..092ecd70fc 100644 --- a/apps/gnb/CMakeLists.txt +++ b/apps/gnb/CMakeLists.txt @@ -42,6 +42,14 @@ target_link_libraries(gnb if (DPDK_FOUND) add_definitions(-DDPDK_FOUND) target_link_libraries(gnb hal_dpdk) + if (ENABLE_PUSCH_HWACC) + add_definitions(-DENABLE_PUSCH_HWACC) + target_link_libraries(gnb hal_hwacc_pusch hal_bbdev_factory) + endif (ENABLE_PUSCH_HWACC) + if (ENABLE_PDSCH_HWACC) + add_definitions(-DENABLE_PDSCH_HWACC) + target_link_libraries(gnb hal_hwacc_pdsch hal_bbdev_factory) + endif (ENABLE_PDSCH_HWACC) endif (DPDK_FOUND) add_backward(gnb) diff --git a/apps/units/flexible_du/du_low/CMakeLists.txt b/apps/units/flexible_du/du_low/CMakeLists.txt index 89756d5bb9..f11ddafa4e 100644 --- a/apps/units/flexible_du/du_low/CMakeLists.txt +++ b/apps/units/flexible_du/du_low/CMakeLists.txt @@ -15,4 +15,13 @@ set(SOURCES add_library(srsran_du_low_unit_helpers STATIC ${SOURCES}) target_include_directories(srsran_du_low_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_du_low_unit_helpers srsran_upper_phy) +set(DU_LOW_UNIT_HELPERS_LIBRARIES srsran_upper_phy) + +# Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. +if (DPDK_FOUND) + set_source_files_properties(${SOURCES} PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + list(APPEND DU_LOW_UNIT_HELPERS_LIBRARIES hal_hwacc_pusch + hal_hwacc_pdsch + hal_bbdev_factory) +endif (DPDK_FOUND) +target_link_libraries(srsran_du_low_unit_helpers PUBLIC ${DU_LOW_UNIT_HELPERS_LIBRARIES}) diff --git a/apps/units/flexible_du/du_low/du_low_config.h b/apps/units/flexible_du/du_low/du_low_config.h index 30c1d8f6f6..922e725da7 100644 --- a/apps/units/flexible_du/du_low/du_low_config.h +++ b/apps/units/flexible_du/du_low/du_low_config.h @@ -46,6 +46,7 @@ struct du_low_unit_expert_upper_phy_config { /// DU low logging functionalities. struct du_low_unit_logger_config { srslog::basic_levels phy_level = srslog::basic_levels::warning; + srslog::basic_levels hal_level = srslog::basic_levels::warning; /// Set to true to log broadcasting messages and all PRACH opportunities. bool broadcast_enabled = false; /// Maximum number of bytes to write when dumping hex arrays. @@ -123,6 +124,71 @@ struct du_low_unit_expert_execution_config { std::vector cell_affinities = {{}}; }; +/// Hardware-accelerated PDSCH encoder configuration of the DU low. +struct hwacc_pdsch_appconfig { + /// \brief Number of hardware-accelerated PDSCH encoding functions. + unsigned nof_hwacc; + /// \brief Operation mode of the PDSCH encoder (CB = true, TB = false [default]). + bool cb_mode = false; + /// \brief Maximum supported buffer size in bytes (CB mode will be forced for larger TBs). Only used in TB mode to + /// size the mbufs. + /// + /// Set to the maximum supported size by default. + std::optional max_buffer_size; + /// \brief Type of hardware queue usage (dedicated = true [default], shared = false). In case of a shared usage, the + /// accelerated function needs to reseve a hardware-queue for each operation. + bool dedicated_queue = true; +}; + +/// Hardware-accelerated PUSCH decoder configuration of the DU low. +struct hwacc_pusch_appconfig { + /// \brief Number of hardware-accelerated PUSCH decoding functions. + unsigned nof_hwacc; + /// \brief Defines if the soft-buffer is implemented in the accelerator (true [default]) or not (false). + bool ext_softbuffer = true; + /// \brief Size of the HARQ context repository. + /// + /// Set to the maximum number of CBs supported by the gNB config by default. + std::optional harq_context_size; + /// \brief Type of hardware queue usage (dedicated = true [default], shared = false). In case of a shared usage, the + /// accelerated function needs to reseve a hardware-queue for each operation. + bool dedicated_queue = true; +}; + +/// BBDEV configuration of the DU low. +struct bbdev_appconfig { + /// \brief Type of BBDEV hardware-accelerator. + std::string bbdev_acc_type = "srs"; + /// \brief Type of BBDEV hardware-accelerator. + std::string hwacc_type; + /// \brief ID of the BBDEV-based hardware-accelerator. + unsigned id; + /// \brief Structure providing the configuration of hardware-accelerated PDSCH encoding functions. + std::optional pdsch_enc; + /// \brief Structure providing the configuration of hardware-accelerated PUSCH decoding functions. + std::optional pusch_dec; + /// \brief Size (in bytes) of each DPDK memory buffer (mbuf) used to exchange unencoded and unrate-matched messages + /// with the accelerator. + /// + /// Set to the maximum supported size by default. + std::optional msg_mbuf_size; + /// \brief Size (in bytes) of each DPDK memory buffer (mbuf) used to exchange encoded and rate-matched messages with + /// the accelerator. + /// + /// Set to the maximum supported size by default. + std::optional rm_mbuf_size; + /// \brief Number of DPDK memory buffers (mbufs) in each memory pool. + /// + /// Set to the maximum number of CBs supported by the gNB config by default. + std::optional nof_mbuf; +}; + +// HAL configuration of the DU low. +struct du_low_unit_hal_config { + /// BBDEV-based hardware-accelerator arguments. + std::optional bbdev_hwacc; +}; + /// DU low configuration. struct du_low_unit_config { /// Loggers. @@ -131,6 +197,8 @@ struct du_low_unit_config { du_low_unit_expert_upper_phy_config expert_phy_cfg; /// Expert execution parameters for the DU low. du_low_unit_expert_execution_config expert_execution_cfg; + /// HAL configuration. + std::optional hal_config; }; } // namespace srsran 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 45d461e8fa..391f1a75d1 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 @@ -33,6 +33,7 @@ static expected parse_int(const std::string& value) static void configure_cli11_log_args(CLI::App& app, du_low_unit_logger_config& log_params) { app_services::add_log_option(app, log_params.phy_level, "--phy_level", "PHY log level"); + app_services::add_log_option(app, log_params.hal_level, "--hal_level", "HAL log level"); add_option(app, "--broadcast_enabled", @@ -200,6 +201,94 @@ static void configure_cli11_expert_phy_args(CLI::App& app, du_low_unit_expert_up ->check(CLI::Range(0, 30)); } +static void configure_cli11_hwacc_pdsch_enc_args(CLI::App& app, std::optional& config) +{ + config.emplace(); + + app.add_option("--nof_hwacc", config->nof_hwacc, "Number of hardware-accelerated PDSCH encoding functions") + ->capture_default_str() + ->check(CLI::Range(0, 64)); + app.add_option("--cb_mode", config->cb_mode, "Operation mode of the PDSCH encoder (CB = true, TB = false [default])") + ->capture_default_str(); + app.add_option("--max_buffer_size", + config->max_buffer_size, + "Maximum supported buffer size in bytes (CB mode will be forced for larger TBs)") + ->capture_default_str(); + app.add_option("--dedicated_queue", + config->dedicated_queue, + "Hardware queue use for the PDSCH encoder (dedicated = true [default], shared = false)") + ->capture_default_str(); +} +static void configure_cli11_hwacc_pusch_dec_args(CLI::App& app, std::optional& config) +{ + config.emplace(); + + app.add_option("--nof_hwacc", config->nof_hwacc, "Number of hardware-accelerated PDSCH encoding functions") + ->capture_default_str() + ->check(CLI::Range(0, 64)); + app.add_option("--ext_softbuffer", + config->ext_softbuffer, + "Defines if the soft-buffer is implemented in the accelerator or not") + ->capture_default_str(); + app.add_option("--harq_context_size", config->harq_context_size, "Size of the HARQ context repository") + ->capture_default_str(); + app.add_option("--dedicated_queue", + config->dedicated_queue, + "Hardware queue use for the PUSCH decoder (dedicated = true [default], shared = false)") + ->capture_default_str(); +} + +static void configure_cli11_bbdev_hwacc_args(CLI::App& app, std::optional& config) +{ + config.emplace(); + + app.add_option("--bbdev_acc_type", config->hwacc_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() + ->check(CLI::Range(0, 65535)); + + // (Optional) Hardware-accelerated PDSCH encoding functions configuration. + CLI::App* hwacc_pdsch_enc_subcmd = + app.add_subcommand("pdsch_enc", "Hardware-accelerated PDSCH encoding functions configuration"); + configure_cli11_hwacc_pdsch_enc_args(*hwacc_pdsch_enc_subcmd, config->pdsch_enc); + + // (Optional) Hardware-accelerated PUSCH decoding functions configuration. + CLI::App* hwacc_pusch_dec_subcmd = + app.add_subcommand("pusch_dec", "Hardware-accelerated PUSCH decoding functions configuration"); + configure_cli11_hwacc_pusch_dec_args(*hwacc_pusch_dec_subcmd, config->pusch_dec); + + app.add_option("--msg_mbuf_size", + config->msg_mbuf_size, + "Size of the mbufs storing unencoded and unrate-matched messages (in bytes)") + ->capture_default_str() + ->check(CLI::Range(0, 64000)); + app.add_option("--rm_mbuf_size", + config->rm_mbuf_size, + "Size of the mbufs storing encoded and rate-matched messages (in bytes)") + ->capture_default_str() + ->check(CLI::Range(0, 64000)); + app.add_option("--nof_mbuf", config->nof_mbuf, "Number of mbufs in the memory pool")->capture_default_str(); +} + +static void configure_cli11_hal_args(CLI::App& app, std::optional& config) +{ + config.emplace(); + + // (Optional) BBDEV-based hardware-accelerator configuration. + CLI::App* bbdev_hwacc_subcmd = + add_subcommand(app, "bbdev_hwacc", "BBDEV-based hardware-acceleration configuration parameters"); + configure_cli11_bbdev_hwacc_args(*bbdev_hwacc_subcmd, config->bbdev_hwacc); +} + +static void manage_hal_optional(CLI::App& app, du_low_unit_config& parsed_cfg) +{ + // Clean the HAL optional. + if (app.get_subcommand("hal")->count_all() == 0) { + parsed_cfg.hal_config.reset(); + } +} + void srsran::configure_cli11_with_du_low_config_schema(CLI::App& app, du_low_unit_config& parsed_cfg) { // Loggers section. @@ -214,6 +303,10 @@ void srsran::configure_cli11_with_du_low_config_schema(CLI::App& app, du_low_uni // Expert execution section. CLI::App* expert_subcmd = add_subcommand(app, "expert_execution", "Expert execution configuration")->configurable(); configure_cli11_expert_execution_args(*expert_subcmd, parsed_cfg.expert_execution_cfg); + + // HAL section. + CLI::App* hal_subcmd = add_subcommand(app, "hal", "HAL configuration")->configurable(); + configure_cli11_hal_args(*hal_subcmd, parsed_cfg.hal_config); } void srsran::autoderive_du_low_parameters_after_parsing(CLI::App& app, @@ -253,4 +346,6 @@ void srsran::autoderive_du_low_parameters_after_parsing(CLI::App& app, if (parsed_cfg.expert_execution_cfg.cell_affinities.size() < nof_cells) { parsed_cfg.expert_execution_cfg.cell_affinities.resize(nof_cells); } + + manage_hal_optional(app, parsed_cfg); } 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 df2d12dda8..54f83696d1 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 @@ -17,11 +17,12 @@ using namespace srsran; -static void generate_du_low_config(du_low_config& out_config, - const du_low_unit_config& du_low, - span du_cells, - span max_puschs_per_slot, - unsigned du_id) +static void generate_du_low_config(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) { out_config.cells.reserve(du_cells.size()); @@ -29,6 +30,9 @@ static void generate_du_low_config(du_low_config& out_config, const 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); @@ -158,11 +162,12 @@ static void generate_du_low_config(du_low_config& out_config, void srsran::generate_du_low_wrapper_config(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) { - generate_du_low_config(out_config.du_low_cfg, du_low_unit_cfg, du_cells, max_puschs_per_slot, 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); -} \ No newline at end of file +} 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 8a9b2d78f6..27a764252d 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 @@ -21,6 +21,7 @@ struct du_low_unit_config; void generate_du_low_wrapper_config(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, diff --git a/apps/units/flexible_du/du_low/du_low_config_validator.cpp b/apps/units/flexible_du/du_low/du_low_config_validator.cpp index 362def5cbc..a3a14eeeff 100644 --- a/apps/units/flexible_du/du_low/du_low_config_validator.cpp +++ b/apps/units/flexible_du/du_low/du_low_config_validator.cpp @@ -15,7 +15,9 @@ using namespace srsran; static bool validate_upper_phy_threads_appconfig(const du_low_unit_expert_threads_config& config, - unsigned max_processing_delay_slots) + unsigned max_processing_delay_slots, + unsigned nof_hwacc_pdsch, + unsigned nof_hwacc_pusch) { static const interval nof_ul_dl_threads_range(1, std::thread::hardware_concurrency()); static const interval nof_pdsch_threads_range(2, std::thread::hardware_concurrency()); @@ -47,6 +49,24 @@ static bool validate_upper_phy_threads_appconfig(const du_low_unit_expert_thread valid = false; } +#ifdef DPDK_FOUND + if (config.nof_dl_threads > nof_hwacc_pdsch) { + fmt::print("Not enough hardware-accelerated PDSCH encoder functions. Number of PHY DL threads (i.e., {}) must be " + "in range {}.\n", + config.nof_dl_threads, + nof_hwacc_pdsch); + valid = false; + } + if ((config.nof_ul_threads + config.nof_pusch_decoder_threads) > nof_hwacc_pusch) { + fmt::print("Not enough hardware-accelerated PUSCH decoder functions. Combined number of PHY UL threads (i.e., {}) " + "and PUSCH decoder threads (i.e., {}) must be in range {}.\n", + config.nof_ul_threads, + config.nof_pusch_decoder_threads, + nof_hwacc_pusch); + valid = false; + } +#endif // DPDK_FOUND + return valid; } @@ -54,8 +74,16 @@ static bool validate_expert_execution_unit_config(const du_low_unit_config& unsigned nof_cells, const os_sched_affinity_bitmask& available_cpus) { + unsigned nof_hwacc_pdsch = 0; + unsigned nof_hwacc_pusch = 0; +#ifdef DPDK_FOUND + nof_hwacc_pdsch = config.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc; + nof_hwacc_pusch = config.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc; +#endif // DPDK_FOUND if (!validate_upper_phy_threads_appconfig(config.expert_execution_cfg.threads, - config.expert_phy_cfg.max_processing_delay_slots)) { + config.expert_phy_cfg.max_processing_delay_slots, + nof_hwacc_pdsch, + nof_hwacc_pusch)) { return false; } 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 196cdd94f2..502b1a1a9a 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 @@ -17,28 +17,35 @@ using namespace srsran; static void generate_dl_processor_config(downlink_processor_factory_sw_config& out_cfg, const du_low_unit_config& unit_cfg, - task_executor& pdsch_codeblock_executor) + task_executor& pdsch_codeblock_executor, + bool hwacc_pdsch_processor) { out_cfg.ldpc_encoder_type = "auto"; out_cfg.crc_calculator_type = "auto"; const du_low_unit_expert_threads_config& upper_phy_threads_cfg = unit_cfg.expert_execution_cfg.threads; - if ((upper_phy_threads_cfg.pdsch_processor_type == "lite") || - ((upper_phy_threads_cfg.pdsch_processor_type == "auto") && (upper_phy_threads_cfg.nof_dl_threads == 1))) { + // Hardware-acceleration is currently supported for 'generic' PDSCH processor types only. + if ((!hwacc_pdsch_processor) && + ((upper_phy_threads_cfg.pdsch_processor_type == "lite") || + ((upper_phy_threads_cfg.pdsch_processor_type == "auto") && (upper_phy_threads_cfg.nof_dl_threads == 1)))) { out_cfg.pdsch_processor.emplace(); - } else if ((upper_phy_threads_cfg.pdsch_processor_type == "concurrent") || - ((upper_phy_threads_cfg.pdsch_processor_type == "auto") && (upper_phy_threads_cfg.nof_dl_threads > 1))) { + } else if ((!hwacc_pdsch_processor) && + ((upper_phy_threads_cfg.pdsch_processor_type == "concurrent") || + ((upper_phy_threads_cfg.pdsch_processor_type == "auto") && (upper_phy_threads_cfg.nof_dl_threads > 1)))) { pdsch_processor_concurrent_configuration pdsch_proc_config; pdsch_proc_config.nof_pdsch_codeblock_threads = upper_phy_threads_cfg.nof_dl_threads; pdsch_proc_config.max_nof_simultaneous_pdsch = (MAX_UE_PDUS_PER_SLOT + 1) * unit_cfg.expert_phy_cfg.max_processing_delay_slots; pdsch_proc_config.pdsch_codeblock_task_executor = &pdsch_codeblock_executor; out_cfg.pdsch_processor.emplace(pdsch_proc_config); - } else if (upper_phy_threads_cfg.pdsch_processor_type == "generic") { + } else if ((hwacc_pdsch_processor) || (upper_phy_threads_cfg.pdsch_processor_type == "generic")) { out_cfg.pdsch_processor.emplace(); } else { - srsran_assert(false, "Invalid PDSCH processor type {}.", upper_phy_threads_cfg.pdsch_processor_type); + srsran_assert(false, + "Invalid {}PDSCH processor type {}.", + hwacc_pdsch_processor ? "hardware-accelerated " : "", + upper_phy_threads_cfg.pdsch_processor_type); } out_cfg.nof_concurrent_threads = upper_phy_threads_cfg.nof_dl_threads; } @@ -46,6 +53,7 @@ static void generate_dl_processor_config(downlink_processor_factory_sw_config& o void srsran::make_du_low_wrapper_config_and_dependencies( 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, @@ -57,13 +65,16 @@ 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, std::move(prach_ports), du_cells, max_puschs_per_slot, du_id); + out_cfg, du_low_unit_cfg, hal_config, std::move(prach_ports), du_cells, max_puschs_per_slot, du_id); // Fill the workers information. for (unsigned i = 0, e = out_cfg.du_low_cfg.cells.size(); i != e; ++i) { du_low_cell_config& cell = out_cfg.du_low_cfg.cells[i]; - generate_dl_processor_config(cell.dl_proc_cfg, du_low_unit_cfg, *workers.upper_pdsch_exec[i + du_id]); + generate_dl_processor_config(cell.dl_proc_cfg, + du_low_unit_cfg, + *workers.upper_pdsch_exec[i + du_id], + cell.upper_phy_cfg.hal_config.hwacc_pdsch_processor); upper_phy_config& upper = cell.upper_phy_cfg; upper.rg_gateway = &rg_gateway; @@ -75,4 +86,4 @@ void srsran::make_du_low_wrapper_config_and_dependencies( upper.srs_executor = workers.upper_srs_exec[i + du_id]; workers.get_du_low_dl_executors(upper.dl_executors, i + du_id); } -} \ No newline at end of file +} 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 6cd1837377..0f8944c437 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 @@ -21,6 +21,7 @@ struct du_low_unit_config; void make_du_low_wrapper_config_and_dependencies(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_dynamic/CMakeLists.txt b/apps/units/flexible_du/split_dynamic/CMakeLists.txt index 00c77d4501..95f0fcd171 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_dynamic STATIC ${SOURCES}) target_include_directories(srsran_flexible_du_dynamic PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_flexible_du_dynamic +set(FLEXIBLE_DU_DYNAMIC_LIBRARIES srsran_du_wrapper srsran_ru_dummy srsran_pcap @@ -27,3 +27,12 @@ target_link_libraries(srsran_flexible_du_dynamic 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_DYNAMIC_LIBRARIES hal_hwacc_pusch + hal_hwacc_pdsch + hal_bbdev_factory) +endif (DPDK_FOUND) +target_link_libraries(srsran_flexible_du_dynamic ${FLEXIBLE_DU_DYNAMIC_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 e167d48b07..992d8a544e 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp @@ -25,6 +25,13 @@ #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; @@ -134,6 +141,81 @@ du_unit srsran::create_du(const dynamic_du_unit_config& dyn_du_cfg, 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. du_wrapper_config du_cfg = {}; @@ -143,6 +225,7 @@ du_unit srsran::create_du(const dynamic_du_unit_config& dyn_du_cfg, 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/include/srsran/hal/dpdk/bbdev/bbdev_acc.h b/include/srsran/hal/dpdk/bbdev/bbdev_acc.h index eb2300a31e..f7bc0a0968 100644 --- a/include/srsran/hal/dpdk/bbdev/bbdev_acc.h +++ b/include/srsran/hal/dpdk/bbdev/bbdev_acc.h @@ -47,109 +47,57 @@ struct bbdev_acc_configuration { unsigned nof_mbuf = 256; }; -/// Abstracted interfacing to bbdev-based hardware-accelerators. +/// Wireless Baseband Device (bbdev) interface. class bbdev_acc { public: - /// Constructor. - /// \param[in] cfg Configuration parameters of the bbdev-based hardware-accelerator. - /// \param[in] info bbdev Device information. - /// \param[in] logger SRS logger. - explicit bbdev_acc(const bbdev_acc_configuration& cfg, const ::rte_bbdev_info& info_, srslog::basic_logger& logger); - - /// Destructor. - ~bbdev_acc(); + /// Default destructor. + virtual ~bbdev_acc() = default; /// Returns the ID of the bbdev-based hardware-accelerator device. - /// \return Device ID. - unsigned get_device_id() const { return id; } + virtual unsigned get_device_id() const = 0; /// Returns the ID of the socket used by the bbdev-based hardware-accelerator. - /// \return Socket ID. - int get_socket_id() const { return info.socket_id; } + virtual int get_socket_id() const = 0; /// Returns the number of LDPC encoder cores provided by the bbdev-based hardware-accelerator. - /// \return Number of LDPC encoder cores. - unsigned get_nof_ldpc_enc_cores() const { return nof_ldpc_enc_lcores; } + virtual unsigned get_nof_ldpc_enc_cores() const = 0; /// Returns the number of LDPC decoder cores provided by the bbdev-based hardware-accelerator. - /// \return Number of LDPC decoder cores. - unsigned get_nof_ldpc_dec_cores() const { return nof_ldpc_dec_lcores; } + virtual unsigned get_nof_ldpc_dec_cores() const = 0; /// Returns the number of FFT cores provided by the bbdev-based hardware-accelerator. - /// \return Number of FFT cores. - unsigned get_nof_fft_cores() const { return nof_fft_lcores; } + virtual unsigned get_nof_fft_cores() const = 0; /// Returns the size of the (external) HARQ buffer size embedded in the hardware-accelerator. - /// \return HARQ buffer size in bytes. Note that 64 bits are used to enable sizes >= 4GB. - uint64_t get_harq_buff_size_bytes() const { return static_cast(info.drv.harq_buffer_size) * 1024; } + virtual uint64_t get_harq_buff_size_bytes() const = 0; /// Returns the size of each mbuf used to exchange unencoded and unrate-matched messages with the accelerator. - /// \return Unencoded and unrate-matched mbuf size (in bytes). - units::bytes get_msg_mbuf_size() const { return units::bytes(msg_mbuf_size); } + virtual units::bytes get_msg_mbuf_size() const = 0; /// Returns the size of each mbuf used to exchange encoded and rate-matched messages with the accelerator. - /// \return Encoded and rate-matched mbuf size (in bytes). - units::bytes get_rm_mbuf_size() const { return units::bytes(rm_mbuf_size); } + virtual units::bytes get_rm_mbuf_size() const = 0; /// Returns the number of mbufs in each memory pool used to exchange data with the accelerator. - /// \return Number of mbufs. - unsigned get_nof_mbuf() const { return nof_mbuf; } + virtual unsigned get_nof_mbuf() const = 0; /// Returns the internal SRS logger. - /// \return SRS logger. - srslog::basic_logger& get_logger() { return logger; } + virtual srslog::basic_logger& get_logger() = 0; - /// Reserves a free queue to be used by a specific hardware-accelerated channel processor function. + /// \brief Reserves a free queue to be used by a specific hardware-accelerated channel processor function. /// \param[in] op_type Type of bbdev op. - /// \return ID of the reserved queue. - int reserve_queue(::rte_bbdev_op_type op_type); + /// \return The identifier of the reserved queue if successful, otherwise a negative integer. + virtual int reserve_queue(::rte_bbdev_op_type op_type) = 0; - /// Frees a queue used by a specific hardware-accelerated channel processor function. - /// \param[in] queue_id ID of the queue to be freed. - void free_queue(::rte_bbdev_op_type op_type, unsigned queue_id); + /// \brief Frees a queue used by a specific hardware-accelerated channel processor function. + /// \param[in] queue_id Identifier of the queue to be freed. + virtual void free_queue(::rte_bbdev_op_type op_type, unsigned queue_id) = 0; /// Returns a unique ID for an instance of an LDPC encoder using the bbdev-based accelerator. - /// \return Encoder ID. - unsigned reserve_encoder() { return nof_ldpc_enc_instances++; } + virtual unsigned reserve_encoder() = 0; /// Returns a unique ID for an instance of an LDPC decoder using the bbdev-based accelerator. - /// \return Decoder ID. - unsigned reserve_decoder() { return nof_ldpc_dec_instances++; } - -private: - /// Codeblock identifier list type. - using queue_id_list = - concurrent_queue; - - /// ID of the bbdev-based hardware-accelerator. - unsigned id; - /// Structure providing device information. - ::rte_bbdev_info info; - /// Number of lcores available to the hardware-accelerated LDPC encoder (disabled if 0). - unsigned nof_ldpc_enc_lcores; - /// Number of lcores available to the hardware-accelerated LDPC decoder (disabled if 0). - unsigned nof_ldpc_dec_lcores; - /// Number of lcores available to the hardware-accelerated FFT (disabled if 0). - unsigned nof_fft_lcores; - /// List containing the free queue ids for hardware-acclerated LDPC encoder functions. - queue_id_list available_ldpc_enc_queue; - /// List containing the free queue ids for hardware-acclerated LDPC decoder functions. - queue_id_list available_ldpc_dec_queue; - /// List containing the free queue ids for hardware-acclerated FFT functions. - queue_id_list available_fft_queue; - /// Size of each mbuf used to exchange unencoded and unrate-matched messages with the accelerator in bytes. - unsigned msg_mbuf_size; - /// Size of each mbuf used to exchange encoded and rate-matched messages with the accelerator in bytes. - unsigned rm_mbuf_size; - /// Number of mbufs in each memory pool. - unsigned nof_mbuf; - /// SRS logger. - srslog::basic_logger& logger; - /// Number of LDPC encoder instances using this bbdev accelerator. - unsigned nof_ldpc_enc_instances; - /// Number of LDPC decoder instances using this bbdev accelerator. - unsigned nof_ldpc_dec_instances; + virtual unsigned reserve_decoder() = 0; }; } // namespace dpdk diff --git a/include/srsran/hal/dpdk/bbdev/bbdev_acc_factory.h b/include/srsran/hal/dpdk/bbdev/bbdev_acc_factory.h index 833224e451..163e3432f7 100644 --- a/include/srsran/hal/dpdk/bbdev/bbdev_acc_factory.h +++ b/include/srsran/hal/dpdk/bbdev/bbdev_acc_factory.h @@ -11,12 +11,45 @@ #pragma once #include "srsran/hal/dpdk/bbdev/bbdev_acc.h" +#include namespace srsran { namespace dpdk { -/// Returns a bbdev_acc instance on success, otherwise returns nullptr. -std::shared_ptr create_bbdev_acc(const bbdev_acc_configuration& cfg, srslog::basic_logger& logger); +/// Describes a bbdev accelerator factory for a determined accelerator implementation. +class bbdev_acc_factory +{ +public: + /// Default destructor. + virtual ~bbdev_acc_factory() = default; + + /// \brief Creates a bbdev accelerator instance with the given configuration parameters. + /// \param[in] cfg Configuration of the bbdev hardware-accelerator. + /// \param[in] logger SRS logger. + /// \return The ownership to a bbdev accelerator on success, otherwise returns nullptr. + virtual std::shared_ptr create(const bbdev_acc_configuration& cfg, srslog::basic_logger& logger) = 0; +}; + +/// \brief Dynamic library bbdev accelerator factory creation entry point. +/// +/// The dynamic library handler loads this function from an external library to create a bbdev accelerator factory. +std::unique_ptr create_dynamic_bbdev_acc_factory() asm("create_dynamic_bbdev_acc_factory"); + +/// \brief Creates a bbdev accelerator factory. +/// +/// This function dynamically loads a shared library corresponding to the specified implementation name and retrieves +/// the factory creation function from it. +/// +/// The naming convention for the shared library is as follows: if the implementation name is \c custom, the library +/// name is expected to be \c libsrsran_bbdev_acc_custom.so. By default, the function tries to load +/// \c libsrsran_bbdev_acc_srs.so. The dynamic library must contain the function prototype +/// \ref create_dynamic_bbdev_acc_factory. +/// +/// Ensure that \c LD_LIBRARY_PATH environment variable includes the path where the dynamic libraries are located. +/// +/// \param[in] impl_name Selects the name of bbdev accelerator dynamic library for example \e srs. +/// \return A valid bbdev accelerator factory if the factory is successfully created, otherwise \c nullptr. +std::unique_ptr create_bbdev_acc_factory(std::string impl_name = "srs"); } // namespace dpdk } // namespace srsran diff --git a/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h b/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h index fdc5c44311..4831cceae9 100644 --- a/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h +++ b/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h @@ -17,7 +17,8 @@ namespace srsran { namespace hal { -struct hw_accelerator_pdsch_enc_configuration { +/// Configuration parameters of the bbdev-based PDSCH encoder hardware-accelerator factory. +struct bbdev_hwacc_pdsch_enc_factory_configuration { /// Accelerator type. std::string acc_type; /// Interfacing to a bbdev-based hardware-accelerator. @@ -31,12 +32,36 @@ struct hw_accelerator_pdsch_enc_configuration { bool dedicated_queue; }; +/// \brief Dynamic library w_accelerator_pdsch_enc_factory creation entry point. +/// /// Returns an instance of a PDSCH encoder hardware accelerator factory on success, /// otherwise returns nullptr. +/// /// \param[in] accelerator_config Hardware-accelerator configuration. /// \return Pointer to PDSCH encoding HW accelerator. -std::shared_ptr -create_hw_accelerator_pdsch_enc_factory(const hw_accelerator_pdsch_enc_configuration& accelerator_config); +std::unique_ptr +create_dynamic_bbdev_pdsch_enc_acc_factory(const bbdev_hwacc_pdsch_enc_factory_configuration& accelerator_config) asm( + "create_dynamic_bbdev_pdsch_enc_acc_factory"); + +/// \brief Creates a bbdev-based PDSCH encoder hardware-accelerator factory. +/// +/// This function dynamically loads a shared library corresponding to the specified implementation name and retrieves +/// the factory creation function from it. +/// +/// The naming convention for the shared library is as follows: if the implementation name is \c custom, the library +/// name is expected to be \c libsrsran_bbdev_pdsch_enc_acc_custom.so. By default, the function tries to load +/// \c libsrsran_bbdev_pdsch_enc_acc_srs.so. The dynamic library must contain the function prototype +/// \ref create_dynamic_bbdev_pdsch_enc_acc_factory. +/// +/// Ensure that \c LD_LIBRARY_PATH environment variable includes the path where the dynamic libraries are located. +/// +/// \param[in] accelerator_config Hardware-accelerator configuration. +/// \param[in] impl_name Selects the name of bbdev-based PDSCH encoder hardware-accelerator dynamic library for +/// example \e srs. \return A valid bbdev-based PDSCH encoder hardware-accelerator factory if the factory is +/// successfully created, otherwise \c nullptr. +std::unique_ptr +create_bbdev_pdsch_enc_acc_factory(const bbdev_hwacc_pdsch_enc_factory_configuration& accelerator_config, + std::string impl_name = "srs"); } // namespace hal } // namespace srsran diff --git a/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h b/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h index af4da7bfdb..603b80fe15 100644 --- a/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h +++ b/include/srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h @@ -79,11 +79,11 @@ class hw_accelerator_pdsch_enc : public hw_accelerator /// Checks if the hardware-accelerated PDSCH encoder uses CB mode or TB mode. /// \return True if CB mode is used, false otherwise. - virtual bool get_cb_mode() const = 0; + virtual bool is_cb_mode_supported() const = 0; - /// Checks the maximum supported TB size. Only used in TB mode. - /// \return TB size (in bytes). - virtual unsigned get_max_tb_size() const = 0; + /// Checks the maximum supported buffer size. Only used in TB mode. + /// \return Buffer size (in bytes). + virtual unsigned get_max_supported_buff_size() const = 0; }; } // namespace hal diff --git a/include/srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h b/include/srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h index e624229e8a..52c07a165f 100644 --- a/include/srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h +++ b/include/srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h @@ -18,7 +18,8 @@ namespace srsran { namespace hal { -struct hw_accelerator_pusch_dec_configuration { +/// Configuration parameters of the bbdev-based PUSCH decoder hardware-accelerator factory. +struct bbdev_hwacc_pusch_dec_factory_configuration { /// Accelerator type. std::string acc_type; /// Interfacing to a bbdev-based hardware-accelerator. @@ -31,12 +32,36 @@ struct hw_accelerator_pusch_dec_configuration { bool dedicated_queue = true; }; +/// \brief Dynamic library w_accelerator_pdsch_enc_factory creation entry point. +/// /// Returns an instance of a PUSCH decoder hardware accelerator factory on success, /// otherwise returns nullptr. +/// /// \param[in] accelerator_config Hardware-accelerator configuration. /// \return Pointer to PUSCH decoding HW accelerator. -std::shared_ptr -create_hw_accelerator_pusch_dec_factory(const hw_accelerator_pusch_dec_configuration& accelerator_config); +std::unique_ptr +create_dynamic_bbdev_pusch_dec_acc_factory(const bbdev_hwacc_pusch_dec_factory_configuration& accelerator_config) asm( + "create_dynamic_bbdev_pusch_dec_acc_factory"); + +/// \brief Creates a bbdev-based PUSCH decoder hardware-accelerator factory. +/// +/// This function dynamically loads a shared library corresponding to the specified implementation name and retrieves +/// the factory creation function from it. +/// +/// The naming convention for the shared library is as follows: if the implementation name is \c custom, the library +/// name is expected to be \c libsrsran_bbdev_pusch_dec_acc_custom.so. By default, the function tries to load +/// \c libsrsran_bbdev_pusch_dec_acc_srs.so. The dynamic library must contain the function prototype +/// \ref create_dynamic_bbdev_pusch_dec_acc_factory. +/// +/// Ensure that \c LD_LIBRARY_PATH environment variable includes the path where the dynamic libraries are located. +/// +/// \param[in] accelerator_config Hardware-accelerator configuration. +/// \param[in] impl_name Selects the name of bbdev-based PUSCH decoder hardware-accelerator dynamic library for +/// example \e srs. \return A valid bbdev-based PUSCH decoder hardware-accelerator factory if the factory is +/// successfully created, otherwise \c nullptr. +std::unique_ptr +create_bbdev_pusch_dec_acc_factory(const bbdev_hwacc_pusch_dec_factory_configuration& accelerator_config, + std::string impl_name = "srs"); } // namespace hal } // namespace srsran diff --git a/include/srsran/phy/upper/channel_processors/pusch/factories.h b/include/srsran/phy/upper/channel_processors/pusch/factories.h index 6cd1e2ea85..e27f837433 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/factories.h +++ b/include/srsran/phy/upper/channel_processors/pusch/factories.h @@ -63,6 +63,8 @@ struct pusch_decoder_factory_hw_configuration { std::shared_ptr segmenter_factory; std::shared_ptr crc_factory; std::shared_ptr hw_decoder_factory; + unsigned nof_pusch_decoder_threads; + task_executor* executor; }; std::shared_ptr diff --git a/include/srsran/phy/upper/upper_phy_factories.h b/include/srsran/phy/upper/upper_phy_factories.h index 8eb6855b73..e41d5270ce 100644 --- a/include/srsran/phy/upper/upper_phy_factories.h +++ b/include/srsran/phy/upper/upper_phy_factories.h @@ -17,6 +17,10 @@ #include "srsran/phy/upper/rx_buffer_pool.h" #include "srsran/phy/upper/uplink_processor.h" #include "srsran/phy/upper/upper_phy.h" +#ifdef DPDK_FOUND +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" +#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" +#endif // DPDK_FOUND #include #include @@ -174,10 +178,19 @@ create_downlink_processor_factory_sw(const downlink_processor_factory_sw_config& /// \brief Downlink processor hardware-accelerated factory configuration. struct downlink_processor_factory_hw_config { - /// \brief CRC calculator factory. - std::shared_ptr crc_calc_factory; - /// \brief PDSCH encoder factory. - std::shared_ptr pdsch_enc_factory; + /// \brief CRC calculator type. + /// + /// Use of there options: + /// - \c auto: let the factory select the most efficient given the CPU architecture, or + /// - \c lut: for using a look-up table CRC calculator, or + /// - \c clmul: for using a look-up table CRC calculator (x86_64 CPUs only). + std::string crc_calculator_type; +#ifdef HWACC_PDSCH_ENABLED + /// Hardware-accelerated PDSCH encoder factory configuration structure. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hwacc_pdsch_enc_cfg = {}; +#endif // HWACC_PDSCH_ENABLED + /// Number of concurrent threads processing downlink transmissions. + unsigned nof_concurrent_threads; }; /// Creates a full hardware-accelerated based downlink processor factory. @@ -205,6 +218,20 @@ struct downlink_processor_pool_config { /// \brief Creates and returns a downlink processor pool. std::unique_ptr create_dl_processor_pool(downlink_processor_pool_config config); +/// HAL configuration parameters for the upper PHY. +struct hal_upper_phy_config { + /// Set to true for a hardware-accelerated PUSCH processor implementation. + bool hwacc_pusch_processor = false; + /// Set to true for a hardware-accelerated PDSCH processor implementation. + bool hwacc_pdsch_processor = false; +#ifdef DPDK_FOUND + /// Hardware-accelerated PUSCH decoder function configuration structure. + hal::bbdev_hwacc_pusch_dec_factory_configuration hwacc_pusch_dec_cfg = {}; + /// Hardware-accelerated PDSCH encoder factory configuration structure. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hwacc_pdsch_enc_cfg = {}; +#endif // DPDK_FOUND +}; + /// Upper PHY configuration parameters used to create a new upper PHY object. struct upper_phy_config { /// \brief Logging level. @@ -307,6 +334,8 @@ struct upper_phy_config { task_executor* srs_executor; /// Received symbol request notifier. upper_phy_rx_symbol_request_notifier* rx_symbol_request_notifier; + /// HAL configuration. + hal_upper_phy_config hal_config; }; /// Returns true if the given upper PHY configuration is valid, otherwise false. diff --git a/lib/du/CMakeLists.txt b/lib/du/CMakeLists.txt index 7bb22b9ec5..2d9f0648e2 100644 --- a/lib/du/CMakeLists.txt +++ b/lib/du/CMakeLists.txt @@ -19,4 +19,13 @@ target_link_libraries(srsran_du_high_wrapper PUBLIC srsran_du_config_validators add_library(srsran_du_wrapper STATIC du_wrapper_impl.cpp du_wrapper_factory.cpp) -target_link_libraries(srsran_du_wrapper PUBLIC srsran_du_high_wrapper srsran_du_low_wrapper) +set(DU_WRAPPER_LIBRARIES srsran_du_high_wrapper srsran_du_low_wrapper) + +# Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. +if (DPDK_FOUND) + set_source_files_properties(du_wrapper_factory.cpp du_wrapper_impl.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + list(APPEND DU_LOW_LIBRARIES hal_hwacc_pusch + hal_hwacc_pdsch + hal_bbdev_factory) +endif (DPDK_FOUND) +target_link_libraries(srsran_du_wrapper PUBLIC ${DU_WRAPPER_LIBRARIES}) diff --git a/lib/du_low/CMakeLists.txt b/lib/du_low/CMakeLists.txt index fcf7267959..e9ecd779d0 100644 --- a/lib/du_low/CMakeLists.txt +++ b/lib/du_low/CMakeLists.txt @@ -13,4 +13,13 @@ set(SOURCES du_low_wrapper_impl.cpp) add_library(srsran_du_low_wrapper STATIC ${SOURCES}) -target_link_libraries(srsran_du_low_wrapper srsran_phy_fapi_adaptor srsran_upper_phy srsran_channel_precoder) +set(DU_LOW_LIBRARIES srsran_phy_fapi_adaptor srsran_upper_phy srsran_channel_precoder) + +# Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. +if (DPDK_FOUND) + set_source_files_properties(${SOURCES} PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + list(APPEND DU_LOW_LIBRARIES hal_hwacc_pusch + hal_hwacc_pdsch + hal_bbdev_factory) +endif (DPDK_FOUND) +target_link_libraries(srsran_du_low_wrapper PUBLIC ${DU_LOW_LIBRARIES}) diff --git a/lib/du_low/du_low_factory.cpp b/lib/du_low/du_low_factory.cpp index b692e6abe5..1043647479 100644 --- a/lib/du_low/du_low_factory.cpp +++ b/lib/du_low/du_low_factory.cpp @@ -19,7 +19,19 @@ static std::unique_ptr create_upper_phy(const upper_phy_config& const downlink_processor_factory_sw_config& dl_fact_config) { // Create downlink processor factory. - std::shared_ptr dl_proc_factory = create_downlink_processor_factory_sw(dl_fact_config); + std::shared_ptr dl_proc_factory = nullptr; + // Check if a hardware-accelerated PDSCH processor is requested. + if (!upper_config.hal_config.hwacc_pdsch_processor) { + dl_proc_factory = create_downlink_processor_factory_sw(dl_fact_config); + } else { + downlink_processor_factory_hw_config hw_cfg = {}; + hw_cfg.crc_calculator_type = upper_config.crc_calculator_type; + hw_cfg.nof_concurrent_threads = dl_fact_config.nof_concurrent_threads; +#ifdef HWACC_PDSCH_ENABLED + hw_cfg.hwacc_pdsch_enc_cfg = upper_config.hal_config.hwacc_pdsch_enc_cfg; +#endif // HWACC_PDSCH_ENABLED + dl_proc_factory = create_downlink_processor_factory_hw(hw_cfg); + } report_fatal_error_if_not(dl_proc_factory, "Invalid DL processor factory."); // Create channel precoder factory. diff --git a/lib/hal/dpdk/CMakeLists.txt b/lib/hal/dpdk/CMakeLists.txt index 2d08bdb6df..2a077c5f65 100644 --- a/lib/hal/dpdk/CMakeLists.txt +++ b/lib/hal/dpdk/CMakeLists.txt @@ -17,3 +17,5 @@ set(SOURCES add_library(hal_dpdk STATIC ${SOURCES}) target_compile_options(hal_dpdk PRIVATE ${DPDK_CFLAGS}) target_link_libraries(hal_dpdk srslog ${DPDK_LIBRARIES}) + +add_to_exported_libs(hal_dpdk) diff --git a/lib/hal/dpdk/bbdev/CMakeLists.txt b/lib/hal/dpdk/bbdev/CMakeLists.txt index 1e5e140cfc..fc55bf89b4 100644 --- a/lib/hal/dpdk/bbdev/CMakeLists.txt +++ b/lib/hal/dpdk/bbdev/CMakeLists.txt @@ -7,14 +7,9 @@ # set(SOURCES - bbdev_acc.cpp bbdev_acc_factory.cpp - bbdev.cpp - bbdev_op_pool_factory.cpp - ldpc/bbdev_ldpc_decoder.cpp - ldpc/bbdev_ldpc_encoder.cpp -) + plugin_bbdev_acc_factory.cpp) -add_library(hal_bbdev STATIC ${SOURCES}) -target_compile_options(hal_bbdev PRIVATE ${DPDK_CFLAGS}) -target_link_libraries(hal_bbdev srslog ${DPDK_LIBRARIES}) +add_library(hal_bbdev_factory STATIC ${SOURCES}) +target_compile_options(hal_bbdev_factory PRIVATE ${DPDK_CFLAGS}) +target_link_libraries(hal_bbdev_factory srslog ${DPDK_LIBRARIES} dl) diff --git a/lib/hal/dpdk/bbdev/bbdev.cpp b/lib/hal/dpdk/bbdev/bbdev.cpp deleted file mode 100644 index e1c345f38b..0000000000 --- a/lib/hal/dpdk/bbdev/bbdev.cpp +++ /dev/null @@ -1,165 +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 "bbdev.h" - -using namespace srsran; -using namespace dpdk; - -expected<::rte_bbdev_info> dpdk::bbdev_start(const bbdev_acc_configuration& cfg, srslog::basic_logger& logger) -{ - ::rte_bbdev_info info = {}; - - // Get information on the utilized bbdev hardware-accelerator. - ::rte_bbdev_info_get(cfg.id, &info); - - // Setup the required queues. - unsigned nof_queues = cfg.nof_ldpc_enc_lcores + cfg.nof_ldpc_dec_lcores + cfg.nof_fft_lcores; - if (::rte_bbdev_setup_queues(cfg.id, nof_queues, info.socket_id) < 0) { - logger.error("[bbdev] queues for device {} not setup properly (requested: ldpc_enc={}, ldpc_dec={}, fft={}, " - "available: ldpc_enc={}, ldpc_dec={}, fft={}).", - cfg.id, - cfg.nof_ldpc_enc_lcores, - cfg.nof_ldpc_dec_lcores, - cfg.nof_fft_lcores, - info.drv.num_queues[RTE_BBDEV_OP_LDPC_ENC], - info.drv.num_queues[RTE_BBDEV_OP_LDPC_DEC], - info.drv.num_queues[RTE_BBDEV_OP_FFT]); - return make_unexpected(default_error_t{}); - } - - // Basic checking of hardware-accelerator capabilities. - const ::rte_bbdev_op_cap* op_cap = info.drv.capabilities; - bool ldpc_enc_capable = false; - bool ldpc_dec_capable = false; - bool fft_capable = false; - - while (op_cap->type != RTE_BBDEV_OP_NONE) { - if (op_cap->type == RTE_BBDEV_OP_LDPC_ENC) { - ldpc_enc_capable = true; - } else if (op_cap->type == RTE_BBDEV_OP_LDPC_DEC) { - ldpc_dec_capable = true; - } else if (op_cap->type == RTE_BBDEV_OP_FFT) { - fft_capable = true; - } - ++op_cap; - } - if ((cfg.nof_ldpc_enc_lcores > 0 && !ldpc_enc_capable) || (cfg.nof_ldpc_dec_lcores > 0 && !ldpc_dec_capable) || - (cfg.nof_fft_lcores > 0 && !fft_capable)) { - logger.error("[bbdev] device {} does not provide the requested acceleration functions.", cfg.id); - return make_unexpected(default_error_t{}); - } - - // Enable interruptions. - if (::rte_bbdev_intr_enable(cfg.id) < 0) { - logger.error("[bbdev] interrupts for device {} not setup properly.", cfg.id); - return make_unexpected(default_error_t{}); - } - - // Configure the queues (only those required). - // The type of accelerated function assigned to a queue is following a known pattern: LDPC encoder, LDPC decoder and - // FFT. - ::rte_bbdev_queue_conf queue_conf = {0}; - unsigned queue_id = 0; - queue_conf.socket = info.socket_id; - queue_conf.queue_size = info.drv.queue_size_lim; - if (cfg.nof_ldpc_enc_lcores > 0) { - // Queue configuration starts from the highest priority level supported. - queue_conf.priority = 0; - queue_conf.op_type = RTE_BBDEV_OP_LDPC_ENC; - for (unsigned qid = 0, lastq = cfg.nof_ldpc_enc_lcores; qid != lastq; ++qid) { - // A maximum of 16 queues is supported per priority level. - if (qid > 0 && qid % 16 == 0) { - ++queue_conf.priority; - } - if (::rte_bbdev_queue_configure(cfg.id, queue_id, &queue_conf) < 0) { - logger.error("[bbdev] device {} queue {} (ldpc encoder) not configured properly (priority = {}).", - cfg.id, - queue_id, - queue_conf.priority); - return make_unexpected(default_error_t{}); - } - ++queue_id; - } - } - if (cfg.nof_ldpc_dec_lcores > 0) { - // Queue configuration starts from the highest priority level supported. - queue_conf.priority = 0; - queue_conf.op_type = RTE_BBDEV_OP_LDPC_DEC; - for (unsigned qid = 0, lastq = cfg.nof_ldpc_dec_lcores; qid != lastq; ++qid) { - // A maximum of 16 queues is supported per priority level. - if (qid > 0 && qid % 16 == 0) { - ++queue_conf.priority; - } - if (::rte_bbdev_queue_configure(cfg.id, queue_id, &queue_conf) < 0) { - logger.error("[bbdev] device {} queue {} (ldpc decoder) not configured properly (priority = {}).", - cfg.id, - queue_id, - queue_conf.priority); - return make_unexpected(default_error_t{}); - } - ++queue_id; - } - } - if (cfg.nof_fft_lcores > 0) { - // Queue configuration starts from the highest priority level supported. - queue_conf.priority = 0; - queue_conf.op_type = RTE_BBDEV_OP_FFT; - for (unsigned qid = 0, lastq = cfg.nof_fft_lcores; qid != lastq; ++qid) { - // A maximum of 16 queues is supported per priority level. - if (qid > 0 && qid % 16 == 0) { - ++queue_conf.priority; - } - if (::rte_bbdev_queue_configure(cfg.id, queue_id, &queue_conf) < 0) { - logger.error("[bbdev] device {} queue {} (fft) not configured properly (priority = {}).", - cfg.id, - queue_id, - queue_conf.priority); - return make_unexpected(default_error_t{}); - } - ++queue_id; - } - } - - if (::rte_bbdev_start(cfg.id) < 0) { - logger.error("[bbdev] device {} not started.", cfg.id); - return make_unexpected(default_error_t{}); - } - - return info; -} - -bool dpdk::bbdev_stop(unsigned dev_id, srslog::basic_logger& logger) -{ - if (::rte_bbdev_close(dev_id) < 0) { - logger.error("[bbdev] device {} not closed.", dev_id); - return false; - } - - return true; -} - -::rte_mempool* dpdk::create_op_pool(const char* pool_name, - ::rte_bbdev_op_type op_type, - uint16_t nof_elements, - int socket, - srslog::basic_logger& logger) - -{ - static constexpr unsigned NB_MBUF = 2048; - - ::rte_mempool* op_pool = ::rte_bbdev_op_pool_create(pool_name, op_type, NB_MBUF, nof_elements, socket); - - if (op_pool == nullptr) { - logger.error("dpdk: create_op_pool '{}' failed", pool_name); - } - - return op_pool; -} diff --git a/lib/hal/dpdk/bbdev/bbdev.h b/lib/hal/dpdk/bbdev/bbdev.h deleted file mode 100644 index ae461a8be9..0000000000 --- a/lib/hal/dpdk/bbdev/bbdev.h +++ /dev/null @@ -1,51 +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. - * - */ - -/// \file -/// \brief Definition of the common functions used by all bbdeb-based hardware-accelerated channel processor -/// implementations. - -#pragma once - -#include "srsran/adt/expected.h" -#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include -#include -#include - -namespace srsran { -namespace dpdk { - -/// bbdev initialization. -/// \param[in] cfg Configuration of the bbdev-based hardware-accelerator. -/// \param[in] logger SRS logger. -/// \return BBDEV device information if successful, otherwise \c std::nullopt. -expected<::rte_bbdev_info> bbdev_start(const bbdev_acc_configuration& cfg, srslog::basic_logger& logger); - -/// bbdev shutdown management. -/// \param[in] dev_id ID of the bbdev-based hardware-accelerator. -/// \param[in] logger SRS logger. -bool bbdev_stop(unsigned dev_id, srslog::basic_logger& logger); - -/// Creates a new op pool for a given hardware-accelerator device. -/// \param[in] pool_name Unique ID for the new mbuf pool. -/// \param[in] op_type Type of bbdev op. -/// \param[in] nof_elements Number of elements in the op pool. -/// \param[in] socket Socket used by the bbdev accelerator. -/// \param[in] logger SRS logger. -/// \return Pointer to the created op pool. -rte_mempool* create_op_pool(const char* pool_name, - ::rte_bbdev_op_type op_type, - uint16_t nof_elements, - int socket, - srslog::basic_logger& logger); - -} // namespace dpdk -} // namespace srsran diff --git a/lib/hal/dpdk/bbdev/bbdev_acc.cpp b/lib/hal/dpdk/bbdev/bbdev_acc.cpp deleted file mode 100644 index 3022b449cf..0000000000 --- a/lib/hal/dpdk/bbdev/bbdev_acc.cpp +++ /dev/null @@ -1,115 +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 "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include "bbdev.h" - -using namespace srsran; -using namespace dpdk; - -bbdev_acc::bbdev_acc(const bbdev_acc_configuration& cfg, const ::rte_bbdev_info& info_, srslog::basic_logger& logger_) : - id(cfg.id), - info(info_), - nof_ldpc_enc_lcores(cfg.nof_ldpc_enc_lcores), - nof_ldpc_dec_lcores(cfg.nof_ldpc_dec_lcores), - nof_fft_lcores(cfg.nof_fft_lcores), - available_ldpc_enc_queue(MAX_NOF_BBDEV_QUEUES), - available_ldpc_dec_queue(MAX_NOF_BBDEV_QUEUES), - available_fft_queue(MAX_NOF_BBDEV_QUEUES), - msg_mbuf_size(cfg.msg_mbuf_size), - rm_mbuf_size(cfg.rm_mbuf_size), - nof_mbuf(cfg.nof_mbuf), - logger(logger_) -{ - unsigned nof_vfs = nof_ldpc_enc_lcores + nof_ldpc_dec_lcores + nof_fft_lcores; - srsran_assert(nof_ldpc_enc_lcores <= MAX_NOF_BBDEV_VF_INSTANCES, - "Requested {} LDPC encoder VFs but only {} are available.", - nof_ldpc_enc_lcores, - MAX_NOF_BBDEV_VF_INSTANCES); - srsran_assert(nof_ldpc_dec_lcores <= MAX_NOF_BBDEV_VF_INSTANCES, - "Requested {} LDPC decoder VFs but only {} are available.", - nof_ldpc_dec_lcores, - MAX_NOF_BBDEV_VF_INSTANCES); - srsran_assert(nof_fft_lcores <= MAX_NOF_BBDEV_VF_INSTANCES, - "Requested {} FFT VFs but only {} are available.", - nof_fft_lcores, - MAX_NOF_BBDEV_VF_INSTANCES); - srsran_assert(nof_vfs <= MAX_NOF_BBDEV_QUEUES, - "Requested {} BBDEV VFs but only {} are available.", - nof_vfs, - MAX_NOF_BBDEV_QUEUES); - - nof_ldpc_enc_instances = 0; - nof_ldpc_dec_instances = 0; - // Hardware-accelerated LDPC encoder functions use queues 0:(nof_ldpc_enc_lcores - 1) - for (unsigned qid = 0, lastq = nof_ldpc_enc_lcores; qid != lastq; qid++) { - available_ldpc_enc_queue.try_push(qid); - } - // Hardware-accelerated LDPC decoder functions use queues nof_ldpc_enc_lcores:(nof_ldpc_enc_lcores + - // nof_ldpc_dec_lcores - 1) - for (unsigned qid = nof_ldpc_enc_lcores, lastq = nof_ldpc_enc_lcores + nof_ldpc_dec_lcores; qid != lastq; qid++) { - available_ldpc_dec_queue.try_push(qid); - } - // Hardware-accelerated FFT functions use queues (nof_ldpc_enc_lcores + nof_ldpc_dec_lcores):(nof_ldpc_enc_lcores + - // nof_ldpc_dec_lcores + nof_fft_lcores - 1) - for (unsigned qid = nof_ldpc_enc_lcores + nof_ldpc_dec_lcores, lastq = nof_vfs; qid != lastq; qid++) { - available_fft_queue.try_push(qid); - } -} - -bbdev_acc::~bbdev_acc() -{ - // bbdev device stop procedure. - ::bbdev_stop(id, logger); -} - -int bbdev_acc::reserve_queue(::rte_bbdev_op_type op_type) -{ - int queue_id = -1; - - if (op_type == RTE_BBDEV_OP_LDPC_ENC) { - // Try to get an available LDPC encoder queue. - std::optional qid = available_ldpc_enc_queue.try_pop(); - if (qid.has_value()) { - queue_id = qid.value(); - } - } else if (op_type == RTE_BBDEV_OP_LDPC_DEC) { - // Try to get an available LDPC decoder queue. - std::optional qid = available_ldpc_dec_queue.try_pop(); - if (qid.has_value()) { - queue_id = qid.value(); - } - } else { - // Try to get an available FFT queue. - std::optional qid = available_fft_queue.try_pop(); - if (qid.has_value()) { - queue_id = qid.value(); - } - } - - return queue_id; -} - -void bbdev_acc::free_queue(::rte_bbdev_op_type op_type, unsigned queue_id) -{ - if (op_type == RTE_BBDEV_OP_LDPC_ENC) { - // Free a LDPC encoder queue. - while (!available_ldpc_enc_queue.try_push(queue_id)) { - } - } else if (op_type == RTE_BBDEV_OP_LDPC_DEC) { - // Free a LDPC decoder queue. - while (!available_ldpc_dec_queue.try_push(queue_id)) { - } - } else { - // Free a FFT queue. - while (!available_fft_queue.try_push(queue_id)) { - } - } -} diff --git a/lib/hal/dpdk/bbdev/bbdev_acc_factory.cpp b/lib/hal/dpdk/bbdev/bbdev_acc_factory.cpp index 3647896c2c..38bed9a24f 100644 --- a/lib/hal/dpdk/bbdev/bbdev_acc_factory.cpp +++ b/lib/hal/dpdk/bbdev/bbdev_acc_factory.cpp @@ -9,19 +9,27 @@ */ #include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" -#include "bbdev.h" +#include "plugin_bbdev_acc_factory.h" +#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" using namespace srsran; using namespace dpdk; -std::shared_ptr srsran::dpdk::create_bbdev_acc(const bbdev_acc_configuration& cfg, - srslog::basic_logger& logger) +std::unique_ptr srsran::dpdk::create_bbdev_acc_factory(std::string impl_name) { - // bbdev device start procedure. - expected<::rte_bbdev_info> info = bbdev_start(cfg, logger); - if (not info.has_value()) { - return nullptr; + // Convert implementation name to lower case. + for (char& c : impl_name) { + c = std::tolower(c); } - return std::make_shared(cfg, info.value(), logger); + // Try creating a plugin bbdev accelerator factory. + auto factory = create_plugin_bbdev_acc_factory(impl_name); + if (factory) { + return factory; + } + + // No match. + fmt::print("Factory for bbdev accelerator type {} not found. Make sure to select a valid type.\n", impl_name); + + return nullptr; } diff --git a/lib/hal/dpdk/bbdev/bbdev_op_pool_factory.cpp b/lib/hal/dpdk/bbdev/bbdev_op_pool_factory.cpp deleted file mode 100644 index 60161a418d..0000000000 --- a/lib/hal/dpdk/bbdev/bbdev_op_pool_factory.cpp +++ /dev/null @@ -1,30 +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 "srsran/hal/dpdk/bbdev/bbdev_op_pool_factory.h" -#include "bbdev.h" - -using namespace srsran; -using namespace dpdk; - -std::unique_ptr srsran::dpdk::create_bbdev_op_pool(const char* pool_name, - ::rte_bbdev_op_type op_type, - uint16_t nof_elements, - int socket, - srslog::basic_logger& logger) -{ - // Create a new bbdev operation pool. - ::rte_mempool* pool = ::create_op_pool(pool_name, op_type, nof_elements, socket, logger); - if (pool == nullptr) { - return nullptr; - } - - return std::make_unique(pool); -} diff --git a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp b/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp deleted file mode 100644 index 8473b318c2..0000000000 --- a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp +++ /dev/null @@ -1,357 +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 "bbdev_ldpc_decoder.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository.h" -#include -#include - -using namespace srsran; -using namespace dpdk; - -void dpdk::set_ldpc_dec_bbdev_config(::rte_bbdev_dec_op& dec_op, - const srsran::hal::hw_pusch_decoder_configuration& cfg, - bool ext_softbuffer) -{ - // Base graph. - dec_op.ldpc_dec.basegraph = static_cast(cfg.base_graph_index); - // Modulation. - // Note that in terms of LDPC decoding, 'PI_2_BPSK' and 'BPSK' are the same. - unsigned modulation = static_cast(cfg.modulation); - dec_op.ldpc_dec.q_m = modulation; - if (modulation == 0) { - dec_op.ldpc_dec.q_m = 1; - } - // RV index. - dec_op.ldpc_dec.rv_index = static_cast(cfg.rv); - - // CB mode is currently forced (TB mode is not yet supported by bbdev/ACC100). CB size is in bytes. - dec_op.ldpc_dec.code_block_mode = 1; - - // Set the CB-specific parameters. - dec_op.ldpc_dec.cb_params.e = static_cast(cfg.cw_length); - - // Lifting size. - dec_op.ldpc_dec.z_c = static_cast(cfg.lifting_size); - // Filler bits. - dec_op.ldpc_dec.n_filler = static_cast(cfg.nof_filler_bits); - // Length of the circular buffer in bits, as described in TS38.212 Section 5.4.2.1. - dec_op.ldpc_dec.n_cb = static_cast(cfg.Ncb); - // Maximum number of iterations to perform in decoding CB. - dec_op.ldpc_dec.iter_max = static_cast(cfg.max_nof_ldpc_iterations); - - // TBD: a certain operation mode is assumed, see if a detailed hardware-accelerator capabilities checking is required? - // Define the PDSCH decoder operation flags. - uint32_t bitmask = 0; - // Only CRC24B checking is supported by the hardware-accelerator. - if (cfg.cb_crc_type == srsran::hal::hw_dec_cb_crc_type::CRC24B) { - // Codeblock CRC-24B checking is always implemented by the accelerator (set the bit). - bitmask |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK; - // Dropping of last CRC bits decoding output is always implemented in the accelerator (set the bit). - bitmask |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP; - } - // Bit-level de-interleaver is always implemented by the accelerator (clear the bit). - bitmask &= ~RTE_BBDEV_LDPC_DEINTERLEAVER_BYPASS; - // Input HARQ combining data is only needed in case of a retransmission. - if (!cfg.new_data) { - // HARQ combined input stream is enabled in the accelerator (set the bit). - bitmask |= RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE; - - // Check if the soft-buffer is implemented in the accelerator or in the host. - if (ext_softbuffer) { - // HARQ input is provided from the accelerator's internal memory (set the bit). - bitmask |= RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE; - } - } - // HARQ combined output stream is always enabled in the accelerator (set the bit). - bitmask |= RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE; - // Check if the soft-buffer is implemented in the accelerator or in the host. - if (ext_softbuffer) { - // HARQ output is provided to the accelerator's internal memory (set the bit). - bitmask |= RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE; - } - // LDPC decoder is always implemented by the accelerator (clear the bit). - bitmask &= ~RTE_BBDEV_LDPC_DECODE_BYPASS; - // If early stop is requested, enable it in the accerlerator (set the bit, otherwise clear it). - if (cfg.use_early_stop) { - bitmask |= RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE; - } else { - bitmask &= ~RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE; - } - dec_op.ldpc_dec.op_flags = bitmask; -} - -bool dpdk::set_ldpc_dec_bbdev_data(::rte_bbdev_dec_op& dec_op, - ::rte_mempool& in_mbuf_pool, - ::rte_mempool& harq_in_mbuf_pool, - ::rte_mempool& out_mbuf_pool, - ::rte_mempool& harq_out_mbuf_pool, - span data, - span soft_data, - bool new_data, - bool ext_softbuffer, - uint32_t soft_data_len, - unsigned cb_index, - unsigned absolute_cb_id, - srslog::basic_logger& logger) -{ - // Allocate an mbuf for the input data from the received mempool. - char* input_data; - ::rte_mbuf* m_head_in = ::rte_pktmbuf_alloc(&in_mbuf_pool); - if (m_head_in == nullptr) { - logger.error("[bbdev] Not enough mbufs in the input ldpc decoder mbuf pool."); - return false; - } - - // Set the memory pointers for the input data, accounting for the offset of the current segment. - dec_op.ldpc_dec.input.data = m_head_in; - dec_op.ldpc_dec.input.offset = 0; // Note that a dedicated mbuf is used per CB. - dec_op.ldpc_dec.input.length = 0; - - // Allocate the required bytes in the mbuf and update the memory pointers. - uint16_t cw_len = data.size(); - input_data = ::rte_pktmbuf_append(m_head_in, cw_len); - if (input_data == nullptr) { - // Free the input mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(m_head_in); - logger.error("[bbdev] Couldn't append {} bytes to the ldpc decoder input mbuf.", cw_len); - return false; - } - - // Copy the CB data. Note that a single copy operation is performed per CB. The copy assumes that the input data size - // is below the requested mbuf size (by default set to the maximum supported value RTE_BBDEV_LDPC_E_MAX_MBUF). - ::rte_memcpy(input_data, data.begin(), cw_len); - dec_op.ldpc_dec.input.length += cw_len; - - // Harq offset for the current CB (based on its unique absolute ID). - unsigned harq_offset = srsran::hal::HARQ_INCR.value() * absolute_cb_id; - - // Input HARQ combining data is only needed in case of a retransmission. - if (!new_data) { - // Copy of HARQ input data is only needed if the soft-buffer is implemented in the host. - if (!ext_softbuffer) { - // Allocate an mbuf for the input soft-data from the received mempool. - char* soft_input_data; - ::rte_mbuf* m_head_soft_in = ::rte_pktmbuf_alloc(&harq_in_mbuf_pool); - if (m_head_soft_in == nullptr) { - logger.error("[bbdev] Not enough mbufs in the harq input ldpc decoder mbuf pool."); - return false; - } - - // Set the memory pointers for the input soft-data. - // When using the host memory the offset is provided by the input span pointers. - uint32_t harq_output_len = dec_op.ldpc_dec.harq_combined_output.length; - dec_op.ldpc_dec.harq_combined_input.data = m_head_soft_in; - dec_op.ldpc_dec.harq_combined_input.offset = 0; - dec_op.ldpc_dec.harq_combined_input.length = harq_output_len; - - // Allocate the required bytes in the mbuf and update the memory pointers. - soft_input_data = ::rte_pktmbuf_append(m_head_soft_in, harq_output_len); - if (soft_input_data == nullptr) { - // Free the input and input soft-data mbufs back to its original mbuf pools. - ::rte_pktmbuf_free(dec_op.ldpc_dec.input.data); - ::rte_pktmbuf_free(m_head_soft_in); - logger.error("[bbdev] Couldn't append {} bytes to the ldpc decoder harq input mbuf.", harq_output_len); - return false; - } - - // Copy the input soft-data located before the filler bits in the soft-buffer. Note that the copy assumes that the - // input soft-data size is below the requested mbuf size (by default set to the maximum supported value - // RTE_BBDEV_LDPC_E_MAX_MBUF). - ::rte_memcpy(soft_input_data, soft_data.begin(), harq_output_len); - - // Preload the accelerator HARQ memory and adjust the offset. - // Note this will introduce non-negligible latency. - ::rte_bbdev_op_data saved_hc_in = dec_op.ldpc_dec.harq_combined_input; - ::rte_bbdev_op_data saved_hc_out = dec_op.ldpc_dec.harq_combined_output; - uint32_t saved_flags = dec_op.ldpc_dec.op_flags; - rte_bbdev_dec_op* op = &dec_op; - dec_op.ldpc_dec.op_flags = - RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_LOOPBACK + RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE; - ::rte_bbdev_enqueue_ldpc_dec_ops(0, 0, &op, 1); - int ret = 0; - while (ret == 0) { - ret = ::rte_bbdev_dequeue_ldpc_dec_ops(0, 0, &op, 1); - } - dec_op.ldpc_dec.op_flags = saved_flags; - dec_op.ldpc_dec.harq_combined_input = saved_hc_in; - dec_op.ldpc_dec.harq_combined_output = saved_hc_out; - // When using the accelerator's HARQ memory only pointers need updating. - } else { - // Update the HARQ input memory offset and length. - // When using the accelerator memory fixed CB offsets are employed. - dec_op.ldpc_dec.harq_combined_input.offset = harq_offset; - dec_op.ldpc_dec.harq_combined_input.length = soft_data_len; - } - } - - // Allocate an mbuf for the output data from the received mempool. - ::rte_mbuf* m_head_out = ::rte_pktmbuf_alloc(&out_mbuf_pool); - if (m_head_out == nullptr) { - // Free the input and input soft-data mbufs back to its original mbuf pools. - ::rte_pktmbuf_free(dec_op.ldpc_dec.input.data); - if (!new_data && !ext_softbuffer) { - ::rte_pktmbuf_free(dec_op.ldpc_dec.harq_combined_input.data); - } - logger.error("[bbdev] Not enough mbufs in the output ldpc decoder mbuf pool."); - return false; - } - - // Set the memory pointers for the output data, accounting for the offset of the current segment. - dec_op.ldpc_dec.hard_output.data = m_head_out; - dec_op.ldpc_dec.hard_output.offset = 0; // Note that a dedicated mbuf is used per segment. - dec_op.ldpc_dec.hard_output.length = 0; - - // Update the HARQ output memory offset and length. - // Host memory (offset is provided by the input span pointers). - if (!ext_softbuffer) { - dec_op.ldpc_dec.harq_combined_output.offset = 0; - // Accelerator memory (fixed CB offsets are used). - } else { - dec_op.ldpc_dec.harq_combined_output.offset = harq_offset; - } - dec_op.ldpc_dec.harq_combined_output.length = 0; - - // Reading of HARQ output data is only needed if the soft-buffer is implemented in the host. - if (!ext_softbuffer) { - // Allocate an mbuf for the output soft-data from the received mempool. - ::rte_mempool* harq_out_pool = &harq_out_mbuf_pool; - ::rte_mbuf* m_head_soft_out = ::rte_pktmbuf_alloc(harq_out_pool); - if (m_head_soft_out == nullptr) { - // Free the input and input soft-data mbufs back to its original mbuf pools. - ::rte_pktmbuf_free(dec_op.ldpc_dec.input.data); - if (!new_data && !ext_softbuffer) { - ::rte_pktmbuf_free(dec_op.ldpc_dec.harq_combined_input.data); - } - logger.error("[bbdev] Not enough mbufs in the harq output ldpc decoder mbuf pool."); - return false; - } - - // Set the memory pointers for the output data. - dec_op.ldpc_dec.harq_combined_output.data = m_head_soft_out; - } - - return true; -} - -bool dpdk::enqueue_ldpc_dec_operation(::rte_bbdev_dec_op& dec_ops, - uint16_t num_dec_ops, - uint16_t bbdev_id, - uint16_t dec_queue_id, - bool new_data, - bool ext_softbuffer, - srslog::basic_logger& logger) -{ - // Enqueue new operations on the hardware-accelerator LDPC decoder. - ::rte_bbdev_dec_op* ops = &dec_ops; - uint16_t num_enq_dec_ops = ::rte_bbdev_enqueue_ldpc_dec_ops(bbdev_id, dec_queue_id, &ops, num_dec_ops); - if (num_enq_dec_ops <= 0) { - // Free the input and output mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(dec_ops.ldpc_dec.input.data); - // Input HARQ combining data is only needed in case of a retransmission. - if (!new_data && !ext_softbuffer) { - ::rte_pktmbuf_free(dec_ops.ldpc_dec.harq_combined_input.data); - } - ::rte_pktmbuf_free(dec_ops.ldpc_dec.hard_output.data); - if (!ext_softbuffer) { - ::rte_pktmbuf_free(dec_ops.ldpc_dec.harq_combined_output.data); - } - logger.error( - "[bbdev] Couldn't enqueue new operations in the ldpc decoder. The operation will be dropped: acc [queue={}].", - dec_queue_id); - return false; - } - - return true; -} - -bool dpdk::dequeue_ldpc_dec_operation(::rte_bbdev_dec_op& dec_ops, - uint16_t num_dec_ops, - uint16_t bbdev_id, - uint16_t dec_queue_id, - srslog::basic_logger& logger) -{ - // Dequeue processed operations from the hardware-accelerator LDPC decoder. - ::rte_bbdev_dec_op* ops = &dec_ops; - uint16_t num_deq_dec_ops = ::rte_bbdev_dequeue_ldpc_dec_ops(bbdev_id, dec_queue_id, &ops, num_dec_ops); - if (num_deq_dec_ops <= 0) { - // logger.error("[bbdev] Couldn't dequeue new operations from the ldpc decoder."); - return false; - } - - return true; -} - -uint32_t dpdk::read_ldpc_dec_bbdev_data(::rte_bbdev_dec_op& dec_op, - span data, - span soft_data, - bool new_data, - bool ext_softbuffer) -{ - uint32_t new_soft_data_len = 0; - - ::rte_mbuf* m_head_out = dec_op.ldpc_dec.hard_output.data; - uint16_t dec_len = rte_pktmbuf_data_len(m_head_out); - // Read the CB data. Note that a single read operation is performed per CB. The read assumes that the output data size - // is below the requested mbuf size (by default set to the maximum supported value RTE_BBDEV_LDPC_E_MAX_MBUF). - uint16_t offset = 0; // Note that a dedicated mbuf is used per segment. - uint8_t* dec_data = rte_pktmbuf_mtod_offset(m_head_out, uint8_t*, offset); - - // Recover the decoded data. - ::rte_memcpy(data.data(), dec_data, dec_len); - - // Update the harq length for this CB. - new_soft_data_len = dec_op.ldpc_dec.harq_combined_output.length; - - // Only if the soft-buffer is implemented in the host then the output soft-data needs to be read from the accelerator - // HARQ memory. - if (!ext_softbuffer) { - // Push back the data from the accelerator HARQ memory. - // Note this will introduce non-negligible latency. - int saved_status = dec_op.status; - uint8_t saved_iter_count = dec_op.ldpc_dec.iter_count; - uint32_t saved_flags = dec_op.ldpc_dec.op_flags; - ::rte_bbdev_dec_op* op = &dec_op; - dec_op.ldpc_dec.op_flags = - RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_LOOPBACK + RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE; - dec_op.ldpc_dec.harq_combined_input.length = new_soft_data_len; - ::rte_bbdev_enqueue_ldpc_dec_ops(0, 0, &op, 1); - int ret = 0; - while (ret == 0) { - ret = ::rte_bbdev_dequeue_ldpc_dec_ops(0, 0, &op, 1); - } - dec_op.ldpc_dec.op_flags = saved_flags; - dec_op.status = saved_status; - dec_op.ldpc_dec.iter_count = saved_iter_count; - - // Retrieve the pointer to the mbuf used for the output soft-data. - ::rte_mbuf* m_head_soft_out = dec_op.ldpc_dec.harq_combined_output.data; - // Note that te read assumes that the decoded soft-data size is below the requested mbuf size (by default set to the - // maximum supported value RTE_BBDEV_LDPC_E_MAX_MBUF). - uint16_t soft_offset = 0; - int8_t* dec_soft_data = rte_pktmbuf_mtod_offset(m_head_soft_out, int8_t*, soft_offset); - - // Copy the output soft-data in the soft-buffer. - ::rte_memcpy(soft_data.data(), dec_soft_data, new_soft_data_len); - } - - // Free the input and output mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(dec_op.ldpc_dec.input.data); - // Input HARQ combining data is only needed in case of a retransmission. - if (!new_data && !ext_softbuffer) { - ::rte_pktmbuf_free(dec_op.ldpc_dec.harq_combined_input.data); - } - ::rte_pktmbuf_free(dec_op.ldpc_dec.hard_output.data); - if (!ext_softbuffer) { - ::rte_pktmbuf_free(dec_op.ldpc_dec.harq_combined_output.data); - } - - return new_soft_data_len; -} diff --git a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.h b/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.h deleted file mode 100644 index 3800f27423..0000000000 --- a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.h +++ /dev/null @@ -1,103 +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. - * - */ - -/// \file -/// \brief Definition of the specific functions used by the bbdeb-based hardware-accelerated LDPC decoder -/// implementations. - -#pragma once - -#include "srsran/adt/static_vector.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec.h" -#include "srsran/srslog/srslog.h" -#include - -namespace srsran { -namespace dpdk { - -/// Sets the contents of the bbdev configuration structure for the hardware-accelerated LPDC decoder operations. -/// \param[out] op bbdev decoder operation configuration structure. -/// \param[in] cfg PUSCH decoder configuration parameter-structure. -/// \param[in] ext_softbuffer Indicates if the soft-buffer implementation type. -void set_ldpc_dec_bbdev_config(::rte_bbdev_dec_op& op, - const srsran::hal::hw_pusch_decoder_configuration& cfg, - bool ext_softbuffer); - -/// Sets the contents of the bbdev input mbuffer structures for the hardware-accelerated LPDC decoder operations. -/// \param[out] op bbdev decoder operation configuration structure. -/// \param[in] in_mbuf_pool Input data mbuf pool for the hardware-accelerated LDPC decoder operations. -/// \param[in] harq_in_mbuf_pool Input soft-data mbuf pool for the hardware-accelerated LDPC decoder operations. -/// \param[in] out_mbuf_pool Output data mbuf pool for the hardware-accelerated LDPC decoder operations. -/// \param[in] harq_out_mbuf_pool Output soft-data mbuf pool for the hardware-accelerated LDPC decoder operations. -/// \param[in] data The input data to the hardware-accelerated LDPC decoder operations. -/// \param[in] soft_data The input soft-data to the hardware-accelerated LDPC decoder operations. -/// \param[in] new_data Indicates if the data is new or a retransmission. -/// \param[in] ext_softbuffer Indicates if the soft-buffer implementation type. -/// \param[in] soft_data_len Length of the soft-combining input data. -/// \param[in] cb_index Index of the CB (within the TB). -/// \param[in] absolute_cb_id Unique ID of associated to the CB in the soft-buffer and HARQ ACK context entry. -/// \param[in] logger SRS logger. -bool set_ldpc_dec_bbdev_data(::rte_bbdev_dec_op& op, - ::rte_mempool& in_mbuf_pool, - ::rte_mempool& harq_in_mbuf_pool, - ::rte_mempool& out_mbuf_pool, - ::rte_mempool& harq_out_mbuf_pool, - span data, - span soft_data, - bool new_data, - bool ext_softbuffer, - uint32_t soft_data_len, - unsigned cb_index, - unsigned absolute_cb_id, - srslog::basic_logger& logger); - -/// Enqueues new operations in the hardware-accelerated LDPC decoder. -/// \param[in] dec_ops Array of decoder operation configuration structures. -/// \param[in] num_dec_ops Number of decoder operations (to be enqueued - from the array). -/// \param[in] id bbdev ID of the hardware-accelerator. -/// \param[in] dec_queue_id bbdev ID of the queue used by the hardrware-accelerator. -/// \param[in] logger SRS logger. -bool enqueue_ldpc_dec_operation(::rte_bbdev_dec_op& dec_ops, - uint16_t ldpc_dec_ops, - uint16_t id, - uint16_t dec_queue_id, - bool new_data, - bool ext_softbuffer, - srslog::basic_logger& logger); - -/// Dequeues processed operations from the hardware-accelerated LDPC decoder. -/// \param[in] dec_ops Array of decoder operation configuration structures. -/// \param[in] num_dec_ops Number of decoder operations (to be dequeued - to the array). -/// \param[in] id bbdev ID of the hardware-accelerator. -/// \param[in] dec_queue_id bbdev ID of the queue used by the hardrware-accelerator. -/// \param[in] new_data Indicates if the data is new or a retransmission. -/// \param[in] ext_softbuffer Indicates if the soft-buffer implementation type. -/// \param[in] logger SRS logger. -bool dequeue_ldpc_dec_operation(::rte_bbdev_dec_op& dec_ops, - uint16_t ldpc_dec_ops, - uint16_t id, - uint16_t dec_queue_id, - srslog::basic_logger& logger); - -/// Reads the contents of the bbdev output mbuffer structures from the hardware-accelerated LPDC decoder operations. -/// \param[in] op bbdev decoder operation configuration structure. -/// \param[out] data The output data from the hardware-accelerated LDPC decoder operations. -/// \param[out] soft_data The output soft-data from the hardware-accelerated LDPC decoder operations. -/// \param[in] new_data Indicates if the data is new or a retransmission. -/// \param[in] ext_softbuffer Indicates if the soft-buffer implementation type. -/// \return Length of the soft-combining output data. -uint32_t read_ldpc_dec_bbdev_data(::rte_bbdev_dec_op& op, - span data, - span soft_data, - bool new_data, - bool ext_softbuffer); - -} // namespace dpdk -} // namespace srsran diff --git a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.cpp b/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.cpp deleted file mode 100644 index 2763d4b185..0000000000 --- a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.cpp +++ /dev/null @@ -1,229 +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 "bbdev_ldpc_encoder.h" -#include "srsran/srsvec/bit.h" -#include -#include - -using namespace srsran; -using namespace dpdk; - -void dpdk::set_ldpc_enc_bbdev_config(::rte_bbdev_enc_op& enc_op, const srsran::hal::hw_pdsch_encoder_configuration& cfg) -{ - // Base graph. - enc_op.ldpc_enc.basegraph = static_cast(cfg.base_graph_index); - // Modulation. - enc_op.ldpc_enc.q_m = static_cast(cfg.modulation); - // RV index. - enc_op.ldpc_enc.rv_index = static_cast(cfg.rv); - - // Check if CB mode or TB mode is to be used. - if (cfg.cb_mode) { - // CB mode is currently used. CB size is in bytes. - enc_op.ldpc_enc.code_block_mode = 1; - - // Set the CB-specific parameters. - enc_op.ldpc_enc.cb_params.e = static_cast(cfg.rm_length); - } else { - // TB mode is currently used. TB size is in bytes. - enc_op.ldpc_enc.code_block_mode = 0; - - // Set the TB-specific parameters. - enc_op.ldpc_enc.tb_params.c = static_cast(cfg.nof_segments); - enc_op.ldpc_enc.tb_params.cab = static_cast(cfg.nof_short_segments); - enc_op.ldpc_enc.tb_params.ea = static_cast(cfg.cw_length_a); - enc_op.ldpc_enc.tb_params.eb = static_cast(cfg.cw_length_b); - // The offset to first CB in inbound mbuf data is assumed to be 0. - enc_op.ldpc_enc.tb_params.r = 0; - } - - // Lifting size. - enc_op.ldpc_enc.z_c = static_cast(cfg.lifting_size); - unsigned K = 0; - if (enc_op.ldpc_enc.basegraph == 1) { - K = 22 * enc_op.ldpc_enc.z_c; - } else { - K = 10 * enc_op.ldpc_enc.z_c; - } - enc_op.ldpc_enc.n_filler = cfg.nof_filler_bits; - // Filler bits. - // Note that providing a byte-aligned 'K - n_filler' value is a requirement. - // Roundig up of 'n_filler' to the nearest value is done if needed. - if ((K - enc_op.ldpc_enc.n_filler) % 8 != 0) { - enc_op.ldpc_enc.n_filler = (cfg.nof_filler_bits + 8 - 1) & -8; - } - // Length of the circular buffer in bits, as described in TS38.212 Section 5.4.2.1. - enc_op.ldpc_enc.n_cb = static_cast(cfg.Ncb); - - // Define the PDSCH encoder operation flags. - uint32_t bitmask = 0; - // Bit-level interleaver is always implemented by the accelerator (clear the bit). - bitmask &= ~RTE_BBDEV_LDPC_INTERLEAVER_BYPASS; - // Rate matching is always implemented by the accelerator (set the bit). - bitmask |= RTE_BBDEV_LDPC_RATE_MATCH; - // In CB mode, both TB anc CB CRC attachment is implemented by the segmenter (and, thus, is disabled in the - // accelerator). In TB mode, TB CRC attachment is not supported by the accelerator, but the CB one is for segmented - // TBs. - if (!cfg.cb_mode && cfg.nof_segments > 1) { - bitmask |= RTE_BBDEV_LDPC_CRC_24B_ATTACH; - } - enc_op.ldpc_enc.op_flags = bitmask; -} - -bool dpdk::set_ldpc_enc_bbdev_data(::rte_bbdev_enc_op& enc_op, - ::rte_mempool& in_mbuf_pool, - ::rte_mempool& out_mbuf_pool, - span data, - srslog::basic_logger& logger, - span tb_crc) -{ - // Allocate an mbuf for the input data from the received mempool. - char* input_data; - ::rte_mbuf* m_head_in = ::rte_pktmbuf_alloc(&in_mbuf_pool); - if (m_head_in == nullptr) { - logger.error("[bbdev] Not enough mbufs in the input ldpc encoder mbuf pool."); - return false; - } - - // Set the memory pointers for the input data. - enc_op.ldpc_enc.input.data = m_head_in; - enc_op.ldpc_enc.input.offset = 0; // Note that a dedicated mbuf is used per operation. - enc_op.ldpc_enc.input.length = 0; - - // Allocate the required bytes in the mbuf and update the memory pointers. - uint16_t data_len = data.size(); - uint16_t tb_crc_len = tb_crc.size(); - input_data = ::rte_pktmbuf_append(m_head_in, data_len + tb_crc_len); - if (input_data == nullptr) { - // Free the input mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(m_head_in); - logger.error("[bbdev] Couldn't append {} bytes to the ldpc encoder input mbuf.", data_len + tb_crc_len); - return false; - } - // Copy the TB/CB data. Note that a single copy operation is performed per TB/CB. The copy assumes that the input data - // size is below the requested mbuf size (by default set to the maximum supported value RTE_BBDEV_LDPC_E_MAX_MBUF). - ::rte_memcpy(input_data, data.begin(), data_len); - // If required, copy the TB-CRC. - if (tb_crc_len > 0) { - ::rte_memcpy(input_data + data_len, &tb_crc[0], tb_crc_len); - } - enc_op.ldpc_enc.input.length += data_len + tb_crc_len; - - // Allocate an mbuf for the output data from the received mempool. - ::rte_mbuf* m_head_out = ::rte_pktmbuf_alloc(&out_mbuf_pool); - if (m_head_out == nullptr) { - // Free the input mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(m_head_in); - logger.error("[bbdev] Not enough mbufs in the output ldpc encoder mbuf pool."); - return false; - } - - // Set the memory pointers for the output data. - enc_op.ldpc_enc.output.data = m_head_out; - enc_op.ldpc_enc.output.offset = 0; // Note that a dedicated mbuf is used per operation. - enc_op.ldpc_enc.output.length = 0; - - return true; -} - -bool dpdk::enqueue_ldpc_enc_operation(::rte_bbdev_enc_op& enc_ops, - uint16_t num_enc_ops, - uint16_t bbdev_id, - uint16_t enc_queue_id, - srslog::basic_logger& logger) -{ - // Enqueue new operations on the hardware-accelerator LDPC encoder. - ::rte_bbdev_enc_op* ops = &enc_ops; - uint16_t num_enq_enc_ops = ::rte_bbdev_enqueue_ldpc_enc_ops(bbdev_id, enc_queue_id, &ops, num_enc_ops); - if (num_enq_enc_ops <= 0) { - // Free the input and output mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(enc_ops.ldpc_enc.input.data); - ::rte_pktmbuf_free(enc_ops.ldpc_enc.output.data); - logger.error( - "[bbdev] Couldn't enqueue new operations in the ldpc encoder. The operation will be dropped: acc [queue={}].", - enc_queue_id); - return false; - } - - return true; -} - -bool dpdk::dequeue_ldpc_enc_operation(::rte_bbdev_enc_op& enc_ops, - uint16_t num_enc_ops, - uint16_t bbdev_id, - uint16_t enc_queue_id, - srslog::basic_logger& logger) -{ - // Dequeue processed operations from the hardware-accelerator LDPC encoder. - ::rte_bbdev_enc_op* ops = &enc_ops; - uint16_t num_deq_enc_ops = ::rte_bbdev_dequeue_ldpc_enc_ops(bbdev_id, enc_queue_id, &ops, num_enc_ops); - if (num_deq_enc_ops <= 0) { - // logger.error("[bbdev] Couldn't dequeue new operations from the ldpc encoder."); - return false; - } - - return true; -} - -void dpdk::read_ldpc_enc_bbdev_data(::rte_bbdev_enc_op& enc_op, - span data, - span packed_data, - bool cb_mode) -{ - ::rte_mbuf* m_head_out = enc_op.ldpc_enc.output.data; - uint16_t enc_len = rte_pktmbuf_data_len(m_head_out); - - // Read the TB/CB data. Note that a single read operation is performed per TB/CB. The read assumes that the output - // data size is below the requested mbuf size (by default set to the maximum supported value - // RTE_BBDEV_LDPC_E_MAX_MBUF). - uint16_t offset = 0; - uint8_t* enc_data = rte_pktmbuf_mtod_offset(m_head_out, uint8_t*, offset); - - // Recover the encoded data. - ::rte_memcpy(packed_data.data(), enc_data, enc_len); - - // Unpack the accelerator outputs, while avoiding (byte-alignment) padding bits. - uint32_t seg_length = 0; - uint32_t seg_offset = 0; - uint32_t seg_byte_offset = 0; - uint8_t nof_segments = 1; - uint8_t nof_short_segments = 0; - // Check if CB mode is used. No data offset in this case (a dedicated mbuf is used). - if (cb_mode) { - seg_length = enc_op.ldpc_enc.cb_params.e; - } else { - seg_length = enc_op.ldpc_enc.tb_params.ea; - nof_short_segments = enc_op.ldpc_enc.tb_params.cab; - nof_segments = enc_op.ldpc_enc.tb_params.c; - } - - for (uint seg_idx = 0, end_idx = nof_segments; seg_idx < end_idx; ++seg_idx) { - uint32_t seg_byte_length = units::bits(seg_length).round_up_to_bytes().value(); - srsvec::bit_unpack( - span(data.subspan(seg_offset, seg_length)), - ::bit_buffer::from_bytes(span(&packed_data[seg_byte_offset], seg_byte_length)).first(seg_length)); - - // In TB mode the segment offset needs to be udpated. - if (!cb_mode) { - seg_offset += seg_length; - seg_byte_offset += seg_byte_length; - if (seg_idx + 1 < nof_short_segments) { - seg_length = enc_op.ldpc_enc.tb_params.ea; - } else { - seg_length = enc_op.ldpc_enc.tb_params.eb; - } - } - } - - // Free the input and output mbuf back to its original mbuf pools. - ::rte_pktmbuf_free(enc_op.ldpc_enc.input.data); - ::rte_pktmbuf_free(enc_op.ldpc_enc.output.data); -} diff --git a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.h b/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.h deleted file mode 100644 index bad4cb4b8f..0000000000 --- a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_encoder.h +++ /dev/null @@ -1,79 +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. - * - */ - -/// \file -/// \brief Definition of the specific functions used by the bbdeb-based hardware-accelerated LDPC encoder -/// implementations. - -#pragma once - -#include "srsran/adt/static_vector.h" -#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h" -#include "srsran/srslog/srslog.h" -#include - -namespace srsran { -namespace dpdk { - -/// Sets the contents of the bbdev configuration structure for the hardware-accelerated LPDC encoder operations. -/// \param[out] op bbdev encoder operation configuration structure. -/// \param[in] cfg PDSCH encoder configuration parameter-structure. -void set_ldpc_enc_bbdev_config(::rte_bbdev_enc_op& op, const srsran::hal::hw_pdsch_encoder_configuration& cfg); - -/// Sets the contents of the bbdev input mbuffer structures for the hardware-accelerated LPDC encoder operations. -/// \param[out] op bbdev encoder operation configuration structure. -/// \param[in] in_mbuf_pool Input data mbuf pool for the hardware-accelerated LDPC encoder operations. -/// \param[in] out_mbuf_pool Output data mbuf pool for the hardware-accelerated LDPC encoder operations. -/// \param[in] data The input data to the hardware-accelerated LDPC encoder operations. -/// \param[in] logger SRS logger. -/// \param[in] tb_crc Optional. The TB CRC computed from 'data'. Only required in TB mode. -bool set_ldpc_enc_bbdev_data(::rte_bbdev_enc_op& op, - ::rte_mempool& in_mbuf_pool, - ::rte_mempool& out_mbuf_pool, - span data, - srslog::basic_logger& logger, - span tb_crc = {}); - -/// Enqueues new operations in the hardware-accelerated LDPC encoder. -/// \param[in] enc_ops Array of encoder operation configuration structures. -/// \param[in] num_enc_ops Number of encoder operations (to be enqueued - from the array). -/// \param[in] id bbdev ID of the hardware-accelerator. -/// \param[in] enc_queue_id bbdev ID of the queue used by the hardrware-accelerator. -/// \param[in] logger SRS logger. -bool enqueue_ldpc_enc_operation(::rte_bbdev_enc_op& enc_ops, - uint16_t ldpc_enc_ops, - uint16_t id, - uint16_t enc_queue_id, - srslog::basic_logger& logger); - -/// Dequeues processed operations from the hardware-accelerated LDPC encoder. -/// \param[in] enc_ops Array of encoder operation configuration structures. -/// \param[in] num_enc_ops Number of encoder operations (to be dequeued - to the array). -/// \param[in] id bbdev ID of the hardware-accelerator. -/// \param[in] enc_queue_id bbdev ID of the queue used by the hardrware-accelerator. -/// \param[in] logger SRS logger. -bool dequeue_ldpc_enc_operation(::rte_bbdev_enc_op& enc_ops, - uint16_t ldpc_enc_ops, - uint16_t id, - uint16_t enc_queue_id, - srslog::basic_logger& logger); - -/// Reads the contents of the bbdev output mbuffer structures from the hardware-accelerated LPDC encoder operations. -/// \param[in] op bbdev encoder operation configuration structure. -/// \param[out] data The output data from the hardware-accelerated LDPC encoder operations. -/// \param[out] packed_data Temporary storage for the packed outputs from the hardware-accelerator. -/// \param[in] cb_mode Optional. Indicates if the encoder operates in CB mode (true) or TB mode (false). -void read_ldpc_enc_bbdev_data(::rte_bbdev_enc_op& op, - span data, - span packed_data, - bool cb_mode = true); - -} // namespace dpdk -} // namespace srsran diff --git a/lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.cpp b/lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.cpp new file mode 100644 index 0000000000..08b4e33175 --- /dev/null +++ b/lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.cpp @@ -0,0 +1,151 @@ +/* + * + * 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 "plugin_bbdev_acc_factory.h" +#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" +#include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" +#include + +using namespace srsran; +using namespace dpdk; + +namespace { + +/// Dynamic library handler deleter - closes the dynamic library upon destruction. +struct dynamic_library_deleter { + void operator()(void* handler) const + { + if (handler != nullptr) { + ::dlclose(handler); + } + } +}; + +using handler_ptr = std::shared_ptr; + +/// Wraps a bbdev accelerator interface with the dynamic library handle. +class bbdev_acc_dynamic_wrapper : public bbdev_acc +{ +public: + /// Constructs a wrapper from the dynamic library handler and an open bbdev accelerator interface. + explicit bbdev_acc_dynamic_wrapper(handler_ptr handler_, std::shared_ptr acc_) noexcept : + handler(std::move(handler_)), acc(std::move(acc_)) + { + } + + /// Default destructor - deletes the instance first then the dynamic library handler. + ~bbdev_acc_dynamic_wrapper() + { + acc.reset(); + handler.reset(); + } + + unsigned get_device_id() const override { return acc->get_device_id(); } + int get_socket_id() const override { return acc->get_socket_id(); } + unsigned get_nof_ldpc_enc_cores() const override { return acc->get_nof_ldpc_enc_cores(); } + unsigned get_nof_ldpc_dec_cores() const override { return acc->get_nof_ldpc_dec_cores(); } + unsigned get_nof_fft_cores() const override { return acc->get_nof_fft_cores(); } + uint64_t get_harq_buff_size_bytes() const override { return acc->get_harq_buff_size_bytes(); } + units::bytes get_msg_mbuf_size() const override { return acc->get_msg_mbuf_size(); } + units::bytes get_rm_mbuf_size() const override { return acc->get_rm_mbuf_size(); } + unsigned get_nof_mbuf() const override { return acc->get_nof_mbuf(); } + srslog::basic_logger& get_logger() override { return acc->get_logger(); } + int reserve_queue(::rte_bbdev_op_type op_type) override { return acc->reserve_queue(op_type); } + void free_queue(::rte_bbdev_op_type op_type, unsigned queue_id) override + { + return acc->free_queue(op_type, queue_id); + } + unsigned reserve_encoder() override { return acc->reserve_encoder(); } + unsigned reserve_decoder() override { return acc->reserve_decoder(); } + +private: + handler_ptr handler; + std::shared_ptr acc; +}; + +/// Wraps a bbdev accelerator factory and a dynamic library handler. +class bbdev_acc_factory_dynamic_wrapper : public bbdev_acc_factory +{ +public: + /// Constructs from handler and factory. + bbdev_acc_factory_dynamic_wrapper(handler_ptr handle_, std::unique_ptr factory_) : + handle(std::move(handle_)), factory(std::move(factory_)) + { + } + + /// Default destructor - deletes the factory first then the dynamic library handler. + ~bbdev_acc_factory_dynamic_wrapper() + { + factory.reset(); + handle.reset(); + } + + // See interface for documentation. + std::shared_ptr create(const bbdev_acc_configuration& cfg, srslog::basic_logger& logger) override + { + // Create bbdev accelerator using the loaded factory. + std::shared_ptr bbdev_if = factory->create(cfg, logger); + if (bbdev_if == nullptr) { + report_error("Failed to create plugin bbdev_acc"); + } + + // Wrap the dynamic library handler and the bbdev accelerator instance. + return std::make_unique(handle, std::move(bbdev_if)); + } + +private: + handler_ptr handle; + std::unique_ptr factory; +}; + +} // namespace + +std::unique_ptr srsran::dpdk::create_plugin_bbdev_acc_factory(std::string impl_name) +{ + char* err = nullptr; + std::string plugin_name = "libsrsran_bbdev_acc_" + impl_name + ".so"; + + void* dl_handle = ::dlopen(plugin_name.c_str(), RTLD_NOW + RTLD_DEEPBIND + RTLD_GLOBAL); + if (dl_handle == nullptr) { + err = ::dlerror(); + if (err != nullptr) { + fmt::print("Failed to load bbdev_acc plugin {}: {}\n", plugin_name, err); + } + return nullptr; + } + + // Create factory function prototype. + using create_factory_func = std::unique_ptr(void); + + // Load symbol. + auto* create_factory = reinterpret_cast(::dlsym(dl_handle, "create_dynamic_bbdev_acc_factory")); + + // Handle an error loading the symbol. + if (create_factory == nullptr) { + err = ::dlerror(); + if (err != nullptr) { + fmt::print("Error loading symbol {}: {}\n", "create_dynamic_bbdev_acc_factory", err); + } + return nullptr; + } + + // Create factory. + std::unique_ptr factory = (*create_factory)(); + + if (factory == nullptr) { + return nullptr; + } + + // Create shared pointer with deleter. + dynamic_library_deleter deleter; + handler_ptr handle(dl_handle, deleter); + + return std::make_unique(std::move(handle), std::move(factory)); +} diff --git a/lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.h b/lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.h new file mode 100644 index 0000000000..623dd9b594 --- /dev/null +++ b/lib/hal/dpdk/bbdev/plugin_bbdev_acc_factory.h @@ -0,0 +1,22 @@ +/* + * + * 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/hal/dpdk/bbdev/bbdev_acc_factory.h" +#include + +namespace srsran { +namespace dpdk { + +std::unique_ptr create_plugin_bbdev_acc_factory(std::string impl_name); + +} // namespace dpdk +} // namespace srsran diff --git a/lib/hal/phy/upper/channel_processors/CMakeLists.txt b/lib/hal/phy/upper/channel_processors/CMakeLists.txt index c4b221499b..cd9f43622b 100644 --- a/lib/hal/phy/upper/channel_processors/CMakeLists.txt +++ b/lib/hal/phy/upper/channel_processors/CMakeLists.txt @@ -16,9 +16,8 @@ endif () add_library(hal_hwacc_pdsch STATIC hw_accelerator_factories.cpp - hw_accelerator_pdsch_enc_impl.cpp - hw_accelerator_pdsch_enc_acc100_impl.cpp) + plugin_bbdev_pdsch_enc_acc_factory.cpp) set_source_files_properties(hw_accelerator_factories.cpp PROPERTIES COMPILE_DEFINITIONS "${HWACC_FACTORIES_DEFINITIONS}") -target_link_libraries(hal_hwacc_pdsch hal_bbdev hal_dpdk ${DPDK_LIBRARIES}) +target_link_libraries(hal_hwacc_pdsch hal_bbdev_factory hal_dpdk ${DPDK_LIBRARIES} dl) diff --git a/lib/hal/phy/upper/channel_processors/hw_accelerator_factories.cpp b/lib/hal/phy/upper/channel_processors/hw_accelerator_factories.cpp index bf41ea9f9a..18e19afa0c 100644 --- a/lib/hal/phy/upper/channel_processors/hw_accelerator_factories.cpp +++ b/lib/hal/phy/upper/channel_processors/hw_accelerator_factories.cpp @@ -9,64 +9,30 @@ */ #include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" -#include "../../../dpdk/bbdev/bbdev.h" -#include "../../../dpdk/dpdk.h" -#include "hw_accelerator_pdsch_enc_acc100_impl.h" -#include "hw_accelerator_pdsch_enc_impl.h" +#include "plugin_bbdev_pdsch_enc_acc_factory.h" using namespace srsran; using namespace hal; -#ifdef ENABLE_PDSCH_HWACC - -namespace { - -class hw_accelerator_pdsch_enc_factory_spec : public hw_accelerator_pdsch_enc_factory +std::unique_ptr +srsran::hal::create_bbdev_pdsch_enc_acc_factory(const bbdev_hwacc_pdsch_enc_factory_configuration& accelerator_config, + std::string impl_name) { -private: - /// Accelerator type. - std::string acc_type; - /// Interfacing to a bbdev-based hardware-accelerator. - std::shared_ptr bbdev_accelerator; - /// Operation mode of the PDSCH encoder (CB = true, TB = false [default]). - bool cb_mode = false; - /// Maximum supported TB size in bytes (used to size the mbufs). - unsigned max_tb_size; - /// Indicates if the accelerated function uses a dedicated hardware queue or needs to reserve one for each operation. - bool dedicated_queue = true; - -public: - // Default constructor. - explicit hw_accelerator_pdsch_enc_factory_spec(const hw_accelerator_pdsch_enc_configuration& accelerator_config) : - acc_type(accelerator_config.acc_type), - bbdev_accelerator(std::move(accelerator_config.bbdev_accelerator)), - cb_mode(accelerator_config.cb_mode), - max_tb_size(accelerator_config.max_tb_size), - dedicated_queue(accelerator_config.dedicated_queue) - { + // Convert implementation name to lower case. + for (char& c : impl_name) { + c = std::tolower(c); } - std::unique_ptr create() override - { - if (acc_type == "acc100") { - return std::make_unique( - bbdev_accelerator, cb_mode, max_tb_size, dedicated_queue); - } - // Handle other accelerator types here. - return {}; + // Try creating a plugin bbdev-based PDSCH encoder hardware-accelerator factory. + auto factory = create_plugin_bbdev_pdsch_enc_acc_factory(accelerator_config, impl_name); + if (factory) { + return factory; } -}; -} // namespace + // No match. + fmt::print("Factory for bbdev-based PDSCH encoder hardware-accelerator type {} not found. Make sure to select a " + "valid type.\n", + impl_name); -#endif // ENABLE_PDSCH_HWACC - -std::shared_ptr -srsran::hal::create_hw_accelerator_pdsch_enc_factory(const hw_accelerator_pdsch_enc_configuration& accelerator_config) -{ -#ifdef ENABLE_PDSCH_HWACC - return std::make_shared(accelerator_config); -#else // ENABLE_PDSCH_HWACC return nullptr; -#endif // ENABLE_PDSCH_HWACC } diff --git a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.cpp b/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.cpp deleted file mode 100644 index 01bc0008bf..0000000000 --- a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.cpp +++ /dev/null @@ -1,207 +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 "hw_accelerator_pdsch_enc_acc100_impl.h" -#include "../../../dpdk/bbdev/ldpc/bbdev_ldpc_encoder.h" -#include "../../../dpdk/dpdk.h" -#include "srsran/hal/dpdk/bbdev/bbdev_op_pool_factory.h" -#include "srsran/hal/dpdk/mbuf_pool_factory.h" - -using namespace srsran; -using namespace hal; - -void hw_accelerator_pdsch_enc_acc100_impl::allocate_resources() -{ - int socket_id = bbdev_accelerator->get_socket_id(); - - // Create bbdev op pools for the accelerated LDPC encoder operations. - // op pools require unique names. - std::string op_pool_name = fmt::format("enc_op_pool_{}_{}", device_id, id); - op_pool = ::dpdk::create_bbdev_op_pool( - op_pool_name.c_str(), RTE_BBDEV_OP_LDPC_ENC, MAX_NOF_SEGMENTS, socket_id, bbdev_accelerator->get_logger()); - - // Create new mbuf pools for both input and output data for the hardware-accelerated LDPC encoder. - // Note that a predefined headroom length is added on top of the size required for the data in the mbufs. Also, the - // set mbuf length represents the maximum supported TB size (also accounting for the TB CRC length) when using TB - // mode. - ::dpdk::mempool_config msg_mpool_cfg; - unsigned nof_mbuf = bbdev_accelerator->get_nof_mbuf(); - msg_mpool_cfg.mbuf_data_size = bbdev_accelerator->get_msg_mbuf_size().value() + RTE_PKTMBUF_HEADROOM; - msg_mpool_cfg.n_mbuf = nof_mbuf; - ::dpdk::mempool_config rm_mpool_cfg; - rm_mpool_cfg.mbuf_data_size = bbdev_accelerator->get_rm_mbuf_size().value() + RTE_PKTMBUF_HEADROOM; - rm_mpool_cfg.n_mbuf = nof_mbuf; - // mbuf pools require unique names. - std::string mbuf_pool_name = fmt::format("enc_in_mbuf_pool_{}_{}", device_id, id); - in_mbuf_pool = - ::dpdk::create_mbuf_pool(mbuf_pool_name.c_str(), socket_id, msg_mpool_cfg, bbdev_accelerator->get_logger()); - mbuf_pool_name = fmt::format("enc_out_mbuf_pool_{}_{}", device_id, id); - out_mbuf_pool = - ::dpdk::create_mbuf_pool(mbuf_pool_name.c_str(), socket_id, rm_mpool_cfg, bbdev_accelerator->get_logger()); -} - -void hw_accelerator_pdsch_enc_acc100_impl::hw_reserve_queue() -{ - // Verify that no hardware-queue is reserved already. - if (queue_id < 0) { - int qid = -1; - do { - qid = bbdev_accelerator->reserve_queue(RTE_BBDEV_OP_LDPC_ENC); - } while (qid < 0 && !dedicated_queue); - queue_id = qid; - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] encoder id={}: reserved queue={}.", id, queue_id); - } -} - -void hw_accelerator_pdsch_enc_acc100_impl::hw_free_queue() -{ - // Free the queue in case of non-dedicated use or upon object destruction. - if (!dedicated_queue) { - bbdev_accelerator->free_queue(RTE_BBDEV_OP_LDPC_ENC, queue_id); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] encoder id={}: freed queue={}.", id, queue_id); - - queue_id = -1; - } -} - -void hw_accelerator_pdsch_enc_acc100_impl::hw_config(const hw_pdsch_encoder_configuration& config, unsigned cb_index) -{ - // Save configuration. - enc_config = config; - - // Store configuration in bbdev structure. - ::dpdk::set_ldpc_enc_bbdev_config(op[cb_index], config); - - // In case of TB mode, save the TB CRC. - if (!config.cb_mode) { - if (config.nof_tb_crc_bits == 16) { - tb_crc.resize(2); - } - tb_crc = config.tb_crc; - } else { - tb_crc.resize(0); - } - - // Reset the operation dropping control. - if (cb_index == 0) { - drop_op.resize(config.nof_segments); - drop_op.reset(); - } -} - -bool hw_accelerator_pdsch_enc_acc100_impl::hw_enqueue(span data, unsigned cb_index) -{ - bool enqueued = false; - - // Verify that the queue is not already full before trying to enqueue. - if (nof_enqueued_op < srsran::dpdk::MAX_NOF_OP_IN_QUEUE) { - // Set the memory-pointers for the accelerator and provide the input data. - ::rte_mempool* in_pool = in_mbuf_pool->get_pool(); - ::rte_mempool* out_pool = out_mbuf_pool->get_pool(); - ::dpdk::set_ldpc_enc_bbdev_data(op[cb_index], *in_pool, *out_pool, data, bbdev_accelerator->get_logger(), tb_crc); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[bbdev] encoder enqueueing: cb={}, LDPC [bg={}, mod={}, tb={}, tb_crc={}, seg={}, short_seg={}, " - "rv={}, cwa={}, cwb={}, lifting={}, Ncb={}, filler={}, rm={}], acc [cb_mode={}, queue={}]", - cb_index, - (unsigned)enc_config.base_graph_index, - (unsigned)enc_config.modulation, - enc_config.nof_tb_bits, - enc_config.nof_tb_crc_bits, - enc_config.nof_segments, - enc_config.nof_short_segments, - enc_config.rv, - enc_config.cw_length_a, - enc_config.cw_length_b, - enc_config.lifting_size, - enc_config.Ncb, - enc_config.nof_filler_bits, - enc_config.rm_length, - enc_config.cb_mode, - queue_id); - - // Enqueue the LDPC encoding operation. - enqueued = ::dpdk::enqueue_ldpc_enc_operation(op[cb_index], - 1, - device_id, - static_cast(queue_id), - bbdev_accelerator->get_logger()); // TBD: single operation enqueued. - - // Update the enqueued task counter. - if (enqueued) { - ++nof_enqueued_op; - // Drop the operation due to an enqueueing error. - } else { - drop_op.set(cb_index); - enqueued = true; - } - } - - return enqueued; -} - -bool hw_accelerator_pdsch_enc_acc100_impl::hw_dequeue(span data, - span packed_data, - unsigned segment_index) -{ - bool dropped = drop_op.test(segment_index); - bool dequeued = false; - - // Verify that the queue is not already emtpy and that the operation has not been dropped before trying to dequeue. - if (nof_enqueued_op > 0 && !dropped) { - // Dequeue processed operations from the hardware-accelerated LDPC encoder. - dequeued = ::dpdk::dequeue_ldpc_enc_operation(op[segment_index], - 1, - device_id, - static_cast(queue_id), - bbdev_accelerator->get_logger()); // TBD: single operation dequeued. - - // Read the returned results (if any). - if (dequeued) { - // Read the accelerator output data. - ::dpdk::read_ldpc_enc_bbdev_data(op[segment_index], data, packed_data, enc_config.cb_mode); - - // Update the enqueued task counter. - --nof_enqueued_op; - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info( - "[bbdev] encoder dequeued: cb={}, acc [cb_mode={}, queue={}]", segment_index, enc_config.cb_mode, queue_id); - } - } else if (dropped) { - drop_op.reset(segment_index); - dequeued = true; - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info( - "[bbdev] encoder skipped: cb={}, acc [cb_mode={}, queue={}]", segment_index, enc_config.cb_mode, queue_id); - } - - return dequeued; -} - -bool hw_accelerator_pdsch_enc_acc100_impl::get_hw_cb_mode() const -{ - return cb_mode; -} - -unsigned hw_accelerator_pdsch_enc_acc100_impl::get_hw_max_tb_size() const -{ - return max_tb_size; -} diff --git a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.h b/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.h deleted file mode 100644 index a3237f4c1b..0000000000 --- a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_acc100_impl.h +++ /dev/null @@ -1,142 +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. - * - */ - -/// \file -/// \brief Hardware accelerated PDSCH encoder functions declaration. - -#pragma once - -#include "../../../dpdk/bbdev/bbdev.h" -#include "hw_accelerator_pdsch_enc_impl.h" -#include "srsran/adt/static_vector.h" -#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include "srsran/hal/dpdk/bbdev/bbdev_op_pool.h" -#include "srsran/hal/dpdk/mbuf_pool.h" -#include "srsran/ran/sch/sch_constants.h" - -namespace srsran { -namespace hal { - -/// Class representing the ACC100 implementation of PDSCH encoding. -class hw_accelerator_pdsch_enc_acc100_impl : public hw_accelerator_pdsch_enc_impl -{ - /// Hardware-specific implementation of the reserve queue function. - void hw_reserve_queue() override; - /// Hardware-specific implementation of the free queue function. - void hw_free_queue() override; - /// Hardware-specific implementation of the enqueue_operation function. - bool hw_enqueue(span data, unsigned cb_index) override; - /// Hardware-specific implementation of the dequeue_operation function. - bool hw_dequeue(span data, span packed_data, unsigned segment_index) override; - /// Hardware-specific configuration function. - void hw_config(const hw_pdsch_encoder_configuration& config, unsigned cb_index) override; - /// Hardware-specific CB mode quering function. - bool get_hw_cb_mode() const override; - /// Hardware-specific maximum supported TB size quering function. - unsigned get_hw_max_tb_size() const override; - - /// Allocate the required resources from the bbdev-based hardware-accelerator. - void allocate_resources(); - - /// \file - /// \brief Members specific to bbdev-accelerated LDPC encoder functions. - - /// Unique ID of the current hardware-accelerated function. - unsigned id; - - /// Pointer to a bbdev-based hardware-accelerator. - std::shared_ptr bbdev_accelerator; - - /// Private member to store the ID of the bbdev-based hardware-accelerator. - unsigned device_id; - - /// Private member to store the ID of the queue used by the hardware-accelerated LDPC encoder function. - int queue_id; - - /// Indicates the number of encoding operations in the queue. - unsigned nof_enqueued_op = 0; - - /// Operation pool used by the hardware-accelerated LDPC encoder. - std::unique_ptr op_pool; - - /// Structure specifying each hardware-accelerated encode operation. - ::rte_bbdev_enc_op op[MAX_NOF_SEGMENTS]; - - /// Input-data mbuf pool used by the hardware-accelerated LDPC encoder. - std::unique_ptr in_mbuf_pool; - - /// Output-data mbuf pool used by the hardware-accelerated LDPC encoder. - std::unique_ptr out_mbuf_pool; - - /// \file - /// \brief Common members to all hardware-accelerated LDPC encoder functions. - - /// Private member to store the configuration of the current operation. - hw_pdsch_encoder_configuration enc_config; - - /// Private member to store the operation mode. - bool cb_mode = false; - - /// Private member to store the maximum supported TB size (in bytes). - unsigned max_tb_size; - - /// Private member to store the TB CRC (only for TB mode operation). - static_vector tb_crc; - - /// Array flagging those encoding operations that will be dropped due to enqueueing errors. - bounded_bitset drop_op; - - /// Indicates if the accelerated function uses a dedicated hardware queue or needs to reserve one for each operation. - bool dedicated_queue; - -public: - /// Constructor taking care of obtaining a bbdev-based hardware-accelerator queue and allocating the required - /// resources. - hw_accelerator_pdsch_enc_acc100_impl(std::shared_ptr bbdev_accelerator_, - bool cb_mode_, - unsigned max_tb_size_, - bool dedicated_queue_) : - bbdev_accelerator(std::move(bbdev_accelerator_)), - cb_mode(cb_mode_), - max_tb_size(max_tb_size_), - dedicated_queue(dedicated_queue_) - { - id = bbdev_accelerator->reserve_encoder(); - device_id = bbdev_accelerator->get_device_id(); - // Reserve a hardware queue in case of dedicated use. - queue_id = -1; - if (dedicated_queue) { - hw_reserve_queue(); - srsran_assert(queue_id >= 0, "No free RTE_BBDEV_OP_LDPC_ENC queues available."); - } - allocate_resources(); - drop_op.resize(MAX_NOF_SEGMENTS); - drop_op.reset(); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] new encoder: id={}.", id); - } - - /// Destructor taking care of freeing the utilized resources. - ~hw_accelerator_pdsch_enc_acc100_impl() - { - // Free the reserved hardware queue in case of dedicated use. - dedicated_queue = false; - hw_free_queue(); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] destroyed encoder: id={}.", id); - } -}; - -} // namespace hal -} // namespace srsran diff --git a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.cpp b/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.cpp deleted file mode 100644 index 944ff02e3f..0000000000 --- a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.cpp +++ /dev/null @@ -1,53 +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 "hw_accelerator_pdsch_enc_impl.h" - -using namespace srsran; -using namespace hal; - -void hw_accelerator_pdsch_enc_impl::reserve_queue() -{ - hw_reserve_queue(); -} - -void hw_accelerator_pdsch_enc_impl::free_queue() -{ - hw_free_queue(); -} - -bool hw_accelerator_pdsch_enc_impl::enqueue_operation(span data, - span aux_data, - unsigned cb_index) -{ - return hw_enqueue(data, cb_index); -} - -bool hw_accelerator_pdsch_enc_impl::dequeue_operation(span data, - span packed_data, - unsigned segment_index) -{ - return hw_dequeue(data, packed_data, segment_index); -} - -void hw_accelerator_pdsch_enc_impl::configure_operation(const hw_pdsch_encoder_configuration& config, unsigned cb_index) -{ - hw_config(config, cb_index); -} - -bool hw_accelerator_pdsch_enc_impl::get_cb_mode() const -{ - return get_hw_cb_mode(); -} - -unsigned hw_accelerator_pdsch_enc_impl::get_max_tb_size() const -{ - return get_hw_max_tb_size(); -} diff --git a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.h b/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.h deleted file mode 100644 index cdf67af306..0000000000 --- a/lib/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_impl.h +++ /dev/null @@ -1,61 +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. - * - */ - -/// \file -/// \brief Hardware accelerated PDSCH encoder functions declaration. - -#pragma once - -#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h" - -namespace srsran { -namespace hal { - -/// Generic hardware accelerated PDSCH encoder functions. -class hw_accelerator_pdsch_enc_impl : public hw_accelerator_pdsch_enc -{ -public: - /// Default constructor. - hw_accelerator_pdsch_enc_impl() = default; - - // See hw_accelerator interface for the documentation. - void reserve_queue() override; - // See hw_accelerator interface for the documentation. - void free_queue() override; - // See hw_accelerator interface for the documentation. - bool enqueue_operation(span data, span aux_data = {}, unsigned cb_index = 0) override; - // See hw_accelerator interface for the documentation. - bool dequeue_operation(span data, span packed_data = {}, unsigned segment_index = 0) override; - // See hw_accelerator interface for the documentation. - void configure_operation(const hw_pdsch_encoder_configuration& config, unsigned cb_index = 0) override; - // See hw_accelerator interface for the documentation. - bool get_cb_mode() const override; - // See hw_accelerator interface for the documentation. - unsigned get_max_tb_size() const override; - -private: - /// Hardware-specific implementation of the reserve queue function. - virtual void hw_reserve_queue() = 0; - /// Hardware-specific implementation of the free queue function. - virtual void hw_free_queue() = 0; - /// Hardware-specific implementation of the enqueue_operation function. - virtual bool hw_enqueue(span data, unsigned cb_index) = 0; - /// Hardware-specific implementation of the dequeue_operation function. - virtual bool hw_dequeue(span data, span packed_data, unsigned segment_index) = 0; - /// Hardware-specific configuration function. - virtual void hw_config(const hw_pdsch_encoder_configuration& config, unsigned cb_index) = 0; - /// Hardware-specific CB mode quering function. - virtual bool get_hw_cb_mode() const = 0; - /// Hardware-specific maximum supported TB size quering function. - virtual unsigned get_hw_max_tb_size() const = 0; -}; - -} // namespace hal -} // namespace srsran diff --git a/lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.cpp b/lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.cpp new file mode 100644 index 0000000000..b28485a44d --- /dev/null +++ b/lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.cpp @@ -0,0 +1,156 @@ +/* + * + * 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 "plugin_bbdev_pdsch_enc_acc_factory.h" +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h" +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_factory.h" +#include + +using namespace srsran; +using namespace hal; + +namespace { + +/// Dynamic library handler deleter - closes the dynamic library upon destruction. +struct dynamic_library_deleter { + void operator()(void* handler) const + { + if (handler != nullptr) { + ::dlclose(handler); + } + } +}; + +using handler_ptr = std::shared_ptr; + +/// Wraps a PDSCH encoder hardware-accelerator interface with the dynamic library handle. +class hw_accelerator_pdsch_enc_dynamic_wrapper : public hw_accelerator_pdsch_enc +{ +public: + /// Constructs a wrapper from the dynamic library handler and an open PDSCH encoder hardware-accelerator interface. + explicit hw_accelerator_pdsch_enc_dynamic_wrapper(handler_ptr handler_, + std::shared_ptr pdsch_acc_) noexcept : + handler(std::move(handler_)), pdsch_acc(std::move(pdsch_acc_)) + { + } + + /// Default destructor - deletes the instance first then the dynamic library handler. + ~hw_accelerator_pdsch_enc_dynamic_wrapper() + { + pdsch_acc.reset(); + handler.reset(); + } + + bool enqueue_operation(span data, span aux_data = {}, unsigned cb_index = 0) override + { + return pdsch_acc->enqueue_operation(data, aux_data, cb_index); + } + bool dequeue_operation(span data, span aux_data = {}, unsigned segment_index = 0) override + { + return pdsch_acc->dequeue_operation(data, aux_data, segment_index); + } + void reserve_queue() override { return pdsch_acc->reserve_queue(); } + void free_queue() override { return pdsch_acc->free_queue(); } + void configure_operation(const hw_pdsch_encoder_configuration& config, unsigned cb_index = 0) override + { + return pdsch_acc->configure_operation(config, cb_index); + } + bool is_cb_mode_supported() const override { return pdsch_acc->is_cb_mode_supported(); } + unsigned get_max_supported_buff_size() const override { return pdsch_acc->get_max_supported_buff_size(); } + +private: + handler_ptr handler; + std::shared_ptr pdsch_acc; +}; + +/// Wraps a bbdev-based PDSCH encoder hardware-accelerator factory and a dynamic library handler. +class bbdev_pdsch_enc_acc_factory_dynamic_wrapper : public hw_accelerator_pdsch_enc_factory +{ +public: + /// Constructs from handler and factory. + bbdev_pdsch_enc_acc_factory_dynamic_wrapper(handler_ptr handle_, + std::unique_ptr factory_) : + handle(std::move(handle_)), factory(std::move(factory_)) + { + } + + /// Default destructor - deletes the factory first then the dynamic library handler. + ~bbdev_pdsch_enc_acc_factory_dynamic_wrapper() + { + factory.reset(); + handle.reset(); + } + + // See interface for documentation. + std::unique_ptr create() override + { + // Create bbdev-based PDSCH encoder hardware-accelerator using the loaded factory. + std::unique_ptr pdsch_enc_if = factory->create(); + if (pdsch_enc_if == nullptr) { + report_error("Failed to create plugin bbdev_pdsch_enc_acc_factory"); + } + + // Wrap the dynamic library handler and the bbdev-based PDSCH encoder hardware-accelerator instance. + return std::make_unique(handle, std::move(pdsch_enc_if)); + } + +private: + handler_ptr handle; + std::unique_ptr factory; +}; + +} // namespace + +std::unique_ptr srsran::hal::create_plugin_bbdev_pdsch_enc_acc_factory( + const bbdev_hwacc_pdsch_enc_factory_configuration& accelerator_config, + std::string impl_name) +{ + char* err = nullptr; + std::string plugin_name = "libsrsran_bbdev_pdsch_enc_acc_" + impl_name + ".so"; + + void* dl_handle = ::dlopen(plugin_name.c_str(), RTLD_NOW + RTLD_DEEPBIND + RTLD_GLOBAL); + if (dl_handle == nullptr) { + err = ::dlerror(); + if (err != nullptr) { + fmt::print("Failed to load bbdev_pdsch_enc_acc plugin {}: {}\n", plugin_name, err); + } + return nullptr; + } + + // Create factory function prototype. + using create_factory_func = + std::unique_ptr(const bbdev_hwacc_pdsch_enc_factory_configuration&); + + // Load symbol. + auto* create_factory = + reinterpret_cast(::dlsym(dl_handle, "create_dynamic_bbdev_pdsch_enc_acc_factory")); + + // Handle an error loading the symbol. + if (create_factory == nullptr) { + err = ::dlerror(); + if (err != nullptr) { + fmt::print("Error loading symbol {}: {}\n", "create_dynamic_bbdev_pdsch_enc_acc_factory", err); + } + return nullptr; + } + + // Create factory. + std::unique_ptr factory = (*create_factory)(accelerator_config); + + if (factory == nullptr) { + return nullptr; + } + + // Create shared pointer with deleter. + dynamic_library_deleter deleter; + handler_ptr handle(dl_handle, deleter); + + return std::make_unique(std::move(handle), std::move(factory)); +} diff --git a/lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.h b/lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.h new file mode 100644 index 0000000000..abe1d8015e --- /dev/null +++ b/lib/hal/phy/upper/channel_processors/plugin_bbdev_pdsch_enc_acc_factory.h @@ -0,0 +1,25 @@ +/* + * + * 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/hal/phy/upper/channel_processors/hw_accelerator_factories.h" +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_factory.h" +#include + +namespace srsran { +namespace hal { + +std::unique_ptr +create_plugin_bbdev_pdsch_enc_acc_factory(const bbdev_hwacc_pdsch_enc_factory_configuration& accelerator_config, + std::string impl_name); + +} // namespace hal +} // namespace srsran diff --git a/lib/hal/phy/upper/channel_processors/pusch/CMakeLists.txt b/lib/hal/phy/upper/channel_processors/pusch/CMakeLists.txt index df823db6cd..9538f84893 100644 --- a/lib/hal/phy/upper/channel_processors/pusch/CMakeLists.txt +++ b/lib/hal/phy/upper/channel_processors/pusch/CMakeLists.txt @@ -14,10 +14,9 @@ endif () add_library(hal_hwacc_pusch STATIC hw_accelerator_factories.cpp - hw_accelerator_pusch_dec_impl.cpp - hw_accelerator_pusch_dec_acc100_impl.cpp - ext_harq_buffer_context_repository_factory.cpp) + ext_harq_buffer_context_repository_factory.cpp + plugin_bbdev_pusch_dec_acc_factory.cpp) set_source_files_properties(hw_accelerator_factories.cpp PROPERTIES COMPILE_DEFINITIONS "${HWACC_FACTORIES_DEFINITIONS}") -target_link_libraries(hal_hwacc_pusch hal_bbdev hal_dpdk ${DPDK_LIBRARIES}) +target_link_libraries(hal_hwacc_pusch hal_bbdev_factory hal_dpdk ${DPDK_LIBRARIES} dl) diff --git a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.cpp b/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.cpp index 837b577de2..870dacc6c0 100644 --- a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.cpp +++ b/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.cpp @@ -9,64 +9,30 @@ */ #include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" -#include "../../../../dpdk/bbdev/bbdev.h" -#include "../../../../dpdk/dpdk.h" -#include "hw_accelerator_pusch_dec_acc100_impl.h" -#include "hw_accelerator_pusch_dec_impl.h" +#include "plugin_bbdev_pusch_dec_acc_factory.h" using namespace srsran; using namespace hal; -#ifdef ENABLE_PUSCH_HWACC - -namespace { - -class hw_accelerator_pusch_dec_factory_spec : public hw_accelerator_pusch_dec_factory +std::unique_ptr +srsran::hal::create_bbdev_pusch_dec_acc_factory(const bbdev_hwacc_pusch_dec_factory_configuration& accelerator_config, + std::string impl_name) { -private: - /// Accelerator type. - std::string acc_type; - /// Interfacing to a bbdev-based hardware-accelerator. - std::shared_ptr bbdev_accelerator; - /// Defines if the soft-buffer is implemented in the accelerator or not. - bool ext_softbuffer; - /// Interfacing to an external HARQ buffer context repository. - std::shared_ptr harq_buffer_context; - /// Indicates if the accelerated function uses a dedicated hardware queue or needs to reserve one for each operation. - bool dedicated_queue; - -public: - // Default constructor. - explicit hw_accelerator_pusch_dec_factory_spec(const hw_accelerator_pusch_dec_configuration& accelerator_config) : - acc_type(accelerator_config.acc_type), - bbdev_accelerator(std::move(accelerator_config.bbdev_accelerator)), - ext_softbuffer(accelerator_config.ext_softbuffer), - harq_buffer_context(accelerator_config.harq_buffer_context), - dedicated_queue(accelerator_config.dedicated_queue) - { + // Convert implementation name to lower case. + for (char& c : impl_name) { + c = std::tolower(c); } - std::unique_ptr create() override - { - if (acc_type == "acc100") { - return std::make_unique( - bbdev_accelerator, ext_softbuffer, harq_buffer_context, dedicated_queue); - } - // Handle other accelerator types here. - return {}; + // Try creating a plugin bbdev-based PUSCH decoder hardware-accelerator factory. + auto factory = create_plugin_bbdev_pusch_dec_acc_factory(accelerator_config, impl_name); + if (factory) { + return factory; } -}; -} // namespace + // No match. + fmt::print("Factory for bbdev-based PUSCH decoder hardware-accelerator type {} not found. Make sure to select a " + "valid type.\n", + impl_name); -#endif // ENABLE_PUSCH_HWACC - -std::shared_ptr -srsran::hal::create_hw_accelerator_pusch_dec_factory(const hw_accelerator_pusch_dec_configuration& accelerator_config) -{ -#ifdef ENABLE_PUSCH_HWACC - return std::make_shared(accelerator_config); -#else // ENABLE_PUSCH_HWACC return nullptr; -#endif // ENABLE_PUSCH_HWACC } diff --git a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.cpp b/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.cpp deleted file mode 100644 index 45b8e60d1e..0000000000 --- a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.cpp +++ /dev/null @@ -1,264 +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 "hw_accelerator_pusch_dec_acc100_impl.h" -#include "../../../../dpdk/bbdev/ldpc/bbdev_ldpc_decoder.h" -#include "../../../../dpdk/dpdk.h" -#include "srsran/hal/dpdk/bbdev/bbdev_op_pool_factory.h" -#include "srsran/hal/dpdk/mbuf_pool_factory.h" - -using namespace srsran; -using namespace hal; - -void hw_accelerator_pusch_dec_acc100_impl::allocate_resources() -{ - int socket_id = bbdev_accelerator->get_socket_id(); - - // Create bbdev op pools for the accelerated LDPC decoder operations. - // op pools require unique names. - std::string op_pool_name = fmt::format("dec_op_pool_{}_{}", device_id, id); - op_pool = ::dpdk::create_bbdev_op_pool( - op_pool_name.c_str(), RTE_BBDEV_OP_LDPC_DEC, MAX_NOF_SEGMENTS, socket_id, bbdev_accelerator->get_logger()); - - // Create new mbuf pools for both input and output data for the hardware-accelerated LDPC decoder. - // Note that the buffers are sized taking into account that only CB mode is supported by the decoder. - ::dpdk::mempool_config rm_mpool_cfg; - unsigned nof_mbuf = bbdev_accelerator->get_nof_mbuf(); - rm_mpool_cfg.mbuf_data_size = bbdev_accelerator->get_rm_mbuf_size().value(); - rm_mpool_cfg.n_mbuf = nof_mbuf; - ::dpdk::mempool_config msg_mpool_cfg; - msg_mpool_cfg.mbuf_data_size = bbdev_accelerator->get_msg_mbuf_size().value(); - msg_mpool_cfg.n_mbuf = nof_mbuf; - - // mbuf pools require unique names. - std::string mbuf_pool_name = fmt::format("dec_in_mbuf_pool_{}_{}", device_id, id); - in_mbuf_pool = - ::dpdk::create_mbuf_pool(mbuf_pool_name.c_str(), socket_id, rm_mpool_cfg, bbdev_accelerator->get_logger()); - - mbuf_pool_name = fmt::format("harq_in_mbuf_pool_{}_{}", device_id, id); - harq_in_mbuf_pool = - ::dpdk::create_mbuf_pool(mbuf_pool_name.c_str(), socket_id, rm_mpool_cfg, bbdev_accelerator->get_logger()); - - mbuf_pool_name = fmt::format("dec_out_mbuf_pool_{}_{}", device_id, id); - out_mbuf_pool = - ::dpdk::create_mbuf_pool(mbuf_pool_name.c_str(), socket_id, msg_mpool_cfg, bbdev_accelerator->get_logger()); - - mbuf_pool_name = fmt::format("harq_out_mbuf_pool_{}_{}", device_id, id); - harq_out_mbuf_pool = - ::dpdk::create_mbuf_pool(mbuf_pool_name.c_str(), socket_id, rm_mpool_cfg, bbdev_accelerator->get_logger()); -} - -void hw_accelerator_pusch_dec_acc100_impl::hw_reserve_queue() -{ - // Verify that no hardware-queue is reserved already. - if (queue_id < 0) { - int qid = -1; - do { - qid = bbdev_accelerator->reserve_queue(RTE_BBDEV_OP_LDPC_DEC); - } while (qid < 0 && !dedicated_queue); - queue_id = qid; - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] decoder id={}: reserved queue={}.", id, queue_id); - } -} - -void hw_accelerator_pusch_dec_acc100_impl::hw_free_queue() -{ - // Free the queue in case of non-dedicated use or upon object destruction. - if (!dedicated_queue) { - bbdev_accelerator->free_queue(RTE_BBDEV_OP_LDPC_DEC, queue_id); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] decoder id={}: freed queue={}.", id, queue_id); - - queue_id = -1; - } -} - -void hw_accelerator_pusch_dec_acc100_impl::hw_config(const hw_pusch_decoder_configuration& config, unsigned cb_index) -{ - // Save configuration. - dec_config = config; - - // Reset the operation dropping control (first CB of the TB only). - if (cb_index == 0) { - drop_op.resize(config.nof_segments); - drop_op.reset(); - harq_context_entries.resize(config.nof_segments); - } - - // Get the HARQ buffer context entry of the CB or create a new one. - harq_context_entries[cb_index] = harq_buffer_context->get(config.absolute_cb_id, config.new_data); - - // Store configuration in bbdev structure. - ::dpdk::set_ldpc_dec_bbdev_config(op[cb_index], config, ext_softbuffer); -} - -bool hw_accelerator_pusch_dec_acc100_impl::hw_enqueue(span data, - span soft_data, - unsigned cb_index) -{ - bool enqueued = false; - unsigned soft_data_len = harq_context_entries[cb_index]->soft_data_len; - bool soft_data_len_ok = dec_config.new_data || (!dec_config.new_data && soft_data_len > 0); - - // Verify that the queue is not already full before trying to enqueue. - if (nof_enqueued_op < ::dpdk::MAX_NOF_OP_IN_QUEUE && soft_data_len_ok) { - // Set the memory-pointers for the accelerator and provide the input data and related soft-combining inputs. - ::rte_mempool* in_pool = in_mbuf_pool->get_pool(); - ::rte_mempool* harq_in_pool = harq_in_mbuf_pool->get_pool(); - ::rte_mempool* out_pool = out_mbuf_pool->get_pool(); - ::rte_mempool* harq_out_pool = harq_out_mbuf_pool->get_pool(); - ::dpdk::set_ldpc_dec_bbdev_data(op[cb_index], - *in_pool, - *harq_in_pool, - *out_pool, - *harq_out_pool, - data, - soft_data, - dec_config.new_data, - ext_softbuffer, - soft_data_len, - cb_index, - dec_config.absolute_cb_id, - bbdev_accelerator->get_logger()); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[bbdev] decoder enqueueing: cb={}, harq [new_data={}, sof_len={}, id={}], " - "LDPC [bg={}, mod={}, seg={}, rv={}, cw={}, lifting={}, Ncb={}, filler={}, crc_len={}], acc [queue={}]", - cb_index, - dec_config.new_data, - soft_data_len, - dec_config.absolute_cb_id, - (unsigned)dec_config.base_graph_index, - (unsigned)dec_config.modulation, - dec_config.nof_segments, - dec_config.rv, - dec_config.cw_length, - dec_config.lifting_size, - dec_config.Ncb, - dec_config.nof_filler_bits, - dec_config.cb_crc_len, - queue_id); - - // Enqueue the LDPC decoding operation. - enqueued = ::dpdk::enqueue_ldpc_dec_operation(op[cb_index], - 1, - device_id, - static_cast(queue_id), - dec_config.new_data, - ext_softbuffer, - bbdev_accelerator->get_logger()); // TBD: single operation enqueued. - - // Update the enqueued task counter. - if (enqueued) { - ++nof_enqueued_op; - // Drop the operation due to an enqueueing error. - } else { - drop_op.set(cb_index); - enqueued = true; - } - } else if (!soft_data_len_ok) { - drop_op.set(cb_index); - enqueued = true; - } - - return enqueued; -} - -bool hw_accelerator_pusch_dec_acc100_impl::hw_dequeue(span data, - span soft_data, - unsigned segment_index) -{ - bool dropped = drop_op.test(segment_index); - bool dequeued = false; - - // Verify that the queue is not already emtpy and that the operation has not been dropped before trying to dequeue. - if (nof_enqueued_op > 0 && !dropped) { - // Dequeue processed operations from the hardware-accelerated LDPC decoder. - dequeued = ::dpdk::dequeue_ldpc_dec_operation(op[segment_index], - 1, - device_id, - static_cast(queue_id), - bbdev_accelerator->get_logger()); // TBD: single operation dequeued. - - // Check if there are new results available from the hardware accelerator. - if (dequeued) { - // Read the accelerator output data and related soft-combining outputs, while updating the HARQ context. - harq_context_entries[segment_index]->soft_data_len = - ::dpdk::read_ldpc_dec_bbdev_data(op[segment_index], data, soft_data, dec_config.new_data, ext_softbuffer); - - // Update the enqueued task counter. - --nof_enqueued_op; - } - } else if (dropped) { - dequeued = true; - } - - return dequeued; -} - -void hw_accelerator_pusch_dec_acc100_impl::hw_read_outputs(hw_pusch_decoder_outputs& out, - unsigned cb_index, - unsigned absolute_cb_id) -{ - // Save outputs. - dec_out = out; - - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - - // Operation dropped due to encoding errors. - if (drop_op.test(cb_index)) { - out.CRC_pass = false; - out.nof_ldpc_iterations = dec_config.max_nof_ldpc_iterations; - drop_op.reset(cb_index); - - // HAL logging. - logger.info("[bbdev] decoder skipped: cb={}, harq [new_data={}, sof_len={}, id={}], acc [queue={}]", - cb_index, - dec_config.new_data, - harq_context_entries[cb_index]->soft_data_len, - absolute_cb_id, - queue_id); - - return; - } - - // Check the CRC and number of utilized ldpc decoding iterations. - int ldpc_dec_status = op[cb_index].status; - out.CRC_pass = !(ldpc_dec_status & (1 << RTE_BBDEV_CRC_ERROR)); - out.nof_ldpc_iterations = op[cb_index].ldpc_dec.iter_count; - - // HAL logging. - logger.info("[bbdev] decoder dequeued: cb={}, harq [new_data={}, sof_len={}, id={}], LDPC " - "[crc_pass={}, " - "ldpc_iter={}], acc [queue={}]", - cb_index, - dec_config.new_data, - harq_context_entries[cb_index]->soft_data_len, - absolute_cb_id, - (unsigned)dec_config.cb_crc_type == 1 ? (int)out.CRC_pass : -1, - out.nof_ldpc_iterations, - queue_id); -} - -void hw_accelerator_pusch_dec_acc100_impl::hw_free_harq_context(unsigned absolute_cb_id) -{ - harq_buffer_context->free(absolute_cb_id); -} - -bool hw_accelerator_pusch_dec_acc100_impl::is_hw_external_harq_supported() const -{ - return ext_softbuffer; -} diff --git a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.h b/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.h deleted file mode 100644 index 9bced2d3cc..0000000000 --- a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_acc100_impl.h +++ /dev/null @@ -1,155 +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. - * - */ - -/// \file -/// \brief Hardware accelerated PUSCH decoder functions declaration. - -#pragma once - -#include "../../../../dpdk/bbdev/bbdev.h" -#include "hw_accelerator_pusch_dec_impl.h" -#include "srsran/adt/static_vector.h" -#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include "srsran/hal/dpdk/bbdev/bbdev_op_pool.h" -#include "srsran/hal/dpdk/mbuf_pool.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h" -#include "srsran/ran/sch/sch_constants.h" - -namespace srsran { -namespace hal { - -/// Class representing the ACC100 implementation of PUSCH decoding. -class hw_accelerator_pusch_dec_acc100_impl : public hw_accelerator_pusch_dec_impl -{ - /// Hardware-specific implementation of the reserve queue function. - void hw_reserve_queue() override; - /// Hardware-specific implementation of the free queue function. - void hw_free_queue() override; - /// Hardware-specific implementation of the enqueue_operation function. - bool hw_enqueue(span data, span soft_data, unsigned cb_index) override; - /// Hardware-specific implementation of the dequeue_operation function. - bool hw_dequeue(span data, span soft_data, unsigned segment_index) override; - /// Hardware-specific configuration function. - void hw_config(const hw_pusch_decoder_configuration& config, unsigned cb_index) override; - /// Hardware-specific operation status outputs recovery function. - void hw_read_outputs(hw_pusch_decoder_outputs& out, unsigned cb_index, unsigned absolute_cb_id) override; - /// Hardware-specific HARQ buffer context freeing function. - void hw_free_harq_context(unsigned absolute_cb_id) override; - /// Hardware-specific external HARQ buffer checking function. - bool is_hw_external_harq_supported() const override; - - /// Allocate the required resources from the bbdev-based hardware-accelerator. - void allocate_resources(); - - /// \file - /// \brief Members specific to bbdev-accelerated LDPC decoder functions. - - /// Unique ID of the current hardware-accelerated function. - unsigned id; - - /// Pointer to a bbdev-based hardware-accelerator. - std::shared_ptr bbdev_accelerator; - - /// Private member to store the ID of the bbdev-based hardware-accelerator. - unsigned device_id; - - /// Private member to store the ID of the queue used by the hardware-accelerated LDPC decoder function. - int queue_id; - - /// Indicates the number of decoding operations in the queue. - unsigned nof_enqueued_op = 0; - - /// Operation pool used by the hardware-accelerated LDPC decoder. - std::unique_ptr op_pool; - - /// Structure specifying each hardware-accelerated decode operation. - ::rte_bbdev_dec_op op[MAX_NOF_SEGMENTS]; - - /// Input-data mbuf pool used by the hardware-accelerated LDPC decoder. - std::unique_ptr in_mbuf_pool; - - /// HARQ input-data mbuf pool used by the hardware-accelerated LDPC decoder. - std::unique_ptr harq_in_mbuf_pool; - - /// Output-data mbuf pool used by the hardware-accelerated LDPC decoder. - std::unique_ptr out_mbuf_pool; - - /// HARQ output-data mbuf pool used by the hardware-accelerated LDPC decoder. - std::unique_ptr harq_out_mbuf_pool; - - /// \file - /// \brief Common members to all hardware-accelerated LDPC decoder functions. - - /// Private member to store the configuration of the current operation. - hw_pusch_decoder_configuration dec_config; - - /// Private member to store the soft-buffer implementation type. - bool ext_softbuffer; - - /// Context of the external HARQ buffer. - std::shared_ptr harq_buffer_context; - - /// Array flagging those decoding operations that will be dropped due to enqueueing errors. - bounded_bitset drop_op; - - /// Private member to store the outputs of the current operation. - hw_pusch_decoder_outputs dec_out; - - /// HARQ context repository entry for the current decoding operation. - std::vector harq_context_entries; - - /// Indicates if the accelerated function uses a dedicated hardware queue or needs to reserve one for each operation. - bool dedicated_queue; - -public: - /// Constructor taking care of obtaining a bbdev-based hardware-accelerator queue and allocating the required - /// resources. - hw_accelerator_pusch_dec_acc100_impl(std::shared_ptr bbdev_accelerator_, - bool ext_softbuffer_, - std::shared_ptr harq_buffer_context_, - bool dedicated_queue_) : - bbdev_accelerator(std::move(bbdev_accelerator_)), - ext_softbuffer(ext_softbuffer_), - harq_buffer_context(std::move(harq_buffer_context_)), - dedicated_queue(dedicated_queue_) - { - id = bbdev_accelerator->reserve_decoder(); - device_id = bbdev_accelerator->get_device_id(); - // Reserve a hardware queue in case of dedicated use. - queue_id = -1; - if (dedicated_queue) { - hw_reserve_queue(); - srsran_assert(queue_id >= 0, "No free RTE_BBDEV_OP_LDPC_DEC queues available."); - } - allocate_resources(); - drop_op.resize(MAX_NOF_SEGMENTS); - drop_op.reset(); - harq_context_entries.reserve(MAX_NOF_SEGMENTS); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] new decoder: id={}.", id); - } - - /// Destructor taking care of freeing the utilized resources. - ~hw_accelerator_pusch_dec_acc100_impl() - { - // Free the reserved hardware queue in case of dedicated use. - dedicated_queue = false; - hw_free_queue(); - - // HAL logging. - srslog::basic_logger& logger = bbdev_accelerator->get_logger(); - logger.info("[acc100] destroyed decoder: id={}.", id); - } -}; - -} // namespace hal -} // namespace srsran diff --git a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.cpp b/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.cpp deleted file mode 100644 index 627489b630..0000000000 --- a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.cpp +++ /dev/null @@ -1,60 +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 "hw_accelerator_pusch_dec_impl.h" - -using namespace srsran; -using namespace hal; - -void hw_accelerator_pusch_dec_impl::reserve_queue() -{ - hw_reserve_queue(); -} - -void hw_accelerator_pusch_dec_impl::free_queue() -{ - hw_free_queue(); -} - -bool hw_accelerator_pusch_dec_impl::enqueue_operation(span data, - span soft_data, - unsigned cb_index) -{ - return hw_enqueue(data, soft_data, cb_index); -} - -bool hw_accelerator_pusch_dec_impl::dequeue_operation(span data, - span soft_data, - unsigned segment_index) -{ - return hw_dequeue(data, soft_data, segment_index); -} - -void hw_accelerator_pusch_dec_impl::configure_operation(const hw_pusch_decoder_configuration& config, unsigned cb_index) -{ - hw_config(config, cb_index); -} - -void hw_accelerator_pusch_dec_impl::read_operation_outputs(hw_pusch_decoder_outputs& out, - unsigned cb_index, - unsigned absolute_cb_id) -{ - hw_read_outputs(out, cb_index, absolute_cb_id); -} - -void hw_accelerator_pusch_dec_impl::free_harq_context_entry(unsigned absolute_cb_id) -{ - hw_free_harq_context(absolute_cb_id); -} - -bool hw_accelerator_pusch_dec_impl::is_external_harq_supported() const -{ - return is_hw_external_harq_supported(); -} diff --git a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.h b/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.h deleted file mode 100644 index 4352579d12..0000000000 --- a/lib/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_impl.h +++ /dev/null @@ -1,66 +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. - * - */ - -/// \file -/// \brief Hardware accelerated PUSCH decoder functions declaration. - -#pragma once - -#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec.h" - -namespace srsran { -namespace hal { - -/// Generic hardware accelerated PUSCH decoder function. -class hw_accelerator_pusch_dec_impl : public hw_accelerator_pusch_dec -{ -public: - /// Default constructor. - hw_accelerator_pusch_dec_impl() = default; - - // See hw_accelerator interface for the documentation. - void reserve_queue() override; - // See hw_accelerator interface for the documentation. - void free_queue() override; - // See hw_accelerator interface for the documentation. - bool enqueue_operation(span data, span soft_data = {}, unsigned cb_index = 0) override; - // See hw_accelerator interface for the documentation. - bool dequeue_operation(span data, span soft_data = {}, unsigned segment_index = 0) override; - // See hw_accelerator interface for the documentation. - void configure_operation(const hw_pusch_decoder_configuration& config, unsigned cb_index = 0) override; - // See hw_accelerator interface for the documentation. - void - read_operation_outputs(hw_pusch_decoder_outputs& out, unsigned cb_index = 0, unsigned absolute_cb_id = 0) override; - // See hw_accelerator interface for the documentation. - void free_harq_context_entry(unsigned absolute_cb_id) override; - // See hw_accelerator interface for the documentation. - bool is_external_harq_supported() const override; - -private: - /// Hardware-specific implementation of the reserve queue function. - virtual void hw_reserve_queue() = 0; - /// Hardware-specific implementation of the free queue function. - virtual void hw_free_queue() = 0; - /// Hardware-specific implementation of the enqueue_operation function. - virtual bool hw_enqueue(span data, span soft_data, unsigned cb_index) = 0; - /// Hardware-specific implementation of the dequeue_operation function. - virtual bool hw_dequeue(span data, span soft_data, unsigned segment_index) = 0; - /// Hardware-specific configuration function. - virtual void hw_config(const hw_pusch_decoder_configuration& config, unsigned cb_index) = 0; - /// Hardware-specific operation status outputs recovery function. - virtual void hw_read_outputs(hw_pusch_decoder_outputs& out, unsigned cb_index, unsigned absolute_cb_id) = 0; - /// Hardware-specific HARQ buffer context freeing function. - virtual void hw_free_harq_context(unsigned absolute_cb_id) = 0; - /// Hardware-specific external HARQ buffer checking function. - virtual bool is_hw_external_harq_supported() const = 0; -}; - -} // namespace hal -} // namespace srsran diff --git a/lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.cpp b/lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.cpp new file mode 100644 index 0000000000..6d82d82e06 --- /dev/null +++ b/lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.cpp @@ -0,0 +1,164 @@ +/* + * + * 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 "plugin_bbdev_pusch_dec_acc_factory.h" +#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec.h" +#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_factory.h" +#include + +using namespace srsran; +using namespace hal; + +namespace { + +/// Dynamic library handler deleter - closes the dynamic library upon destruction. +struct dynamic_library_deleter { + void operator()(void* handler) const + { + if (handler != nullptr) { + ::dlclose(handler); + } + } +}; + +using handler_ptr = std::shared_ptr; + +/// Wraps a PUSCH decoder hardware-accelerator interface with the dynamic library handle. +class hw_accelerator_pusch_dec_dynamic_wrapper : public hw_accelerator_pusch_dec +{ +public: + /// Constructs a wrapper from the dynamic library handler and an open PUSCH decoder hardware-accelerator interface. + explicit hw_accelerator_pusch_dec_dynamic_wrapper(handler_ptr handler_, + std::shared_ptr pusch_acc_) noexcept : + handler(std::move(handler_)), pusch_acc(std::move(pusch_acc_)) + { + } + + /// Default destructor - deletes the instance first then the dynamic library handler. + ~hw_accelerator_pusch_dec_dynamic_wrapper() + { + pusch_acc.reset(); + handler.reset(); + } + + bool enqueue_operation(span data, span aux_data = {}, unsigned cb_index = 0) override + { + return pusch_acc->enqueue_operation(data, aux_data, cb_index); + } + bool dequeue_operation(span data, span aux_data = {}, unsigned segment_index = 0) override + { + return pusch_acc->dequeue_operation(data, aux_data, segment_index); + } + void reserve_queue() override { return pusch_acc->reserve_queue(); } + void free_queue() override { return pusch_acc->free_queue(); } + void configure_operation(const hw_pusch_decoder_configuration& config, unsigned cb_index = 0) override + { + return pusch_acc->configure_operation(config, cb_index); + } + void + read_operation_outputs(hw_pusch_decoder_outputs& out, unsigned cb_index = 0, unsigned absolute_cb_id = 0) override + { + return pusch_acc->read_operation_outputs(out, cb_index, absolute_cb_id); + } + void free_harq_context_entry(unsigned absolute_cb_id) override + { + return pusch_acc->free_harq_context_entry(absolute_cb_id); + } + bool is_external_harq_supported() const override { return pusch_acc->is_external_harq_supported(); } + +private: + handler_ptr handler; + std::shared_ptr pusch_acc; +}; + +/// Wraps a bbdev-based PUSCH decoder hardware-accelerator factory and a dynamic library handler. +class bbdev_pusch_dec_acc_factory_dynamic_wrapper : public hw_accelerator_pusch_dec_factory +{ +public: + /// Constructs from handler and factory. + bbdev_pusch_dec_acc_factory_dynamic_wrapper(handler_ptr handle_, + std::unique_ptr factory_) : + handle(std::move(handle_)), factory(std::move(factory_)) + { + } + + /// Default destructor - deletes the factory first then the dynamic library handler. + ~bbdev_pusch_dec_acc_factory_dynamic_wrapper() + { + factory.reset(); + handle.reset(); + } + + // See interface for documentation. + std::unique_ptr create() override + { + // Create bbdev-based PUSCH decoder hardware-accelerator using the loaded factory. + std::unique_ptr pusch_dec_if = factory->create(); + if (pusch_dec_if == nullptr) { + report_error("Failed to create plugin bbdev_pusch_dec_acc_factory"); + } + + // Wrap the dynamic library handler and the bbdev-based PUSCH decoder hardware-accelerator instance. + return std::make_unique(handle, std::move(pusch_dec_if)); + } + +private: + handler_ptr handle; + std::unique_ptr factory; +}; + +} // namespace + +std::unique_ptr srsran::hal::create_plugin_bbdev_pusch_dec_acc_factory( + const bbdev_hwacc_pusch_dec_factory_configuration& accelerator_config, + std::string impl_name) +{ + char* err = nullptr; + std::string plugin_name = "libsrsran_bbdev_pusch_dec_acc_" + impl_name + ".so"; + + void* dl_handle = ::dlopen(plugin_name.c_str(), RTLD_NOW + RTLD_DEEPBIND + RTLD_GLOBAL); + if (dl_handle == nullptr) { + err = ::dlerror(); + if (err != nullptr) { + fmt::print("Failed to load bbdev_pusch_dec_acc plugin {}: {}\n", plugin_name, err); + } + return nullptr; + } + + // Create factory function prototype. + using create_factory_func = + std::unique_ptr(const bbdev_hwacc_pusch_dec_factory_configuration&); + + // Load symbol. + auto* create_factory = + reinterpret_cast(::dlsym(dl_handle, "create_dynamic_bbdev_pusch_dec_acc_factory")); + + // Handle an error loading the symbol. + if (create_factory == nullptr) { + err = ::dlerror(); + if (err != nullptr) { + fmt::print("Error loading symbol {}: {}\n", "create_dynamic_bbdev_pusch_dec_acc_factory", err); + } + return nullptr; + } + + // Create factory. + std::unique_ptr factory = (*create_factory)(accelerator_config); + + if (factory == nullptr) { + return nullptr; + } + + // Create shared pointer with deleter. + dynamic_library_deleter deleter; + handler_ptr handle(dl_handle, deleter); + + return std::make_unique(std::move(handle), std::move(factory)); +} diff --git a/lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.h b/lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.h new file mode 100644 index 0000000000..2b34a299b7 --- /dev/null +++ b/lib/hal/phy/upper/channel_processors/pusch/plugin_bbdev_pusch_dec_acc_factory.h @@ -0,0 +1,25 @@ +/* + * + * 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/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" +#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_factory.h" +#include + +namespace srsran { +namespace hal { + +std::unique_ptr +create_plugin_bbdev_pusch_dec_acc_factory(const bbdev_hwacc_pusch_dec_factory_configuration& accelerator_config, + std::string impl_name); + +} // namespace hal +} // namespace srsran diff --git a/lib/phy/upper/CMakeLists.txt b/lib/phy/upper/CMakeLists.txt index fc5e7cf420..caefff6f9d 100644 --- a/lib/phy/upper/CMakeLists.txt +++ b/lib/phy/upper/CMakeLists.txt @@ -29,8 +29,7 @@ target_link_libraries(srsran_uplink_processor srsran_channel_processors) add_library(srsran_upper_phy upper_phy_factories.cpp upper_phy_impl.cpp upper_phy_factories.cpp upper_phy_rx_symbol_handler_impl.cpp upper_phy_rx_results_notifier_wrapper.cpp upper_phy_error_handler_impl.cpp) -target_link_libraries(srsran_upper_phy - srsran_instrumentation +set(UPPER_PHY_LIBRARIES srsran_instrumentation srsran_downlink_processor srsran_uplink_processor srsran_phy_support @@ -38,6 +37,15 @@ target_link_libraries(srsran_upper_phy srsran_transform_precoding srsran_channel_equalizer) +# Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. +if (DPDK_FOUND) + set_source_files_properties(upper_phy_factories.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + list(APPEND UPPER_PHY_LIBRARIES hal_hwacc_pusch + hal_hwacc_pdsch + hal_bbdev_factory) +endif (DPDK_FOUND) +target_link_libraries(srsran_upper_phy ${UPPER_PHY_LIBRARIES}) + add_library(log_likelihood_ratio log_likelihood_ratio.cpp) target_link_libraries(log_likelihood_ratio srsvec) diff --git a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp index dd818f59fd..8f82f4f075 100644 --- a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp @@ -23,10 +23,13 @@ void pdsch_encoder_hw_impl::encode(span codeword, span transport_block, const configuration& config) { - // CB mode will be forced if TB mode is requested for a TB larger than the maximum supported size. - cb_mode = encoder->get_cb_mode(); - max_tb_size = encoder->get_max_tb_size(); - if (!cb_mode && transport_block.size_bytes() > max_tb_size) { + // CB mode will be forced if TB mode is requested for a TB requiring a larger buffer than the maximum supported size. + cb_mode = encoder->is_cb_mode_supported(); + max_buffer_size = encoder->get_max_supported_buff_size(); + unsigned max_required_buff_size = + std::max(static_cast(transport_block.size_bytes()), + static_cast(units::bits(codeword.size()).round_up_to_bytes().value())); + if (!cb_mode && max_required_buff_size > max_buffer_size) { cb_mode = true; } diff --git a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h index 2aaa3e751b..b5232381cd 100644 --- a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h @@ -74,8 +74,9 @@ class pdsch_encoder_hw_impl : public pdsch_encoder /// Defines if the PDSCH encoder operates in CB mode (true) or TB mode (false). bool cb_mode; - /// Defines the maximum supported TB size in bytes (CB mode will be forced for larger TBs). Only used in TB mode. - unsigned max_tb_size; + /// Defines the maximum supported buffer size in bytes (CB mode will be forced for TBs requiring larger sizes). Only + /// used in TB mode. + unsigned max_buffer_size; /// CRC calculator for transport-block checksum. sch_crc crc_set; diff --git a/lib/phy/upper/channel_processors/pusch/factories.cpp b/lib/phy/upper/channel_processors/pusch/factories.cpp index b1e67236a4..b1f3a552f6 100644 --- a/lib/phy/upper/channel_processors/pusch/factories.cpp +++ b/lib/phy/upper/channel_processors/pusch/factories.cpp @@ -107,20 +107,25 @@ class pusch_decoder_factory_generic : public pusch_decoder_factory /// HW-accelerated PUSCH decoder factory. class pusch_decoder_factory_hw : public pusch_decoder_factory { -private: - std::shared_ptr segmenter_factory; - std::shared_ptr crc_factory; - std::shared_ptr hw_decoder_factory; - public: explicit pusch_decoder_factory_hw(const pusch_decoder_factory_hw_configuration& config) : segmenter_factory(std::move(config.segmenter_factory)), crc_factory(std::move(config.crc_factory)), - hw_decoder_factory(std::move(config.hw_decoder_factory)) + executor(config.executor) { srsran_assert(segmenter_factory, "Invalid LDPC segmenter factory."); srsran_assert(crc_factory, "Invalid CRC factory."); - srsran_assert(hw_decoder_factory, "Invalid hardware accelerator factory."); + srsran_assert(config.hw_decoder_factory, "Invalid hardware accelerator factory."); + + // Creates a vector of hardware decoders. These are shared for all the PUSCH decoders. + std::vector> hw_decoders( + std::max(1U, config.nof_pusch_decoder_threads)); + for (std::unique_ptr& hw_decoder : hw_decoders) { + hw_decoder = config.hw_decoder_factory->create(); + } + + // Creates the hardware decoder pool. The pool is common among all the PUSCH decoders. + hw_decoder_pool = std::make_unique(std::move(hw_decoders)); } std::unique_ptr create() override @@ -130,8 +135,14 @@ class pusch_decoder_factory_hw : public pusch_decoder_factory crc_factory->create(crc_generator_poly::CRC24A), crc_factory->create(crc_generator_poly::CRC24B), }; - return std::make_unique(segmenter_factory->create(), crc, hw_decoder_factory->create()); + return std::make_unique(segmenter_factory->create(), crc, hw_decoder_pool, executor); } + +private: + std::shared_ptr segmenter_factory; + std::shared_ptr crc_factory; + std::shared_ptr hw_decoder_pool; + task_executor* executor; }; class pusch_demodulator_factory_generic : public pusch_demodulator_factory diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.cpp index 182f94c118..2fece7743f 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.cpp @@ -119,6 +119,25 @@ void pusch_decoder_hw_impl::on_new_softbits(span sof void pusch_decoder_hw_impl::on_end_softbits() { + // Create the asynchronous function. + auto asynch_func = [this]() { run_asynch_hw_decoder(); }; + + // Try to execute the asynchronous decoder. + bool success = false; + if (executor != nullptr) { + success = executor->execute(asynch_func); + } + + // Execute the decoder syncrhonously. + if (!success) { + asynch_func(); + } +} + +void pusch_decoder_hw_impl::run_asynch_hw_decoder() +{ + hal::hw_accelerator_pusch_dec& decoder = decoder_pool->get(); + unsigned modulation_order = get_bits_per_symbol(current_config.mod); srsran_assert(softbits_count % modulation_order == 0, "The number of soft bits (i.e., {}) must be multiple of the modulation order (i.e., {}).\n", @@ -126,7 +145,7 @@ void pusch_decoder_hw_impl::on_end_softbits() modulation_order); // Reserve a hardware-queue for the current decoding operation. - decoder->reserve_queue(); + decoder.reserve_queue(); segmenter_config segmentation_config; segmentation_config.base_graph = current_config.base_graph; @@ -164,14 +183,10 @@ void pusch_decoder_hw_impl::on_end_softbits() srsvec::zero(cb_crcs); } - // Initialize decoder status. - pusch_decoder_result stats = {}; - - stats.nof_codeblocks_total = nof_cbs; - stats.ldpc_decoder_stats.reset(); + // Decode the CBs. unsigned last_enqueued_cb_id = 0, last_dequeued_cb_id = 0, enq_tb_offset = 0, deq_tb_offset = 0; bool all_enqueued = false, all_dequeued = false; - bool external_harq = decoder->is_external_harq_supported(); + bool external_harq = decoder.is_external_harq_supported(); // Validate that all CBs have been succesfully enqueued and dequeued. while (!all_enqueued || !all_dequeued) { @@ -200,7 +215,8 @@ void pusch_decoder_hw_impl::on_end_softbits() absolute_cb_ids[cb_id] = softbuffer->get_absolute_codeblock_id(cb_id); // Set the decoding parameters of the CB as required by the hardware-accelerated PUSCH decoder. - set_hw_dec_configuration(nof_cbs, + set_hw_dec_configuration(decoder, + nof_cbs, cb_meta.cb_specific.rm_length, static_cast(cb_meta.tb_common.lifting_size), nof_new_bits, @@ -222,7 +238,7 @@ void pusch_decoder_hw_impl::on_end_softbits() span(reinterpret_cast(rm_buffer.data()), rm_buffer.size()); // Enqueue the hardware-accelerated PUSCH decoding operation. - enqueued = decoder->enqueue_operation(cb_llrs_i8, rm_buffer_i8, cb_id); + enqueued = decoder.enqueue_operation(cb_llrs_i8, rm_buffer_i8, cb_id); // Exit the enqueing loop in case the operation couldn't be enqueued. if (!enqueued) { break; @@ -290,7 +306,7 @@ void pusch_decoder_hw_impl::on_end_softbits() dequeued = false; while (!dequeued) { // Dequeue the hardware-accelerated PUSCH decoding operation (updates the softbuffer too). - dequeued = decoder->dequeue_operation(message.get_buffer(), codeblock_i8, cb_id); + dequeued = decoder.dequeue_operation(message.get_buffer(), codeblock_i8, cb_id); if (!dequeued) { if (num_dequeued > 0) { break; @@ -299,7 +315,7 @@ void pusch_decoder_hw_impl::on_end_softbits() ++num_dequeued; // Check the CB decoding operation success. - check_hw_results(stats, cb_crcs, cb_id, crc_type, message.first(nof_new_bits + crc_len)); + check_hw_results(cb_crcs, decoder, cb_id, crc_type, message.first(nof_new_bits + crc_len)); } } @@ -326,17 +342,17 @@ void pusch_decoder_hw_impl::on_end_softbits() } srsran_assert(deq_tb_offset == tb_and_crc_size, "All TB bits should be filled at this point."); - copy_tb_and_notify(stats, nof_cbs, cb_crcs); + copy_tb_and_notify(decoder, cb_crcs.first(nof_cbs)); } -void pusch_decoder_hw_impl::check_hw_results(pusch_decoder_result& stats, - span cb_crcs, - unsigned cb_id, - hal::hw_dec_cb_crc_type crc_type, - bit_buffer data) +void pusch_decoder_hw_impl::check_hw_results(span cb_crcs, + hal::hw_accelerator_pusch_dec& decoder, + unsigned int cb_id, + hal::hw_dec_cb_crc_type crc_type, + srsran::bit_buffer data) { hal::hw_pusch_decoder_outputs hw_out = {}; - decoder->read_operation_outputs(hw_out, cb_id, absolute_cb_ids[cb_id]); + decoder.read_operation_outputs(hw_out, cb_id, absolute_cb_ids[cb_id]); // CRC24B is always checked by the accelerator. if (crc_type != hal::hw_dec_cb_crc_type::CRC24B) { // CRC24A and CRC16 are not checked by the accelerator. @@ -348,20 +364,39 @@ void pusch_decoder_hw_impl::check_hw_results(pusch_decoder_result& stats, } cb_crcs[cb_id] = hw_out.CRC_pass; - stats.ldpc_decoder_stats.update(hw_out.nof_ldpc_iterations); + if (hw_out.CRC_pass) { + // If successful decoding, flag the CRC, record number of iterations and copy bits to the TB buffer. + cb_crcs[cb_id] = true; + cb_stats.push_blocking(hw_out.nof_ldpc_iterations); + } else { + cb_stats.push_blocking(current_config.nof_ldpc_iterations); + } } -void pusch_decoder_hw_impl::copy_tb_and_notify(pusch_decoder_result& stats, unsigned nof_cbs, span cb_crcs) +void pusch_decoder_hw_impl::copy_tb_and_notify(hal::hw_accelerator_pusch_dec& decoder, span cb_crcs) { - stats.tb_crc_ok = false; + // Initialize decoder status. + unsigned nof_cbs = cb_crcs.size(); + pusch_decoder_result stats; + stats.tb_crc_ok = false; + stats.nof_codeblocks_total = nof_cbs; + stats.ldpc_decoder_stats.reset(); + + // Calculate statistics. + std::optional cb_nof_iter = cb_stats.try_pop(); + while (cb_nof_iter.has_value()) { + stats.ldpc_decoder_stats.update(cb_nof_iter.value()); + cb_nof_iter = cb_stats.try_pop(); + } + if (nof_cbs == 1) { // When only one codeblock, the CRC of codeblock and transport block are the same. stats.tb_crc_ok = cb_crcs[0]; if (stats.tb_crc_ok) { srsvec::copy(transport_block, tmp_tb_bits.get_buffer().first(transport_block.size())); // Free the HARQ context entries. - for (unsigned cb_idx = 0, cb_idx_end = nof_cbs; cb_idx != cb_idx_end; ++cb_idx) { - decoder->free_harq_context_entry(absolute_cb_ids[cb_idx]); + for (unsigned cb_idx = 0, cb_idx_end = cb_crcs.size(); cb_idx != cb_idx_end; ++cb_idx) { + decoder.free_harq_context_entry(absolute_cb_ids[cb_idx]); } } } else if (std::all_of(cb_crcs.begin(), cb_crcs.end(), [](bool a) { return a; })) { @@ -372,8 +407,8 @@ void pusch_decoder_hw_impl::copy_tb_and_notify(pusch_decoder_result& stats, unsi if (crc_set.crc24A->calculate(tmp_tb_bits) == 0) { stats.tb_crc_ok = true; // Free the HARQ context entries. - for (unsigned cb_idx = 0, cb_idx_end = nof_cbs; cb_idx != cb_idx_end; ++cb_idx) { - decoder->free_harq_context_entry(absolute_cb_ids[cb_idx]); + for (unsigned cb_idx = 0, cb_idx_end = cb_crcs.size(); cb_idx != cb_idx_end; ++cb_idx) { + decoder.free_harq_context_entry(absolute_cb_ids[cb_idx]); } } else { // If the checksum is wrong, then at least one of the codeblocks is a false negative. Reset all of them. @@ -389,7 +424,7 @@ void pusch_decoder_hw_impl::copy_tb_and_notify(pusch_decoder_result& stats, unsi } // Free the hardware-queue utilized by completed decoding operation. - decoder->free_queue(); + decoder.free_queue(); // In case there are multiple codeblocks and at least one has a corrupted codeblock CRC, nothing to do. @@ -397,14 +432,15 @@ void pusch_decoder_hw_impl::copy_tb_and_notify(pusch_decoder_result& stats, unsi result_notifier->on_sch_data(stats); } -void pusch_decoder_hw_impl::set_hw_dec_configuration(unsigned nof_segments, - unsigned rm_length, - unsigned lifting_size, - unsigned nof_segment_bits, - unsigned nof_filler_bits, - unsigned crc_len, - hal::hw_dec_cb_crc_type crc_type, - unsigned cb_index) +void pusch_decoder_hw_impl::set_hw_dec_configuration(hal::hw_accelerator_pusch_dec& decoder, + unsigned nof_segments, + unsigned rm_length, + unsigned lifting_size, + unsigned nof_segment_bits, + unsigned nof_filler_bits, + unsigned crc_len, + hal::hw_dec_cb_crc_type crc_type, + unsigned cb_index) { hal::hw_pusch_decoder_configuration hw_cfg = {}; @@ -457,5 +493,5 @@ void pusch_decoder_hw_impl::set_hw_dec_configuration(unsigned nof hw_cfg.absolute_cb_id = absolute_cb_ids[cb_index]; // Set configuration in the HW accelerated decoder. - decoder->configure_operation(hw_cfg, cb_index); + decoder.configure_operation(hw_cfg, cb_index); } diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h index 60447f0a29..24e4458139 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h @@ -13,6 +13,7 @@ #pragma once +#include "srsran/adt/mutexed_mpsc_queue.h" #include "srsran/hal/hw_accelerator.h" #include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec.h" #include "srsran/phy/upper/channel_coding/crc_calculator.h" @@ -22,6 +23,8 @@ #include "srsran/phy/upper/codeblock_metadata.h" #include "srsran/phy/upper/unique_rx_buffer.h" #include "srsran/ran/pdsch/pdsch_constants.h" +#include "srsran/support/executors/task_executor.h" +#include "srsran/support/memory_pool/concurrent_thread_local_object_pool.h" namespace srsran { @@ -36,6 +39,9 @@ static constexpr unsigned LONG_CRC_LENGTH = 24; class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer { public: + /// Code block decoder pool type. + using hw_decoder_pool = concurrent_thread_local_object_pool; + /// CRC calculators used in shared channels. struct sch_crc { /// For short TB checksums. @@ -50,17 +56,22 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer /// /// Sets up the internal components, namely LDPC segmenter, all the CRC calculators and the hardware accelerator. /// - /// \param[in] seg Pointer to an LDPC segmenter object. - /// \param[in] crcs Structure with pointers to three CRC calculator objects, with generator polynomials of type \c - /// CRC16, \c CRC24A and \c CRC24B. - /// \param[in] hw Unique pointer to a hardware-accelerator. - pusch_decoder_hw_impl(std::unique_ptr seg, - sch_crc& c, - std::unique_ptr hw) : + /// \param[in] seg Pointer to an LDPC segmenter object. + /// \param[in] crcs Structure with pointers to three CRC calculator objects, with generator polynomials of + /// type \c CRC16, \c CRC24A and \c CRC24B. + /// \param[in] decoder_pool_ Hardware decoder pool. + /// \param[in] executor_ Optional asynchronous processing task executor. Set to \c nullptr for synchronous + /// operation. + pusch_decoder_hw_impl(std::unique_ptr seg, + sch_crc& c, + std::shared_ptr decoder_pool_, + task_executor* executor_) : segmenter(std::move(seg)), crc_set({std::move(c.crc16), std::move(c.crc24A), std::move(c.crc24B)}), - decoder(std::move(hw)), - softbits_buffer(pdsch_constants::CODEWORD_MAX_SIZE.value()) + decoder_pool(std::move(decoder_pool_)), + executor(executor_), + softbits_buffer(pdsch_constants::CODEWORD_MAX_SIZE.value()), + cb_stats(MAX_NOF_SEGMENTS) { srsran_assert(segmenter, "Invalid LDPC segmenter factory."); srsran_assert(crc_set.crc16, "Invalid CRC16 calculator."); @@ -72,7 +83,7 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer "Not a CRC generator of type CRC24A."); srsran_assert(crc_set.crc24B->get_generator_poly() == crc_generator_poly::CRC24B, "Not a CRC generator of type CRC24B."); - srsran_assert(decoder, "Invalid hardware-accelerated PUSCH decoder."); + srsran_assert(decoder_pool, "Invalid hardware-accelerated PUSCH decoder pool."); absolute_cb_ids.resize(MAX_NOF_SEGMENTS); } @@ -96,8 +107,10 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer /// Only the CRC calculator with generator polynomial crc_generator_poly::CRC24A, used for long transport blocks, is /// needed. Indeed, if a transport block is short enough not to be segmented, the CRC is verified by the decoder. sch_crc crc_set; - /// Pointer to a hardware-accelerated PUSCH decoder. - std::unique_ptr decoder; + /// Hardware decoder pool. It provides a hardware decoder for each processing thread. + std::shared_ptr decoder_pool; + /// Asynchronous task executor. Set it to \c nullptr for disabling the asynchronous operation. + task_executor* executor = nullptr; /// Soft bit buffer. std::vector softbits_buffer; /// Counts the number of soft bits in the buffer. @@ -116,6 +129,8 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer static_vector codeblock_llrs = {}; /// Temporary buffer to store the unpacked transport block (and, if applicable, its CRC). static_bit_buffer tmp_tb_bits; + /// Enqueues code block decoder statistics. + concurrent_queue cb_stats; // See interface for the documentation. span get_next_block_view(unsigned block_size) override; @@ -126,42 +141,50 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer // See interface for the documentation. void on_end_softbits() override; - /// \brief Checks the results of the decoding operation. - /// \param[in] stats Structure to store the PUSCH decoder results. - /// \param[in] cb_crcs Set of CRC flags. - /// \param[in] cb_index Index of the CB (within the TB). - /// \param[in] crc_type Type of the CB CRC. - /// \param[in] data Decoded data. + /// \brief Processes + void run_asynch_hw_decoder(); + + /// \brief Checks the results of a decoding operation for a certain code block. + /// + /// It combines the decoder statistics \c stats and updates the code block CRC flag. + /// + /// \param[in,out] cb_crcs Set of CRC flags. + /// \param[in,out] decoder Hardware decoder used to process the codeblocks. + /// \param[in] cb_index Index of the CB (within the TB). + /// \param[in] crc_type Type of the CB CRC. + /// \param[in] data Decoded data. /// \return Results of the decoding operation (CRC and number of LDPC decoder iterations). - void check_hw_results(pusch_decoder_result& stats, - span cb_crcs, - unsigned cb_id, - hal::hw_dec_cb_crc_type crc_type, - bit_buffer data); + void check_hw_results(span cb_crcs, + hal::hw_accelerator_pusch_dec& decoder, + unsigned cb_id, + hal::hw_dec_cb_crc_type crc_type, + bit_buffer data); /// \brief Copies the decoded bits and notifies the end of the operation. - /// \param[in] stats Structure to store the PUSCH decoder results. - /// \param[in] cb_crcs Set of CRC flags. - void copy_tb_and_notify(pusch_decoder_result& stats, unsigned nof_cbs, span cb_crcs); + /// \param[in,out] decoder Hardware decoder used to process the codeblocks. + /// \param[in] cb_crcs Set of CRC flags. + void copy_tb_and_notify(hal::hw_accelerator_pusch_dec& decoder, span cb_crcs); /// \brief Sets the segmentation and decoding parameters required by the hardware-accelerated PUSCH decoder function. - /// \param[in] cfg PUSCH configuration parameters. - /// \param[in] nof_segments Number of segments in the transport block. - /// \param[in] rm_length Length of the rate-matched codeblock in bits. - /// \param[in] lifting_size Length of the circular buffer in bits, as described in TS38.212 Section 5.4.2.1. - /// \param[in] nof_segment_bits Number of information bits that is assigned to a segment. - /// \param[in] nof_filler_bits Number of filler bits in a segment. - /// \param[in] crc_len Length of the CB CRC in bits, - /// \param[in] crc_type Type of the CB CRC. - /// \param[in] cb_index Index of the CB (within the TB). - void set_hw_dec_configuration(unsigned nof_segments, - unsigned rm_length, - unsigned lifting_size, - unsigned nof_segment_bits, - unsigned nof_filler_bits, - unsigned crc_len, - hal::hw_dec_cb_crc_type crc_type, - unsigned cb_index); + /// \param[in,out] decoder Selected hardware decoder to configure. + /// \param[in] cfg PUSCH configuration parameters. + /// \param[in] nof_segments Number of segments in the transport block. + /// \param[in] rm_length Length of the rate-matched codeblock in bits. + /// \param[in] lifting_size Length of the circular buffer in bits, as described in TS38.212 Section 5.4.2.1. + /// \param[in] nof_segment_bits Number of information bits that is assigned to a segment. + /// \param[in] nof_filler_bits Number of filler bits in a segment. + /// \param[in] crc_len Length of the CB CRC in bits, + /// \param[in] crc_type Type of the CB CRC. + /// \param[in] cb_index Index of the CB (within the TB). + void set_hw_dec_configuration(hal::hw_accelerator_pusch_dec& decoder, + unsigned nof_segments, + unsigned rm_length, + unsigned lifting_size, + unsigned nof_segment_bits, + unsigned nof_filler_bits, + unsigned crc_len, + hal::hw_dec_cb_crc_type crc_type, + unsigned cb_index); }; } // namespace srsran diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 6dd57b19bd..06b676800d 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -394,21 +394,40 @@ static std::shared_ptr create_ul_processor_factory(con create_crc_calculator_factory_sw(config.crc_calculator_type); report_fatal_error_if_not(crc_calc_factory, "Invalid CRC calculator factory of type {}.", config.crc_calculator_type); - pusch_decoder_factory_sw_configuration decoder_config; - decoder_config.crc_factory = crc_calc_factory; - decoder_config.decoder_factory = create_ldpc_decoder_factory_sw(config.ldpc_decoder_type); - report_fatal_error_if_not( - decoder_config.decoder_factory, "Invalid LDPC decoder factory of type {}.", config.crc_calculator_type); - decoder_config.dematcher_factory = create_ldpc_rate_dematcher_factory_sw(config.ldpc_rate_dematcher_type); - report_fatal_error_if_not(decoder_config.dematcher_factory, - "Invalid LDPC Rate Dematcher factory of type {}.", - config.ldpc_rate_dematcher_type); - decoder_config.segmenter_factory = create_ldpc_segmenter_rx_factory_sw(); - report_fatal_error_if_not(decoder_config.segmenter_factory, "Invalid LDPC Rx segmenter factory."); - decoder_config.nof_pusch_decoder_threads = config.nof_pusch_decoder_threads; - decoder_config.executor = config.pusch_decoder_executor; - decoder_config.nof_prb = config.ul_bw_rb; - decoder_config.nof_layers = 1; + // Check if a hardware-accelerated PUSCH processor is requested. + pusch_processor_factory_sw_configuration pusch_config; + if (!config.hal_config.hwacc_pusch_processor) { + pusch_decoder_factory_sw_configuration decoder_config; + decoder_config.crc_factory = crc_calc_factory; + decoder_config.decoder_factory = create_ldpc_decoder_factory_sw(config.ldpc_decoder_type); + report_fatal_error_if_not( + decoder_config.decoder_factory, "Invalid LDPC decoder factory of type {}.", config.crc_calculator_type); + decoder_config.dematcher_factory = create_ldpc_rate_dematcher_factory_sw(config.ldpc_rate_dematcher_type); + report_fatal_error_if_not(decoder_config.dematcher_factory, + "Invalid LDPC Rate Dematcher factory of type {}.", + config.ldpc_rate_dematcher_type); + decoder_config.segmenter_factory = create_ldpc_segmenter_rx_factory_sw(); + report_fatal_error_if_not(decoder_config.segmenter_factory, "Invalid LDPC Rx segmenter factory."); + decoder_config.nof_pusch_decoder_threads = config.nof_pusch_decoder_threads; + decoder_config.executor = config.pusch_decoder_executor; + decoder_config.nof_prb = config.ul_bw_rb; + decoder_config.nof_layers = 1; + pusch_config.decoder_factory = create_pusch_decoder_factory_sw(decoder_config); + } else { + pusch_decoder_factory_hw_configuration decoder_config; + decoder_config.segmenter_factory = create_ldpc_segmenter_rx_factory_sw(); + report_fatal_error_if_not(decoder_config.segmenter_factory, "Invalid LDPC Rx segmenter factory."); + decoder_config.crc_factory = crc_calc_factory; + decoder_config.hw_decoder_factory = nullptr; + decoder_config.nof_pusch_decoder_threads = config.nof_pusch_decoder_threads; +#ifdef HWACC_PUSCH_ENABLED + decoder_config.hw_decoder_factory = + hal::create_bbdev_pusch_dec_acc_factory(config.hal_config.hwacc_pusch_dec_cfg, "srs"); +#endif // HWACC_PUSCH_ENABLED + decoder_config.executor = config.pusch_decoder_executor; + report_fatal_error_if_not(decoder_config.hw_decoder_factory, "Invalid hardware-accelerated PUSCH decoder factory."); + pusch_config.decoder_factory = create_pusch_decoder_factory_hw(decoder_config); + } std::shared_ptr short_block_det_factory = create_short_block_detector_factory_sw(); report_fatal_error_if_not(short_block_det_factory, "Invalid short block detector factory."); @@ -428,7 +447,7 @@ static std::shared_ptr create_ul_processor_factory(con bool enable_eq_sinr = (config.pusch_sinr_calc_method == channel_state_information::sinr_type::post_equalization) || (config.log_level == srslog::basic_levels::debug); - pusch_processor_factory_sw_configuration pusch_config; + // Add the remaining PUSCH processor configuration values. pusch_config.estimator_factory = create_dmrs_pusch_estimator_factory_sw(prg_factory, low_papr_sequence_gen_factory, ch_estimator_factory); pusch_config.demodulator_factory = create_pusch_demodulator_factory_sw(equalizer_factory, @@ -446,12 +465,10 @@ static std::shared_ptr create_ul_processor_factory(con pusch_config.max_nof_concurrent_threads = config.max_ul_thread_concurrency; // :TODO: check these values in the future. Extract them to more public config. - pusch_config.ch_estimate_dimensions.nof_symbols = MAX_NSYMB_PER_SLOT; - pusch_config.ch_estimate_dimensions.nof_tx_layers = 1; - pusch_config.ch_estimate_dimensions.nof_prb = config.ul_bw_rb; - pusch_config.ch_estimate_dimensions.nof_rx_ports = config.nof_rx_ports; - pusch_config.decoder_factory = create_pusch_decoder_factory_sw(decoder_config); - + pusch_config.ch_estimate_dimensions.nof_symbols = MAX_NSYMB_PER_SLOT; + pusch_config.ch_estimate_dimensions.nof_tx_layers = 1; + pusch_config.ch_estimate_dimensions.nof_prb = config.ul_bw_rb; + pusch_config.ch_estimate_dimensions.nof_rx_ports = config.nof_rx_ports; std::shared_ptr pusch_factory = create_pusch_processor_factory_sw(pusch_config); report_fatal_error_if_not(pusch_factory, "Invalid PUSCH processor factory."); @@ -822,8 +839,14 @@ std::shared_ptr srsran::create_downlink_processor_factory_hw(const downlink_processor_factory_hw_config& config) { // Create channel coding factories - CRC - std::shared_ptr crc_calc_factory = config.crc_calc_factory; - report_fatal_error_if_not(crc_calc_factory, "Invalid CRC calculator factory."); + std::shared_ptr crc_calc_factory = + create_crc_calculator_factory_sw(config.crc_calculator_type); + report_fatal_error_if_not(crc_calc_factory, "Invalid CRC calculator factory of type {}.", config.crc_calculator_type); + + // Create channel coding factories - LDPC + std::shared_ptr ldpc_seg_tx_factory = + create_ldpc_segmenter_tx_factory_sw(crc_calc_factory); + report_fatal_error_if_not(ldpc_seg_tx_factory, "Invalid LDPC segmenter factory."); // Create channel coding factories - Polar std::shared_ptr polar_factory = create_polar_factory_sw(); @@ -847,8 +870,16 @@ srsran::create_downlink_processor_factory_hw(const downlink_processor_factory_hw create_pdcch_encoder_factory_sw(crc_calc_factory, polar_factory); report_fatal_error_if_not(pdcch_enc_factory, "Invalid PDCCH encoder factory."); - std::shared_ptr pdsch_enc_factory = config.pdsch_enc_factory; - report_fatal_error_if_not(pdsch_enc_factory, "Invalid PDSCH encoder factory."); + // Create a hardware-accelerated PDSCH encoder factory. + pdsch_encoder_factory_hw_configuration encoder_config; + encoder_config.crc_factory = crc_calc_factory; + encoder_config.segmenter_factory = ldpc_seg_tx_factory; +#ifdef HWACC_PDSCH_ENABLED + encoder_config.hw_encoder_factory = hal::create_bbdev_pdsch_enc_acc_factory(config.hwacc_pdsch_enc_cfg, "srs"); +#endif // HWACC_PDSCH_ENABLED + report_fatal_error_if_not(encoder_config.hw_encoder_factory, "Invalid hardware-accelerated PDSCH encoder factory."); + std::shared_ptr pdsch_enc_factory = create_pdsch_encoder_factory_hw(encoder_config); + report_fatal_error_if_not(pdsch_enc_factory, "Invalid hardware-accelerated PDSCH encoder factory."); // Create channel processors modulation factories - PBCH std::shared_ptr pbch_mod_factory = create_pbch_modulator_factory_sw(mod_factory, prg_factory); @@ -891,6 +922,7 @@ srsran::create_downlink_processor_factory_hw(const downlink_processor_factory_hw report_fatal_error_if_not(pdcch_proc_factory, "Invalid PDCCH processor factory."); // Create channel processors - PDSCH + // Hardware-acceleration currently supports 'generic' PDSCH processor types only. std::shared_ptr pdsch_proc_factory = create_pdsch_processor_factory_sw(pdsch_enc_factory, pdsch_mod_factory, dmrs_pdsch_proc_factory); report_fatal_error_if_not(pdsch_proc_factory, "Invalid PDSCH processor factory."); @@ -910,6 +942,27 @@ srsran::create_downlink_processor_factory_hw(const downlink_processor_factory_hw create_nzp_csi_rs_generator_factory_sw(prg_factory); report_fatal_error_if_not(nzp_csi_rs_factory, "Invalid NZP-CSI-RS generator factory."); + // Wrap the downlink processor dependencies with pools to allow concurrent execution. + if (config.nof_concurrent_threads > 1) { + // If the PDSCH instance is concurrent, the number of instances is given by the PDSCH processor configuration. + unsigned max_nof_simultaneous_pdsch = config.nof_concurrent_threads; + + pdcch_proc_factory = + create_pdcch_processor_pool_factory(std::move(pdcch_proc_factory), config.nof_concurrent_threads); + report_fatal_error_if_not(pdcch_proc_factory, "Invalid PDCCH processor pool factory."); + + // The hardware-accelerated PDSCH processor pool needs to be locked. + pdsch_proc_factory = create_pdsch_processor_pool(std::move(pdsch_proc_factory), max_nof_simultaneous_pdsch); + report_fatal_error_if_not(pdsch_proc_factory, "Invalid PDSCH processor pool factory."); + + ssb_proc_factory = create_ssb_processor_pool_factory(std::move(ssb_proc_factory), config.nof_concurrent_threads); + report_fatal_error_if_not(ssb_proc_factory, "Invalid SSB processor pool factory."); + + nzp_csi_rs_factory = + create_nzp_csi_rs_generator_pool_factory(std::move(nzp_csi_rs_factory), config.nof_concurrent_threads); + report_fatal_error_if_not(nzp_csi_rs_factory, "Invalid NZP-CSI-RS generator pool factory."); + } + return std::make_shared( pdcch_proc_factory, pdsch_proc_factory, ssb_proc_factory, nzp_csi_rs_factory); } diff --git a/tests/benchmarks/phy/upper/channel_processors/pdsch_encoder_hwacc_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pdsch_encoder_hwacc_benchmark.cpp index 51b6bf1b46..09ecc0864a 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pdsch_encoder_hwacc_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pdsch_encoder_hwacc_benchmark.cpp @@ -188,6 +188,13 @@ static std::shared_ptr create_hw_accelera TESTASSERT(dpdk_interface, "Failed to open DPDK EAL with arguments."); } + // Create a bbdev accelerator factory. + static std::unique_ptr bbdev_acc_factory = nullptr; + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + TESTASSERT(bbdev_acc_factory, "Failed to create the bbdev accelerator factory."); + } + // Intefacing to the bbdev-based hardware-accelerator. dpdk::bbdev_acc_configuration bbdev_config; bbdev_config.id = 0; @@ -195,11 +202,11 @@ static std::shared_ptr create_hw_accelera bbdev_config.nof_ldpc_dec_lcores = 0; bbdev_config.nof_fft_lcores = 0; bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); TESTASSERT(bbdev_accelerator); - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pdsch_enc_configuration hw_encoder_config; + // Set the PDSCH encoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hw_encoder_config; hw_encoder_config.acc_type = "acc100"; hw_encoder_config.bbdev_accelerator = bbdev_accelerator; hw_encoder_config.cb_mode = cb_mode; @@ -207,7 +214,7 @@ static std::shared_ptr create_hw_accelera hw_encoder_config.dedicated_queue = dedicated_queue; // ACC100 hardware-accelerator implementation. - return create_hw_accelerator_pdsch_enc_factory(hw_encoder_config); + return srsran::hal::create_bbdev_pdsch_enc_acc_factory(hw_encoder_config, "srs"); #else // DPDK_FOUND return nullptr; #endif // DPDK_FOUND diff --git a/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp index 2d4ef21485..89f5da3c16 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp @@ -491,6 +491,13 @@ create_sw_pdsch_encoder_factory(std::shared_ptr crc_calc static std::shared_ptr create_hw_accelerator_pdsch_enc_factory() { #ifdef HWACC_PDSCH_ENABLED + // Create a bbdev accelerator factory. + static std::unique_ptr bbdev_acc_factory = nullptr; + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + TESTASSERT(bbdev_acc_factory, "Failed to create the bbdev accelerator factory."); + } + // Intefacing to the bbdev-based hardware-accelerator. srslog::basic_logger& logger = srslog::fetch_basic_logger("HWACC", false); logger.set_level(hal_log_level); @@ -500,11 +507,11 @@ static std::shared_ptr create_hw_accelera bbdev_config.nof_ldpc_dec_lcores = 0; bbdev_config.nof_fft_lcores = 0; bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); TESTASSERT(bbdev_accelerator); - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pdsch_enc_configuration hw_encoder_config; + // Set the PDSCH encoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hw_encoder_config; hw_encoder_config.acc_type = "acc100"; hw_encoder_config.bbdev_accelerator = bbdev_accelerator; hw_encoder_config.cb_mode = cb_mode; @@ -512,7 +519,7 @@ static std::shared_ptr create_hw_accelera hw_encoder_config.dedicated_queue = dedicated_queue; // ACC100 hardware-accelerator implementation. - return create_hw_accelerator_pdsch_enc_factory(hw_encoder_config); + return srsran::hal::create_bbdev_pdsch_enc_acc_factory(hw_encoder_config, "srs"); #else // HWACC_PDSCH_ENABLED return nullptr; #endif // HWACC_PDSCH_ENABLED @@ -754,13 +761,18 @@ int main(int argc, char** argv) // Inform of the benchmark configuration. if (benchmark_mode != benchmark_modes::silent) { + std::string hwacc_verbose = ""; + if (ldpc_encoder_type == "acc100") { + hwacc_verbose = fmt::format(" ({} VFs)", nof_threads); + } fmt::print("Launching benchmark for {} threads, {} times per thread, and {} repetitions. Using {} profile, and {} " - "LDPC encoder.\n", + "LDPC encoder{}.\n", nof_threads, batch_size_per_thread, nof_repetitions, selected_profile_name, - ldpc_encoder_type); + ldpc_encoder_type, + hwacc_verbose); } benchmarker perf_meas("PDSCH processor", nof_repetitions); diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp index 87718220ff..8baedf76d8 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp @@ -205,14 +205,21 @@ static std::shared_ptr create_hw_accelera TESTASSERT(dpdk_interface, "Failed to open DPDK EAL with arguments."); } + // Create a bbdev accelerator factory. + static std::unique_ptr bbdev_acc_factory = nullptr; + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + TESTASSERT(bbdev_acc_factory, "Failed to create the bbdev accelerator factory."); + } + // Intefacing to the bbdev-based hardware-accelerator. dpdk::bbdev_acc_configuration bbdev_config; bbdev_config.id = 0; bbdev_config.nof_ldpc_enc_lcores = 0; - bbdev_config.nof_ldpc_dec_lcores = 1; + bbdev_config.nof_ldpc_dec_lcores = dpdk::MAX_NOF_BBDEV_VF_INSTANCES; bbdev_config.nof_fft_lcores = 0; bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); TESTASSERT(bbdev_accelerator); // Interfacing to a shared external HARQ buffer context repository. @@ -222,8 +229,8 @@ static std::shared_ptr create_hw_accelera hal::create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, test_harq); TESTASSERT(harq_buffer_context); - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pusch_dec_configuration hw_decoder_config; + // Set the PUSCH decoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pusch_dec_factory_configuration hw_decoder_config; hw_decoder_config.acc_type = "acc100"; hw_decoder_config.bbdev_accelerator = bbdev_accelerator; hw_decoder_config.ext_softbuffer = ext_softbuffer; @@ -231,7 +238,7 @@ static std::shared_ptr create_hw_accelera hw_decoder_config.dedicated_queue = dedicated_queue; // ACC100 hardware-accelerator implementation. - return create_hw_accelerator_pusch_dec_factory(hw_decoder_config); + return srsran::hal::create_bbdev_pusch_dec_acc_factory(hw_decoder_config, "srs"); #else // DPDK_FOUND return nullptr; #endif // DPDK_FOUND @@ -253,6 +260,7 @@ static std::shared_ptr create_acc100_pusch_decoder_factor decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; decoder_hw_factory_config.crc_factory = crc_calculator_factory; decoder_hw_factory_config.hw_decoder_factory = hw_decoder_factory; + decoder_hw_factory_config.executor = nullptr; return create_pusch_decoder_factory_hw(decoder_hw_factory_config); } diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp index 379a67d7aa..c915b72cc8 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp @@ -431,16 +431,28 @@ create_sw_pusch_decoder_factory(std::shared_ptr crc_calc static std::shared_ptr create_hw_accelerator_pusch_dec_factory() { #ifdef HWACC_PUSCH_ENABLED + // Create a bbdev accelerator factory. + static std::unique_ptr bbdev_acc_factory = nullptr; + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + TESTASSERT(bbdev_acc_factory, "Failed to create the bbdev accelerator factory."); + } + + TESTASSERT(nof_threads + nof_pusch_decoder_threads + 1 <= dpdk::MAX_NOF_BBDEV_VF_INSTANCES, + "Insufficient hardware-accelerated LDPC decoder VFs: requested {} but only {} are available.", + nof_threads + nof_pusch_decoder_threads + 1, + dpdk::MAX_NOF_BBDEV_VF_INSTANCES); + // Intefacing to the bbdev-based hardware-accelerator. srslog::basic_logger& logger = srslog::fetch_basic_logger("HWACC", false); logger.set_level(hal_log_level); dpdk::bbdev_acc_configuration bbdev_config; bbdev_config.id = 0; bbdev_config.nof_ldpc_enc_lcores = 0; - bbdev_config.nof_ldpc_dec_lcores = nof_threads; + bbdev_config.nof_ldpc_dec_lcores = nof_threads + nof_pusch_decoder_threads + 1; bbdev_config.nof_fft_lcores = 0; bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); TESTASSERT(bbdev_accelerator); // Interfacing to a shared external HARQ buffer context repository. @@ -450,8 +462,8 @@ static std::shared_ptr create_hw_accelera hal::create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, false); TESTASSERT(harq_buffer_context); - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pusch_dec_configuration hw_decoder_config; + // Set the PUSCH decoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pusch_dec_factory_configuration hw_decoder_config; hw_decoder_config.acc_type = "acc100"; hw_decoder_config.bbdev_accelerator = bbdev_accelerator; hw_decoder_config.ext_softbuffer = ext_softbuffer; @@ -459,7 +471,7 @@ static std::shared_ptr create_hw_accelera hw_decoder_config.dedicated_queue = dedicated_queue; // ACC100 hardware-accelerator implementation. - return create_hw_accelerator_pusch_dec_factory(hw_decoder_config); + return srsran::hal::create_bbdev_pusch_dec_acc_factory(hw_decoder_config, "srs"); #else // HWACC_PUSCH_ENABLED return nullptr; #endif // HWACC_PUSCH_ENABLED @@ -476,9 +488,11 @@ create_acc100_pusch_decoder_factory(std::shared_ptr crc_ // Set the hardware-accelerated PUSCH decoder configuration. pusch_decoder_factory_hw_configuration decoder_hw_factory_config; - decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; - decoder_hw_factory_config.crc_factory = crc_calculator_factory; - decoder_hw_factory_config.hw_decoder_factory = hw_decoder_factory; + decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; + decoder_hw_factory_config.crc_factory = crc_calculator_factory; + decoder_hw_factory_config.hw_decoder_factory = hw_decoder_factory; + decoder_hw_factory_config.executor = executor.get(); + decoder_hw_factory_config.nof_pusch_decoder_threads = nof_threads + nof_pusch_decoder_threads + 1; return create_pusch_decoder_factory_hw(decoder_hw_factory_config); } @@ -558,7 +572,7 @@ static pusch_processor_factory& get_pusch_processor_factory() // Create worker pool and exectuors for concurrent PUSCH processor implementations. // Note that currently hardware-acceleration is limited to "generic" processor types. - if (nof_pusch_decoder_threads != 0 && ldpc_decoder_type != "acc100" && rate_dematcher_type != "acc100") { + if (nof_pusch_decoder_threads != 0) { worker_pool = std::make_unique>( "decoder", nof_pusch_decoder_threads, 1024); executor = std::make_unique>(*worker_pool); @@ -730,14 +744,19 @@ int main(int argc, char** argv) // Inform of the benchmark configuration. if (benchmark_mode != benchmark_modes::silent) { + std::string hwacc_verbose = ""; + if (ldpc_decoder_type == "acc100") { + hwacc_verbose = fmt::format(" ({} VFs)", nof_threads + nof_pusch_decoder_threads + 1); + } fmt::print("Launching benchmark for {} threads, {} times per thread, and {} repetitions. Using {} profile, {} LDPC " - "decoder, and {} rate dematcher.\n", + "decoder, and {} rate dematcher{}.\n", nof_threads, batch_size_per_thread, nof_repetitions, selected_profile_name, ldpc_decoder_type, - rate_dematcher_type); + rate_dematcher_type, + hwacc_verbose); } benchmarker perf_meas("PUSCH processor", nof_repetitions); diff --git a/tests/integrationtests/phy/upper/channel_processors/CMakeLists.txt b/tests/integrationtests/phy/upper/channel_processors/CMakeLists.txt index f53d0a2e28..3b5a34007a 100644 --- a/tests/integrationtests/phy/upper/channel_processors/CMakeLists.txt +++ b/tests/integrationtests/phy/upper/channel_processors/CMakeLists.txt @@ -12,14 +12,21 @@ add_executable(pxsch_bler_test pxsch_bler_test.cpp pxsch_bler_test_channel_emulator.cpp pxsch_bler_test_factories.cpp) -target_link_libraries(pxsch_bler_test - srsran_ran +set(PXSCH_BLER_TEST_LIBRARIES srsran_ran srsran_upper_phy srsran_upper_phy_support srsran_channel_precoder srslog - srsvec -) + srsvec) + +if (ENABLE_PDSCH_HWACC AND ENABLE_PUSCH_HWACC) + set_source_files_properties(pxsch_bler_test.cpp pxsch_bler_test_factories.cpp PROPERTIES COMPILE_DEFINITIONS "HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + list(APPEND PXSCH_BLER_TEST_LIBRARIES hal_hwacc_pusch + hal_hwacc_pdsch + hal_bbdev_factory) +endif (ENABLE_PDSCH_HWACC AND ENABLE_PUSCH_HWACC) + +target_link_libraries(pxsch_bler_test ${PXSCH_BLER_TEST_LIBRARIES}) add_test(pxsch_bler_test pxsch_bler_test -R 10) add_executable(pxsch_chain_test pxsch_chain_test.cpp) diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp index 563e13dffd..6f2d0cb1fc 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp @@ -59,6 +59,8 @@ static unsigned bwp_size_rb = 273; static pusch_mcs_table mcs_table = pusch_mcs_table::qam64; static sch_mcs_index mcs_index = 20; static bool enable_dc_position = false; +static std::string pxsch_type = "auto"; +static std::string eal_arguments = "pxsch_bler_test"; namespace { @@ -79,6 +81,39 @@ const char* to_string(pusch_mcs_table table) return "invalid"; } +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) +// Separates EAL and non-EAL arguments. +// The function assumes that 'eal_arg' flags the start of the EAL arguments and that no more non-EAL arguments follow. +static std::string capture_eal_args(int* argc, char*** argv) +{ + // Searchs for the EAL args (if any), flagged by 'eal_args', while removing all the rest (except argv[0]). + bool eal_found = false; + char** mod_argv = *argv; + std::string eal_argv = {mod_argv[0]}; + int opt_ind = *argc; + for (int j = 1; j < opt_ind; ++j) { + // Search for the 'eal_args' flag (if any). + if (!eal_found) { + if (strcmp(mod_argv[j], "eal_args") == 0) { + // 'eal_args' flag found. + eal_found = true; + // Remove all main app arguments starting from that point, while copying them to the EAL argument string. + mod_argv[j] = NULL; + for (int k = j + 1; k < opt_ind; ++k) { + eal_argv += " "; + eal_argv += mod_argv[k]; + mod_argv[k] = NULL; + } + *argc = j; + } + } + } + *argv = mod_argv; + + return eal_argv; +} +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED + std::optional to_mcs_table(const char* str) { for (unsigned table_idx = 0; table_idx != 5; ++table_idx) { @@ -195,12 +230,12 @@ class pxsch_bler_test // Create PDSCH processor factory. std::shared_ptr pdsch_proc_factory = - create_sw_pdsch_processor_factory(*executor, max_nof_threads + 1); + create_sw_pdsch_processor_factory(*executor, max_nof_threads + 1, eal_arguments, pxsch_type); report_fatal_error_if_not(pdsch_proc_factory, "Failted to create PDSCH processor factory."); // Create PUSCH processor factory. - std::shared_ptr pusch_proc_factory = - create_sw_pusch_processor_factory(*executor, max_nof_threads + 1, nof_ldpc_iterations, use_early_stop); + std::shared_ptr pusch_proc_factory = create_sw_pusch_processor_factory( + *executor, max_nof_threads + 1, nof_ldpc_iterations, use_early_stop, pxsch_type); report_fatal_error_if_not(pusch_proc_factory, "Failted to create PUSCH processor factory."); // Create resource grid factory. @@ -376,6 +411,7 @@ class pxsch_bler_test ++pdsch_config.slot; ++pusch_config.slot; + // Set following line to 1 for printing partial results. if (show_stats && (n % 100 == 0)) { // Calculate resultant metrics. double crc_bler = static_cast(crc_error_count) / static_cast(count); @@ -387,7 +423,8 @@ class pxsch_bler_test "BLER={:.10f}/{:.10f}; " "SINR={{{:+.2f} {:+.2f} {:+.2f}}}; " "EVM={{{:.3f} {:.3f} {:.3f}}}; " - "TA={{{:.2f} {:.2f} {:.2f}}}us\r", + "TA={{{:.2f} {:.2f} {:.2f}}}us; " + "pxsch={}\r", static_cast(n) / static_cast(nof_repetitions) * 100.0, min_iterations, max_iterations, @@ -403,7 +440,8 @@ class pxsch_bler_test evm_stats.get_mean(), ta_stats_us.get_min(), ta_stats_us.get_max(), - ta_stats_us.get_mean()); + ta_stats_us.get_mean(), + pxsch_type); } } @@ -417,7 +455,8 @@ class pxsch_bler_test "BLER={:.10f}/{:.10f}; " "SINR={{{:+.2f} {:+.2f} {:+.2f}}}; " "EVM={{{:.3f} {:.3f} {:.3f}}}; " - "TA={{{:.2f} {:.2f} {:.2f}}}us;\n", + "TA={{{:.2f} {:.2f} {:.2f}}}us;" + "pxsch={}\n", min_iterations, max_iterations, mean_iterations, @@ -431,7 +470,8 @@ class pxsch_bler_test evm_stats.get_mean(), ta_stats_us.get_min(), ta_stats_us.get_max(), - ta_stats_us.get_mean()); + ta_stats_us.get_mean(), + pxsch_type); } unsigned nof_codeblocks; @@ -457,26 +497,28 @@ class pxsch_bler_test static void usage(std::string_view prog) { - fmt::print("Usage: {}\n", prog); - fmt::print("\t-C Channel delay profile: single-tap, TDLA, TDLB or TDLC. [Default {}]\n", channel_delay_profile); - fmt::print("\t-F Channel fading distribution: uniform-phase or rayleigh. [Default {}]\n", + fmt::print("Usage: {} [-C X] [-F X] [-S X] [-N X] [-P X] [-R X] [-M X] [-m X] [-D] [-T X] [eal_args ...]\n", prog); + fmt::print("\t-C Channel delay profile: single-tap, TDLA, TDLB or TDLC. [Default {}]\n", channel_delay_profile); + fmt::print("\t-F Channel fading distribution: uniform-phase or rayleigh. [Default {}]\n", channel_fading_distribution); - fmt::print("\t-D Toggle enable DC position. [Default {}]\n", enable_dc_position); - fmt::print("\t-S SINR. [Default {}]\n", sinr_dB); - fmt::print("\t-N Number of corrupted RE per OFDM symbol. [Default {}]\n", nof_corrupted_re_per_ofdm_symbol); - fmt::print("\t-P Number of receive ports. [Default {}]\n", nof_rx_ports); - fmt::print("\t-B Number of allocated PRBs (same as BWP size). [Default {}]\n", bwp_size_rb); - fmt::print("\t-M MCS table. [Default {}]\n", mcs_table); - fmt::print("\t-m MCS index. [Default {}]\n", mcs_index); - fmt::print("\t-R Number of slots to process. [Default {}]\n", nof_repetitions); - fmt::print("\t-v Toggle preliminary stats. [Default {}]\n", show_stats); - fmt::print("\t-h Print this message.\n"); + fmt::print("\t-D Toggle enable DC position. [Default {}]\n", enable_dc_position); + fmt::print("\t-S SINR. [Default {}]\n", sinr_dB); + fmt::print("\t-N Number of corrupted RE per OFDM symbol. [Default {}]\n", nof_corrupted_re_per_ofdm_symbol); + fmt::print("\t-P Number of receive ports. [Default {}]\n", nof_rx_ports); + fmt::print("\t-B Number of allocated PRBs (same as BWP size). [Default {}]\n", bwp_size_rb); + fmt::print("\t-M MCS table. [Default {}]\n", mcs_table); + fmt::print("\t-m MCS index. [Default {}]\n", mcs_index); + fmt::print("\t-R Number of slots to process. [Default {}]\n", nof_repetitions); + fmt::print("\t-T PxSCH implementation type [auto,acc100][Default {}]\n", pxsch_type); + fmt::print("\teal_args EAL arguments\n"); + fmt::print("\t-v Toggle preliminary stats. [Default {}]\n", show_stats); + fmt::print("\t-h Print this message.\n"); } static void parse_args(int argc, char** argv) { int opt = 0; - while ((opt = getopt(argc, argv, "C:F:S:N:P:R:B:M:m:Dvh")) != -1) { + while ((opt = getopt(argc, argv, "C:F:S:N:P:R:B:M:m:DT:vh")) != -1) { switch (opt) { case 'C': if (optarg != nullptr) { @@ -520,6 +562,9 @@ static void parse_args(int argc, char** argv) case 'R': nof_repetitions = std::strtol(optarg, nullptr, 10); break; + case 'T': + pxsch_type = std::string(optarg); + break; case 'v': show_stats = !show_stats; break; @@ -533,6 +578,11 @@ static void parse_args(int argc, char** argv) int main(int argc, char** argv) { +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) + // Separate EAL and non-EAL arguments. + eal_arguments = capture_eal_args(&argc, &argv); +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED + parse_args(argc, argv); pxsch_bler_test test; diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp index 687194d767..0eff5d5da1 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp @@ -9,11 +9,109 @@ */ #include "pxsch_bler_test_factories.h" +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) +#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" +#include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" +#include "srsran/hal/dpdk/dpdk_eal_factory.h" +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc_factory.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" +#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_factory.h" +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED using namespace srsran; -std::shared_ptr srsran::create_sw_pdsch_processor_factory(task_executor& executor, - unsigned max_nof_threads) +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) +static bool hwacc_pxsch_init_done = false; +static std::unique_ptr dpdk_interface = nullptr; +static std::unique_ptr bbdev_acc_factory = nullptr; +static std::shared_ptr hwacc_pdsch_enc_factory = nullptr; +static std::shared_ptr hwacc_pusch_dec_factory = nullptr; + +static void create_hwacc_pxsch_factories(const std::string& eal_arguments) +{ + if (!hwacc_pxsch_init_done) { + // Hardcoded stdout and error logging. + srslog::sink* log_sink = srslog::create_stdout_sink(); + srslog::set_default_sink(*log_sink); + srslog::init(); + srslog::basic_logger& logger = srslog::fetch_basic_logger("HAL", false); + logger.set_level(srslog::basic_levels::error); + + // Pointer to a dpdk-based hardware-accelerator interface. + if (!dpdk_interface) { + // :TODO: Enable passing EAL arguments. + dpdk_interface = dpdk::create_dpdk_eal(eal_arguments, logger); + if (!dpdk_interface) { + return; + } + } + + // Create a bbdev accelerator factory. + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + if (!bbdev_acc_factory) { + return; + } + } + + // Intefacing to the bbdev-based hardware-accelerator. + dpdk::bbdev_acc_configuration bbdev_config; + bbdev_config.id = 0; + bbdev_config.nof_ldpc_enc_lcores = dpdk::MAX_NOF_BBDEV_VF_INSTANCES; + bbdev_config.nof_ldpc_dec_lcores = dpdk::MAX_NOF_BBDEV_VF_INSTANCES; + bbdev_config.nof_fft_lcores = 0; + bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); + if (!bbdev_accelerator) { + return; + } + + // Set the PDSCH encoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hw_encoder_config; + hw_encoder_config.acc_type = "acc100"; + hw_encoder_config.bbdev_accelerator = bbdev_accelerator; + hw_encoder_config.cb_mode = false; + hw_encoder_config.max_tb_size = RTE_BBDEV_LDPC_E_MAX_MBUF; + hw_encoder_config.dedicated_queue = true; + // ACC100 hardware-accelerator implementation. + hwacc_pdsch_enc_factory = srsran::hal::create_bbdev_pdsch_enc_acc_factory(hw_encoder_config, "srs"); + if (!hwacc_pdsch_enc_factory) { + return; + } + + // Interfacing to a shared external HARQ buffer context repository. + unsigned nof_cbs = MAX_NOF_SEGMENTS; + uint64_t acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); + std::shared_ptr harq_buffer_context = + hal::create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, false); + if (!harq_buffer_context) { + return; + } + + // Set the PUSCH decoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pusch_dec_factory_configuration hw_decoder_config; + hw_decoder_config.acc_type = "acc100"; + hw_decoder_config.bbdev_accelerator = bbdev_accelerator; + hw_decoder_config.ext_softbuffer = true; + hw_decoder_config.harq_buffer_context = harq_buffer_context; + hw_decoder_config.dedicated_queue = true; + // ACC100 hardware-accelerator implementation. + hwacc_pusch_dec_factory = hal::create_bbdev_pusch_dec_acc_factory(hw_decoder_config, "srs"); + if (!hwacc_pusch_dec_factory) { + return; + } + + hwacc_pxsch_init_done = true; + } +} +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED + +std::shared_ptr srsran::create_sw_pdsch_processor_factory(task_executor& executor, + unsigned max_nof_threads, + const std::string& eal_arguments, + const std::string& pxsch_type) { std::shared_ptr crc_calc_factory = create_crc_calculator_factory_sw("auto"); report_fatal_error_if_not(crc_calc_factory, "Failed to create CRC calculator factory."); @@ -38,6 +136,31 @@ std::shared_ptr srsran::create_sw_pdsch_processor_facto create_dmrs_pdsch_processor_factory_sw(pseudo_random_gen_factory); report_fatal_error_if_not(dmrs_pdsch_proc_factory, "Failed to create factory."); +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) + if (pxsch_type.find("acc100") != std::string::npos) { + // Initialize the hardware-accelerator. + create_hwacc_pxsch_factories(eal_arguments); + if (!hwacc_pxsch_init_done) { + return nullptr; + } + + // Set the hardware-accelerated PDSCH encoder configuration. + pdsch_encoder_factory_hw_configuration encoder_hw_factory_config; + encoder_hw_factory_config.crc_factory = crc_calc_factory; + encoder_hw_factory_config.segmenter_factory = segmenter_factory; + encoder_hw_factory_config.hw_encoder_factory = hwacc_pdsch_enc_factory; + std::shared_ptr pdsch_encoder_factory = + create_pdsch_encoder_factory_hw(encoder_hw_factory_config); + report_fatal_error_if_not(pdsch_encoder_factory, "Failed to create factory."); + + std::shared_ptr pdsch_modulator_factory = + create_pdsch_modulator_factory_sw(channel_mod_factory, pseudo_random_gen_factory); + report_fatal_error_if_not(pdsch_modulator_factory, "Failed to create factory."); + + return create_pdsch_processor_factory_sw(pdsch_encoder_factory, pdsch_modulator_factory, dmrs_pdsch_proc_factory); + } +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED + return create_pdsch_concurrent_processor_factory_sw(crc_calc_factory, ldpc_encoder_factory, ldpc_rate_matcher_factory, @@ -51,7 +174,8 @@ std::shared_ptr srsran::create_sw_pdsch_processor_facto std::shared_ptr srsran::create_sw_pusch_processor_factory(task_executor& executor, unsigned max_nof_threads, unsigned nof_ldpc_iterations, - bool dec_enable_early_stop) + bool dec_enable_early_stop, + const std::string& pxsch_type) { std::shared_ptr dft_proc_factory = create_dft_processor_factory_fftw_slow(); report_fatal_error_if_not(dft_proc_factory, "Failed to create factory."); @@ -69,17 +193,31 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto std::shared_ptr segmenter_rx_factory = create_ldpc_segmenter_rx_factory_sw(); report_fatal_error_if_not(segmenter_rx_factory, "Failed to create factory."); - pusch_decoder_factory_sw_configuration pusch_decoder_factory_sw_config; - pusch_decoder_factory_sw_config.crc_factory = crc_calc_factory; - pusch_decoder_factory_sw_config.decoder_factory = ldpc_decoder_factory; - pusch_decoder_factory_sw_config.dematcher_factory = ldpc_rate_dematcher_factory; - pusch_decoder_factory_sw_config.segmenter_factory = segmenter_rx_factory; - pusch_decoder_factory_sw_config.nof_pusch_decoder_threads = max_nof_threads; - pusch_decoder_factory_sw_config.executor = &executor; - pusch_decoder_factory_sw_config.nof_prb = MAX_RB; - pusch_decoder_factory_sw_config.nof_layers = pusch_constants::MAX_NOF_LAYERS; - std::shared_ptr pusch_dec_factory = - create_pusch_decoder_factory_sw(pusch_decoder_factory_sw_config); + std::shared_ptr pusch_dec_factory = nullptr; +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) + if (pxsch_type.find("acc100") != std::string::npos) { + // Set the hardware-accelerated PUSCH decoder configuration. + pusch_decoder_factory_hw_configuration decoder_hw_factory_config; + decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; + decoder_hw_factory_config.crc_factory = crc_calc_factory; + decoder_hw_factory_config.hw_decoder_factory = hwacc_pusch_dec_factory; + decoder_hw_factory_config.executor = &executor; + pusch_dec_factory = create_pusch_decoder_factory_hw(decoder_hw_factory_config); + } else { +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED + pusch_decoder_factory_sw_configuration pusch_decoder_factory_sw_config; + pusch_decoder_factory_sw_config.crc_factory = crc_calc_factory; + pusch_decoder_factory_sw_config.decoder_factory = ldpc_decoder_factory; + pusch_decoder_factory_sw_config.dematcher_factory = ldpc_rate_dematcher_factory; + pusch_decoder_factory_sw_config.segmenter_factory = segmenter_rx_factory; + pusch_decoder_factory_sw_config.nof_pusch_decoder_threads = max_nof_threads; + pusch_decoder_factory_sw_config.executor = &executor; + pusch_decoder_factory_sw_config.nof_prb = MAX_RB; + pusch_decoder_factory_sw_config.nof_layers = pusch_constants::MAX_NOF_LAYERS; + pusch_dec_factory = create_pusch_decoder_factory_sw(pusch_decoder_factory_sw_config); +#if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) + } +#endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED report_fatal_error_if_not(pusch_dec_factory, "Failed to create factory."); std::shared_ptr pseudo_random_gen_factory = @@ -148,4 +286,4 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto report_fatal_error_if_not(pusch_proc_factory, "Failed to create factory."); return pusch_proc_factory; -} \ No newline at end of file +} diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.h b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.h index 828e91a3b5..1cb1705a74 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.h +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.h @@ -18,19 +18,25 @@ namespace srsran { /// \brief Creates a PDSCH processor factory. /// \param[in] executor Asynchronous executor. /// \param[in] max_nof_threads Maximum number of concurrent threads. +/// \param[in] eal_arguments String containing the EAL arguments to be used in case of hardware-acceleration. +/// \param[in] pxsch_type Type of PxSCH implementation to be tested. /// \return A PDSCH processor factory if it is successful. -std::shared_ptr create_sw_pdsch_processor_factory(task_executor& executor, - unsigned max_nof_threads); +std::shared_ptr create_sw_pdsch_processor_factory(task_executor& executor, + unsigned max_nof_threads, + const std::string& eal_arguments, + const std::string& pxsch_type); /// \brief Creates a PUSCH processor factory. /// \param[in] executor Asynchornous executor. /// \param[in] max_nof_threads Maximum number of concurrent threads. /// \param[in] nof_ldpc_iterations Maximum number of LDPC decoder iterations. /// \param[in] dec_enable_early_stop Set to true to enable LDPC decoder early stop. +/// \param[in] pxsch_type Type of PxSCH implementation to be tested. /// \return A PUSCH processor factory if it is successful. -std::shared_ptr create_sw_pusch_processor_factory(task_executor& executor, - unsigned max_nof_threads, - unsigned nof_ldpc_iterations, - bool dec_enable_early_stop); +std::shared_ptr create_sw_pusch_processor_factory(task_executor& executor, + unsigned max_nof_threads, + unsigned nof_ldpc_iterations, + bool dec_enable_early_stop, + const std::string& pxsch_type); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/phy/upper/channel_processors/pdsch_encoder_test.cpp b/tests/unittests/phy/upper/channel_processors/pdsch_encoder_test.cpp index 8438aea67e..8b8a8276fa 100644 --- a/tests/unittests/phy/upper/channel_processors/pdsch_encoder_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pdsch_encoder_test.cpp @@ -150,6 +150,13 @@ static std::shared_ptr create_hw_accelera TESTASSERT(dpdk_interface, "Failed to open DPDK EAL with arguments."); } + // Create a bbdev accelerator factory. + static std::unique_ptr bbdev_acc_factory = nullptr; + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + TESTASSERT(bbdev_acc_factory, "Failed to create the bbdev accelerator factory."); + } + // Intefacing to the bbdev-based hardware-accelerator. dpdk::bbdev_acc_configuration bbdev_config; bbdev_config.id = 0; @@ -157,11 +164,11 @@ static std::shared_ptr create_hw_accelera bbdev_config.nof_ldpc_dec_lcores = 0; bbdev_config.nof_fft_lcores = 0; bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); TESTASSERT(bbdev_accelerator); - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pdsch_enc_configuration hw_encoder_config; + // Set the PDSCH encoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hw_encoder_config; hw_encoder_config.acc_type = "acc100"; hw_encoder_config.bbdev_accelerator = bbdev_accelerator; hw_encoder_config.cb_mode = cb_mode; @@ -169,7 +176,7 @@ static std::shared_ptr create_hw_accelera hw_encoder_config.dedicated_queue = dedicated_queue; // ACC100 hardware-accelerator implementation. - return create_hw_accelerator_pdsch_enc_factory(hw_encoder_config); + return srsran::hal::create_bbdev_pdsch_enc_acc_factory(hw_encoder_config, "srs"); #else // HWACC_PDSCH_ENABLED return nullptr; #endif // HWACC_PDSCH_ENABLED diff --git a/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp index 30848a1a40..91d68e5440 100644 --- a/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp @@ -29,8 +29,44 @@ using namespace srsran; +static std::string eal_arguments = "pdsch_processor_vectortest"; #ifdef HWACC_PDSCH_ENABLED -static bool skip_hwacc_test = false; +static bool skip_hwacc_test = false; +static std::unique_ptr dpdk_interface = nullptr; +static std::unique_ptr bbdev_acc_factory = nullptr; + +// Separates EAL and non-EAL arguments. +// The function assumes that 'eal_arg' flags the start of the EAL arguments and that no more non-EAL arguments follow. +static std::string capture_eal_args(int* argc, char*** argv) +{ + // Searchs for the EAL args (if any), flagged by 'eal_args', while removing all the rest (except argv[0]). + bool eal_found = false; + char** mod_argv = *argv; + std::string eal_argv = {mod_argv[0]}; + int opt_ind = *argc; + for (int j = 1; j < opt_ind; ++j) { + // Search for the 'eal_args' flag (if any). + if (!eal_found) { + if (strcmp(mod_argv[j], "eal_args") == 0) { + // 'eal_args' flag found. + eal_found = true; + // Remove all main app arguments starting from that point, while copying them to the EAL argument string. + mod_argv[j] = NULL; + for (int k = j + 1; k < opt_ind; ++k) { + eal_argv += " "; + eal_argv += mod_argv[k]; + mod_argv[k] = NULL; + } + *argc = j; + } + } + } + *argv = mod_argv; + + fmt::print("eal_arg={}\n", eal_argv); + + return eal_argv; +} #endif // HWACC_PDSCH_ENABLED namespace srsran { @@ -71,7 +107,8 @@ class PdschProcessorFixture : public ::testing::TestWithParam create_hw_accelerator_pdsch_enc_factory() + static std::shared_ptr + create_hw_accelerator_pdsch_enc_factory(const std::string& eal_arguments) { #ifdef HWACC_PDSCH_ENABLED // Hardcoded stdout and error logging. @@ -82,10 +119,9 @@ class PdschProcessorFixture : public ::testing::TestWithParam dpdk_interface = nullptr; if (!dpdk_interface && !skip_hwacc_test) { // :TODO: Enable passing EAL arguments. - dpdk_interface = dpdk::create_dpdk_eal("pdsch_processor_vectortest", logger); + dpdk_interface = dpdk::create_dpdk_eal(eal_arguments, logger); if (!dpdk_interface) { skip_hwacc_test = true; return nullptr; @@ -94,6 +130,15 @@ class PdschProcessorFixture : public ::testing::TestWithParam(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); if (!bbdev_accelerator || skip_hwacc_test) { skip_hwacc_test = true; return nullptr; } - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pdsch_enc_configuration hw_encoder_config; + // Set the PDSCH encoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pdsch_enc_factory_configuration hw_encoder_config; hw_encoder_config.acc_type = "acc100"; hw_encoder_config.bbdev_accelerator = bbdev_accelerator; hw_encoder_config.cb_mode = false; @@ -116,14 +161,15 @@ class PdschProcessorFixture : public ::testing::TestWithParam - create_acc100_pdsch_encoder_factory(std::shared_ptr crc_calculator_factory) + create_acc100_pdsch_encoder_factory(std::shared_ptr crc_calculator_factory, + const std::string& eal_arguments) { std::shared_ptr segmenter_factory = create_ldpc_segmenter_tx_factory_sw(crc_calculator_factory); @@ -132,7 +178,7 @@ class PdschProcessorFixture : public ::testing::TestWithParam hw_encoder_factory = - create_hw_accelerator_pdsch_enc_factory(); + create_hw_accelerator_pdsch_enc_factory(eal_arguments); if (!hw_encoder_factory) { return nullptr; } @@ -147,20 +193,22 @@ class PdschProcessorFixture : public ::testing::TestWithParam create_pdsch_encoder_factory(std::shared_ptr crc_calculator_factory, - const std::string& encoder_type) + const std::string& encoder_type, + const std::string& eal_arguments) { if (encoder_type == "generic") { return create_generic_pdsch_encoder_factory(crc_calculator_factory); } if (encoder_type == "acc100") { - return create_acc100_pdsch_encoder_factory(crc_calculator_factory); + return create_acc100_pdsch_encoder_factory(crc_calculator_factory, eal_arguments); } return nullptr; } - std::shared_ptr create_pdsch_processor_factory(const std::string& factory_type) + std::shared_ptr create_pdsch_processor_factory(const std::string& factory_type, + const std::string& eal_arguments) { std::string encoder_type = "generic"; #ifdef HWACC_PDSCH_ENABLED @@ -191,7 +239,7 @@ class PdschProcessorFixture : public ::testing::TestWithParam pdsch_encoder_factory = - create_pdsch_encoder_factory(crc_calc_factory, encoder_type); + create_pdsch_encoder_factory(crc_calc_factory, encoder_type, eal_arguments); if (!pdsch_encoder_factory) { return nullptr; } @@ -264,7 +312,8 @@ class PdschProcessorFixture : public ::testing::TestWithParam(param); // Create PDSCH processor factory. - std::shared_ptr pdsch_proc_factory = create_pdsch_processor_factory(factory_type); + std::shared_ptr pdsch_proc_factory = + create_pdsch_processor_factory(factory_type, eal_arguments); #ifdef HWACC_PDSCH_ENABLED if ((factory_type.find("acc100") != std::string::npos) && skip_hwacc_test) { GTEST_SKIP() << "[WARNING] ACC100 not found. Skipping test."; @@ -340,3 +389,16 @@ INSTANTIATE_TEST_SUITE_P(PdschProcessorVectortest, } // namespace } // namespace srsran + +int main(int argc, char** argv) +{ +#ifdef HWACC_PDSCH_ENABLED + if (argc > 1) { + // Separate EAL and non-EAL arguments. + eal_arguments = capture_eal_args(&argc, &argv); + } +#endif // HWACC_PDSCH_ENABLED + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp index cd4b842ccb..b1134cc967 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp @@ -182,6 +182,13 @@ static std::shared_ptr create_hw_accelera TESTASSERT(dpdk_interface, "Failed to open DPDK EAL with arguments."); } + // Create a bbdev accelerator factory. + static std::unique_ptr bbdev_acc_factory = nullptr; + if (!bbdev_acc_factory) { + bbdev_acc_factory = srsran::dpdk::create_bbdev_acc_factory("srs"); + TESTASSERT(bbdev_acc_factory, "Failed to create the bbdev accelerator factory."); + } + // Intefacing to the bbdev-based hardware-accelerator. dpdk::bbdev_acc_configuration bbdev_config; bbdev_config.id = 0; @@ -189,7 +196,7 @@ static std::shared_ptr create_hw_accelera bbdev_config.nof_ldpc_dec_lcores = 1; bbdev_config.nof_fft_lcores = 0; bbdev_config.nof_mbuf = static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); TESTASSERT(bbdev_accelerator); // Interfacing to a shared external HARQ buffer context repository. @@ -199,8 +206,8 @@ static std::shared_ptr create_hw_accelera hal::create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, test_harq); TESTASSERT(harq_buffer_context); - // Set the hardware-accelerator configuration. - hal::hw_accelerator_pusch_dec_configuration hw_decoder_config; + // Set the PUSCH decoder hardware-accelerator factory configuration for the ACC100. + hal::bbdev_hwacc_pusch_dec_factory_configuration hw_decoder_config; hw_decoder_config.acc_type = "acc100"; hw_decoder_config.bbdev_accelerator = bbdev_accelerator; hw_decoder_config.ext_softbuffer = ext_softbuffer; @@ -208,7 +215,7 @@ static std::shared_ptr create_hw_accelera hw_decoder_config.dedicated_queue = dedicated_queue; // ACC100 hardware-accelerator implementation. - return create_hw_accelerator_pusch_dec_factory(hw_decoder_config); + return srsran::hal::create_bbdev_pusch_dec_acc_factory(hw_decoder_config, "srs"); #else // HWACC_PUSCH_ENABLED return nullptr; #endif // HWACC_PUSCH_ENABLED @@ -230,6 +237,7 @@ static std::shared_ptr create_acc100_pusch_decoder_factor decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; decoder_hw_factory_config.crc_factory = crc_calculator_factory; decoder_hw_factory_config.hw_decoder_factory = hw_decoder_factory; + decoder_hw_factory_config.executor = nullptr; return create_pusch_decoder_factory_hw(decoder_hw_factory_config); } diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp index ca0ae90299..c6e1ef76fc 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp @@ -28,8 +28,44 @@ using namespace srsran; +static std::string eal_arguments = "pusch_processor_vectortest"; #ifdef HWACC_PUSCH_ENABLED -static bool skip_hwacc_test = false; +static bool skip_hwacc_test = false; +static std::unique_ptr dpdk_interface = nullptr; +static std::unique_ptr bbdev_acc_factory = nullptr; + +// Separates EAL and non-EAL arguments. +// The function assumes that 'eal_arg' flags the start of the EAL arguments and that no more non-EAL arguments follow. +static std::string capture_eal_args(int* argc, char*** argv) +{ + // Searchs for the EAL args (if any), flagged by 'eal_args', while removing all the rest (except argv[0]). + bool eal_found = false; + char** mod_argv = *argv; + std::string eal_argv = {mod_argv[0]}; + int opt_ind = *argc; + for (int j = 1; j < opt_ind; ++j) { + // Search for the 'eal_args' flag (if any). + if (!eal_found) { + if (strcmp(mod_argv[j], "eal_args") == 0) { + // 'eal_args' flag found. + eal_found = true; + // Remove all main app arguments starting from that point, while copying them to the EAL argument string. + mod_argv[j] = NULL; + for (int k = j + 1; k < opt_ind; ++k) { + eal_argv += " "; + eal_argv += mod_argv[k]; + mod_argv[k] = NULL; + } + *argc = j; + } + } + } + *argv = mod_argv; + + fmt::print("eal_arg={}\n", eal_argv); + + return eal_argv; +} #endif // HWACC_PUSCH_ENABLED namespace srsran { @@ -85,7 +121,8 @@ class PuschProcessorFixture : public ::testing::TestWithParam create_hw_accelerator_pusch_dec_factory() + static std::shared_ptr + create_hw_accelerator_pusch_dec_factory(const std::string& eal_arguments) { #ifdef HWACC_PUSCH_ENABLED // Hardcoded stdout and error logging. @@ -96,10 +133,9 @@ class PuschProcessorFixture : public ::testing::TestWithParam dpdk_interface = nullptr; if (!dpdk_interface && !skip_hwacc_test) { // :TODO: Enable passing EAL arguments. - dpdk_interface = dpdk::create_dpdk_eal("pusch_processor_vectortest", logger); + dpdk_interface = dpdk::create_dpdk_eal(eal_arguments, logger); if (!dpdk_interface) { skip_hwacc_test = true; return nullptr; @@ -108,14 +144,23 @@ class PuschProcessorFixture : public ::testing::TestWithParam(pow2(log2_ceil(MAX_NOF_SEGMENTS))); - std::shared_ptr bbdev_accelerator = create_bbdev_acc(bbdev_config, logger); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, logger); if (!bbdev_accelerator || skip_hwacc_test) { skip_hwacc_test = true; return nullptr; @@ -131,8 +176,8 @@ class PuschProcessorFixture : public ::testing::TestWithParam - create_acc100_pusch_decoder_factory(std::shared_ptr crc_calculator_factory) + create_acc100_pusch_decoder_factory(std::shared_ptr crc_calculator_factory, + const std::string& eal_arguments) { std::shared_ptr segmenter_rx_factory = create_ldpc_segmenter_rx_factory_sw(); if (!segmenter_rx_factory) { @@ -155,22 +201,25 @@ class PuschProcessorFixture : public ::testing::TestWithParam hw_decoder_factory = - create_hw_accelerator_pusch_dec_factory(); + create_hw_accelerator_pusch_dec_factory(eal_arguments); if (!hw_decoder_factory) { return nullptr; } // Set the hardware-accelerated PUSCH decoder configuration. pusch_decoder_factory_hw_configuration decoder_hw_factory_config; - decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; - decoder_hw_factory_config.crc_factory = crc_calculator_factory; - decoder_hw_factory_config.hw_decoder_factory = hw_decoder_factory; + decoder_hw_factory_config.segmenter_factory = segmenter_rx_factory; + decoder_hw_factory_config.crc_factory = crc_calculator_factory; + decoder_hw_factory_config.hw_decoder_factory = hw_decoder_factory; + decoder_hw_factory_config.executor = nullptr; + decoder_hw_factory_config.nof_pusch_decoder_threads = 2; return create_pusch_decoder_factory_hw(decoder_hw_factory_config); } static std::shared_ptr create_pusch_decoder_factory(std::shared_ptr crc_calculator_factory, - const std::string& decoder_type) + const std::string& decoder_type, + const std::string& eal_arguments) { if (decoder_type == "empty") { return create_pusch_decoder_empty_factory(MAX_RB, pusch_constants::MAX_NOF_LAYERS); @@ -181,14 +230,15 @@ class PuschProcessorFixture : public ::testing::TestWithParam create_pusch_processor_factory(const test_case_context& context, - const std::string& decoder_type) + const std::string& decoder_type, + const std::string& eal_arguments) { // Create pseudo-random sequence generator. std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); @@ -275,7 +325,7 @@ class PuschProcessorFixture : public ::testing::TestWithParam pusch_dec_factory = - create_pusch_decoder_factory(crc_calc_factory, decoder_type); + create_pusch_decoder_factory(crc_calc_factory, decoder_type, eal_arguments); if (!pusch_dec_factory) { return nullptr; } @@ -321,7 +371,8 @@ class PuschProcessorFixture : public ::testing::TestWithParam pusch_proc_factory = create_pusch_processor_factory(context, decoder_type); + std::shared_ptr pusch_proc_factory = + create_pusch_processor_factory(context, decoder_type, eal_arguments); #ifdef HWACC_PUSCH_ENABLED if (decoder_type == "acc100" && skip_hwacc_test) { GTEST_SKIP() << "[WARNING] ACC100 not found. Skipping test."; @@ -532,3 +583,16 @@ INSTANTIATE_TEST_SUITE_P(PuschProcessorVectortest, #endif // HWACC_PUSCH_ENABLED ::testing::ValuesIn(pusch_processor_test_data))); } // namespace + +int main(int argc, char** argv) +{ +#ifdef HWACC_PUSCH_ENABLED + if (argc > 1) { + // Separate EAL and non-EAL arguments. + eal_arguments = capture_eal_args(&argc, &argv); + } +#endif // HWACC_PUSCH_ENABLED + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From c2184f333f413c442f60af5c8f32aa1d14e37301 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 30 Jul 2024 10:02:21 +0200 Subject: [PATCH 045/407] sched: refactor policy scheduler by wrapping UE inside a slice UE --- lib/scheduler/CMakeLists.txt | 1 + lib/scheduler/policy/scheduler_time_pf.cpp | 28 +++---- lib/scheduler/policy/scheduler_time_pf.h | 4 +- lib/scheduler/policy/scheduler_time_rr.cpp | 54 +++++++------ lib/scheduler/policy/ue_allocator.h | 5 +- lib/scheduler/slicing/ran_slice_instance.cpp | 18 ++--- lib/scheduler/slicing/ran_slice_instance.h | 16 ++-- lib/scheduler/slicing/slice_scheduler.cpp | 4 +- lib/scheduler/slicing/slice_ue_repository.cpp | 62 +++++++++++++++ lib/scheduler/slicing/slice_ue_repository.h | 75 ++++++++++++++++++- .../ue_scheduling/ue_cell_grid_allocator.cpp | 8 +- .../policy/scheduler_policy_test.cpp | 2 +- .../ue_scheduling/ue_grid_allocator_test.cpp | 71 ++++++++++-------- 13 files changed, 250 insertions(+), 98 deletions(-) create mode 100644 lib/scheduler/slicing/slice_ue_repository.cpp diff --git a/lib/scheduler/CMakeLists.txt b/lib/scheduler/CMakeLists.txt index a6b79d33df..000ab62d07 100644 --- a/lib/scheduler/CMakeLists.txt +++ b/lib/scheduler/CMakeLists.txt @@ -40,6 +40,7 @@ set(SOURCES support/csi_report_helpers.cpp slicing/slice_scheduler.cpp slicing/ran_slice_instance.cpp + slicing/slice_ue_repository.cpp cell_scheduler.cpp scheduler_factory.cpp scheduler_impl.cpp diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index a5681209bc..31b4f115a9 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -35,12 +35,12 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, // Add new users to history db, and update DL priority queue. for (const auto& u : ues) { - if (not ue_history_db.contains(u->ue_index)) { + if (not ue_history_db.contains(u.ue_index())) { // TODO: Consider other cells when carrier aggregation is supported. - ue_history_db.emplace(u->ue_index, ue_ctxt{u->ue_index, u->get_pcell().cell_index, this}); + ue_history_db.emplace(u.ue_index(), ue_ctxt{u.ue_index(), u.get_pcell().cell_index, this}); } - ue_ctxt& ctxt = ue_history_db[u->ue_index]; - ctxt.compute_dl_prio(*u); + ue_ctxt& ctxt = ue_history_db[u.ue_index()]; + ctxt.compute_dl_prio(u); dl_queue.push(&ctxt); } @@ -80,12 +80,12 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, // Add new users to history db, and update UL priority queue. for (const auto& u : ues) { - if (not ue_history_db.contains(u->ue_index)) { + if (not ue_history_db.contains(u.ue_index())) { // TODO: Consider other cells when carrier aggregation is supported. - ue_history_db.emplace(u->ue_index, ue_ctxt{u->ue_index, u->get_pcell().cell_index, this}); + ue_history_db.emplace(u.ue_index(), ue_ctxt{u.ue_index(), u.get_pcell().cell_index, this}); } - ue_ctxt& ctxt = ue_history_db[u->ue_index]; - ctxt.compute_ul_prio(*u, res_grid); + ue_ctxt& ctxt = ue_history_db[u.ue_index()]; + ctxt.compute_ul_prio(u, res_grid); ul_queue.push(&ctxt); } @@ -113,7 +113,7 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; - ue_pdsch_grant grant{ues[ctxt.ue_index], ctxt.cell_index}; + ue_pdsch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; // Prioritize reTx over newTx. if (ctxt.dl_retx_h != nullptr) { grant.h_id = ctxt.dl_retx_h->id; @@ -129,7 +129,7 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, if (ctxt.dl_newtx_h != nullptr) { grant.h_id = ctxt.dl_newtx_h->id; grant.recommended_nof_bytes = ctxt.dl_newtx_srb_pending_bytes > 0 ? ctxt.dl_newtx_srb_pending_bytes - : ues[ctxt.ue_index]->pending_dl_newtx_bytes(); + : ues[ctxt.ue_index].pending_dl_newtx_bytes(); grant.max_nof_rbs = max_rbs; alloc_result = pdsch_alloc.allocate_dl_grant(grant); if (alloc_result.status == alloc_status::success) { @@ -147,7 +147,7 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; - ue_pusch_grant grant{ues[ctxt.ue_index], ctxt.cell_index}; + ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; // Prioritize reTx over newTx. if (ctxt.ul_retx_h != nullptr) { grant.h_id = ctxt.ul_retx_h->id; @@ -163,7 +163,7 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, if (ctxt.ul_newtx_h != nullptr) { grant.h_id = ctxt.ul_newtx_h->id; grant.recommended_nof_bytes = ctxt.ul_newtx_srb_pending_bytes > 0 ? ctxt.ul_newtx_srb_pending_bytes - : ues[ctxt.ue_index]->pending_ul_newtx_bytes(); + : ues[ctxt.ue_index].pending_ul_newtx_bytes(); grant.max_nof_rbs = max_rbs; alloc_result = pusch_alloc.allocate_ul_grant(grant); if (alloc_result.status == alloc_status::success) { @@ -177,7 +177,7 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void scheduler_time_pf::ue_ctxt::compute_dl_prio(const ue& u) +void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u) { dl_retx_h = nullptr; dl_newtx_h = nullptr; @@ -253,7 +253,7 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const ue& u) dl_newtx_h = nullptr; } -void scheduler_time_pf::ue_ctxt::compute_ul_prio(const ue& u, const ue_resource_grid_view& res_grid) +void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid) { ul_retx_h = nullptr; ul_newtx_h = nullptr; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index 3a09acfd13..dbc1e5a02e 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -44,8 +44,8 @@ class scheduler_time_pf : public scheduler_policy /// Returns average UL rate expressed in bytes per slot. [[nodiscard]] double ul_avg_rate() const { return ul_nof_samples == 0 ? 0 : ul_avg_rate_; } - void compute_dl_prio(const ue& u); - void compute_ul_prio(const ue& u, const ue_resource_grid_view& res_grid); + void compute_dl_prio(const slice_ue& u); + void compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid); void save_dl_alloc(uint32_t alloc_bytes); void save_ul_alloc(uint32_t alloc_bytes); diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 46582377ad..dddb44a105 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -51,13 +51,13 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& unsigned nof_ues_to_be_scheduled_per_slot = 0; for (const auto& u : ues) { - if ((is_dl and u->has_pending_dl_newtx_bytes()) or (not is_dl and u->pending_ul_newtx_bytes() > 0)) { + if ((is_dl and u.has_pending_dl_newtx_bytes()) or (not is_dl and u.pending_ul_newtx_bytes() > 0)) { ++nof_ue_with_new_tx; } } // NOTE: All UEs use the same dedicated SearchSpace configuration. - const ue& u = **ues.begin(); + const slice_ue& u = *ues.begin(); const ue_cell_configuration& ue_cfg = u.get_pcell().cfg(); const auto* ss_info = ue_cfg.find_search_space(ue_cfg.cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.back().get_id()); @@ -118,7 +118,7 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& } /// \brief Fetches list of DL HARQ candidates to schedule. -static static_vector get_ue_dl_harq_candidates(const ue& ue_ref, +static static_vector get_ue_dl_harq_candidates(const slice_ue& ue_ref, ue_cell_index_t cell_index, bool is_retx, bool ue_with_srb_data_only, @@ -175,8 +175,10 @@ static static_vector get_ue_dl_harq_candi } /// \brief Fetches list of UL HARQ candidates to schedule. -static static_vector -get_ue_ul_harq_candidates(const ue& ue_ref, ue_cell_index_t cell_index, bool is_retx, srslog::basic_logger& logger) +static static_vector get_ue_ul_harq_candidates(const slice_ue& ue_ref, + ue_cell_index_t cell_index, + bool is_retx, + srslog::basic_logger& logger) { static_vector ul_harq_candidates; @@ -244,7 +246,7 @@ round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, // wrap-around it = ue_db.begin(); } - const ue& u = **it; + const slice_ue& u = *it; const alloc_result result = alloc_ue(u); if (result.status == alloc_status::skip_slot) { // Grid allocator directed policy to stop allocations for this slot. @@ -256,7 +258,7 @@ round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, // It is important that we equally distribute the opportunity to be the first UE being allocated in a slot for // all UEs. Otherwise, we could end up in a situation, where a UE is always the last one to be allocated and // can only use the RBs that were left from the previous UE allocations. - next_ue_index = to_du_ue_index(static_cast(u.ue_index) + 1U); + next_ue_index = to_du_ue_index(static_cast(u.ue_index()) + 1U); first_alloc = false; } } @@ -264,7 +266,7 @@ round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, } /// Allocate UE PDSCH grant. -static alloc_result alloc_dl_ue(const ue& u, +static alloc_result alloc_dl_ue(const slice_ue& u, const ue_resource_grid_view& res_grid, ue_pdsch_allocator& pdsch_alloc, bool is_retx, @@ -293,7 +295,7 @@ static alloc_result alloc_dl_ue(const ue& u, // UE is already allocated in the PDCCH for this slot (e.g. we should skip a newTx if a reTx has already been // allocated for this UE). - if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti)) { + if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti())) { return {alloc_status::skip_ue}; } @@ -324,7 +326,7 @@ static alloc_result alloc_dl_ue(const ue& u, } /// Allocate UE PUSCH grant. -static alloc_result alloc_ul_ue(const ue& u, +static alloc_result alloc_ul_ue(const slice_ue& u, const ue_resource_grid_view& res_grid, ue_pusch_allocator& pusch_alloc, bool is_retx, @@ -405,7 +407,7 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, } // First, schedule UEs with SRB data re-transmissions. - auto srb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const ue& u) { + auto srb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const slice_ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, true, true, logger, expert_cfg); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_retx_ue_function); @@ -414,25 +416,27 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg, max_rbs); if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Second, schedule UEs with SRB data new transmission. - auto srb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { - return alloc_dl_ue( - u, res_grid, pdsch_alloc, false, true, logger, expert_cfg, dl_new_tx_max_nof_rbs_per_ue_per_slot); - }; + auto srb_newtx_ue_function = + [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { + return alloc_dl_ue( + u, res_grid, pdsch_alloc, false, true, logger, expert_cfg, dl_new_tx_max_nof_rbs_per_ue_per_slot); + }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_newtx_ue_function); } // Third, schedule UEs with DRB re-transmissions. - auto drb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const ue& u) { + auto drb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const slice_ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, true, false, logger, expert_cfg); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_retx_ue_function); if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Then, schedule UEs with DRB new transmissions. - auto drb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { - return alloc_dl_ue( - u, res_grid, pdsch_alloc, false, false, logger, expert_cfg, dl_new_tx_max_nof_rbs_per_ue_per_slot); - }; + auto drb_newtx_ue_function = + [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { + return alloc_dl_ue( + u, res_grid, pdsch_alloc, false, false, logger, expert_cfg, dl_new_tx_max_nof_rbs_per_ue_per_slot); + }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); } } @@ -452,28 +456,30 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. - auto sr_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { + auto sr_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { return alloc_ul_ue(u, res_grid, pusch_alloc, false, true, false, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Second, schedule UEs with SRB data new transmissions. - auto srb_newtx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { + auto srb_newtx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot]( + const slice_ue& u) { return alloc_ul_ue(u, res_grid, pusch_alloc, false, false, true, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, srb_newtx_ue_function); } // Third, schedule UEs with re-transmissions. - auto data_retx_ue_function = [this, &res_grid, &pusch_alloc](const ue& u) { + auto data_retx_ue_function = [this, &res_grid, &pusch_alloc](const slice_ue& u) { return alloc_ul_ue(u, res_grid, pusch_alloc, true, false, false, logger); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); // Then, schedule UEs with new transmissions. if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - auto data_tx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { + auto data_tx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot]( + const slice_ue& u) { return alloc_ul_ue(u, res_grid, pusch_alloc, false, false, false, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); diff --git a/lib/scheduler/policy/ue_allocator.h b/lib/scheduler/policy/ue_allocator.h index 378002d1ea..77de875655 100644 --- a/lib/scheduler/policy/ue_allocator.h +++ b/lib/scheduler/policy/ue_allocator.h @@ -11,6 +11,7 @@ #include "../cell/resource_grid.h" #include "../pdcch_scheduling/pdcch_resource_allocator.h" +#include "../slicing/slice_ue_repository.h" #include "../ue_scheduling/ue.h" #include "../ue_scheduling/ue_repository.h" #include "../ue_scheduling/ue_scheduler.h" @@ -20,7 +21,7 @@ namespace srsran { /// Information relative to a UE PDSCH grant. struct ue_pdsch_grant { - const ue* user; + const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. @@ -31,7 +32,7 @@ struct ue_pdsch_grant { /// Information relative to a UE PUSCH grant. struct ue_pusch_grant { - const ue* user; + const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index c388a0cdc9..c002ac59f7 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -28,7 +28,6 @@ void ran_slice_instance::slot_indication(const ue_repository& cell_ues) while (ue_to_rem_it != slice_ues_to_rem.end()) { if (not cell_ues.contains(*ue_to_rem_it)) { slice_ues.erase(*ue_to_rem_it); - bearers.erase(*ue_to_rem_it); ue_to_rem_it = slice_ues_to_rem.erase(ue_to_rem_it); continue; } @@ -39,9 +38,9 @@ void ran_slice_instance::slot_indication(const ue_repository& cell_ues) void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) { if (lcid < MAX_NOF_RB_LCIDS) { - if (bearers.contains(ue_idx)) { - bearers[ue_idx].reset(lcid); - if (bearers[ue_idx].none()) { + if (slice_ues.contains(ue_idx)) { + slice_ues[ue_idx].rem_logical_channel(lcid); + if (not slice_ues[ue_idx].has_bearers_in_slice()) { slice_ues_to_rem.push_back(ue_idx); } } @@ -55,13 +54,10 @@ const slice_ue_repository& ran_slice_instance::get_ues() return slice_ues; } -void ran_slice_instance::add_logical_channel(const ue* u, lcid_t lcid) +void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid) { - if (not slice_ues.contains(u->ue_index)) { - slice_ues.emplace(u->ue_index, u); + if (not slice_ues.contains(u.ue_index)) { + slice_ues.emplace(u.ue_index, u); } - if (not bearers.contains(u->ue_index)) { - bearers.emplace(u->ue_index, MAX_NOF_RB_LCIDS); - } - bearers[u->ue_index].set(lcid); + slice_ues[u.ue_index].add_logical_channel(lcid); } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 40e21ee7d3..076424b478 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -26,7 +26,7 @@ class ran_slice_instance void slot_indication(const ue_repository& cell_ues); - bool active() const { return not bearers.empty(); } + bool active() const { return not slice_ues.empty(); } /// Save PDSCH grant. void store_pdsch_grant(unsigned crbs) { pdsch_rb_count += crbs; } @@ -35,13 +35,19 @@ class ran_slice_instance void store_pusch_grant(unsigned crbs) { pusch_rb_count += crbs; } /// Determine if at least one bearer of the given UE is currently managed by this slice. - bool contains(du_ue_index_t ue_idx) const { return bearers.contains(ue_idx); } + bool contains(du_ue_index_t ue_idx) const + { + return slice_ues.contains(ue_idx) and slice_ues[ue_idx].has_bearers_in_slice(); + } /// Determine if a (UE, LCID) tuple are managed by this slice. - bool contains(du_ue_index_t ue_idx, lcid_t lcid) const { return contains(ue_idx) and bearers[ue_idx].test(lcid); } + bool contains(du_ue_index_t ue_idx, lcid_t lcid) const + { + return contains(ue_idx) and slice_ues[ue_idx].contains(lcid); + } /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. - void add_logical_channel(const ue* u, lcid_t lcid); + void add_logical_channel(const ue& u, lcid_t lcid); /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. /// \remark UE is removed if all LCIDs of a UE are removed. @@ -54,8 +60,6 @@ class ran_slice_instance const cell_configuration* cell_cfg; slice_rrm_policy_config cfg; - slotted_id_table, MAX_NOF_DU_UES> bearers; - /// Counter of how many RBs have been scheduled for PDSCH in the current slot for this slice. unsigned pdsch_rb_count = 0; /// Counter of how many RBs have been scheduled for PUSCH in the current slot for this slice. diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 36d50c6c77..1563487654 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -58,7 +58,7 @@ void slice_scheduler::add_ue(const ue_configuration& ue_cfg) for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); if (ues.contains(ue_cfg.ue_index)) { - sl_inst.add_logical_channel(&ues[ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid); } } } @@ -75,7 +75,7 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); if (ues.contains(next_ue_cfg.ue_index)) { - sl_inst.add_logical_channel(&ues[next_ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid); } } } diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp new file mode 100644 index 0000000000..a334861166 --- /dev/null +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -0,0 +1,62 @@ +/* + * + * 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 "slice_ue_repository.h" + +using namespace srsran; + +slice_ue::slice_ue(const ue& u_) : u(u_), bearers(MAX_NOF_RB_LCIDS) {} + +void slice_ue::add_logical_channel(lcid_t lcid) +{ + bearers.set(lcid); +} + +void slice_ue::rem_logical_channel(lcid_t lcid) +{ + bearers.reset(lcid); +} + +bool slice_ue::has_pending_dl_newtx_bytes() const +{ + // TODO: Check for pending bytes only in bearers belonging to this slice. + return u.has_pending_dl_newtx_bytes(); +} + +unsigned slice_ue::pending_dl_srb_newtx_bytes() const +{ + return u.pending_dl_srb_newtx_bytes(); +} + +unsigned slice_ue::pending_dl_newtx_bytes(lcid_t lcid) const +{ + return u.pending_dl_newtx_bytes(lcid); +} + +bool slice_ue::has_pending_dl_srb_newtx_bytes() const +{ + return u.has_pending_dl_srb_newtx_bytes(); +} + +unsigned slice_ue::pending_ul_newtx_bytes() const +{ + // TODO: Check for pending bytes only in bearers belonging to this slice. + return u.pending_ul_newtx_bytes(); +} + +bool slice_ue::has_pending_sr() const +{ + return u.has_pending_sr(); +} + +unsigned slice_ue::pending_ul_srb_newtx_bytes() const +{ + return u.pending_ul_srb_newtx_bytes(); +} diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h index 86c2c9e79b..6d77525648 100644 --- a/lib/scheduler/slicing/slice_ue_repository.h +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -14,7 +14,80 @@ namespace srsran { +class slice_ue +{ +public: + explicit slice_ue(const ue& u); + + /// Returns DU UE index. + du_ue_index_t ue_index() const { return u.ue_index; } + + /// Returns number of cells configured for the UE. + unsigned nof_cells() const { return u.nof_cells(); } + + /// Returns UE C-RNTI. + rnti_t crnti() const { return u.crnti; } + + /// \brief Fetch UE cell based on DU cell index. + const ue_cell* find_cell(du_cell_index_t cell_index) const { return u.find_cell(cell_index); } + + /// \brief Fetch UE cell based on UE-specific cell identifier. E.g. PCell corresponds to ue_cell_index==0. + const ue_cell& get_cell(ue_cell_index_t ue_cell_index) const { return u.get_cell(ue_cell_index); } + + /// Determines if at least one bearer of the UE is part of this slice. + bool has_bearers_in_slice() const { return bearers.any(); } + + /// Determines if bearer with LCID is part of this slice. + bool contains(lcid_t lcid) const { return bearers.test(lcid); } + + /// Fetch DU cell index of UE's PCell. + const ue_cell& get_pcell() const { return u.get_pcell(); } + + /// Add LCID to the bearers of the UE belonging to this slice. + void add_logical_channel(lcid_t lcid); + + /// Remove LCID from the bearers of the UE belonging to this slice. + void rem_logical_channel(lcid_t lcid); + + /// \brief Checks if there are DL pending bytes that are yet to be allocated in a DL HARQ. + /// This method is faster than computing \c pending_dl_newtx_bytes() > 0. + /// \remark Excludes SRB0 and UE Contention Resolution Identity CE. + bool has_pending_dl_newtx_bytes() const; + + /// \brief Computes the number of DL pending bytes in SRBs that are not already allocated in a DL HARQ. + /// \return The number of DL pending bytes in SRBs that are not already allocated in a DL HARQ. + /// \remark Excludes SRB0 pending bytes. + unsigned pending_dl_srb_newtx_bytes() const; + + /// \brief Computes the number of DL pending bytes that are not already allocated in a DL HARQ. + /// param[in] lcid If the LCID is provided, the method will return the number of pending bytes for that LCID. + /// Otherwise it will return the sum of all LCIDs pending bytes, excluding SRB0. + /// \return The number of DL pending bytes that are not already allocated in a DL HARQ. + unsigned pending_dl_newtx_bytes(lcid_t lcid = lcid_t::INVALID_LCID) const; + + /// \brief Checks if there are DL pending bytes in SRBs that are not already allocated in a DL HARQ. + /// \remark Excludes SRB0 pending bytes. + bool has_pending_dl_srb_newtx_bytes() const; + + /// \brief Computes the number of UL pending bytes in bearers belonging to this slice that are not already allocated + /// in a UL HARQ. + unsigned pending_ul_newtx_bytes() const; + + /// \brief Returns whether a SR indication handling is pending. + bool has_pending_sr() const; + + /// \brief Computes the number of UL pending bytes in SRBs. The value is used to derive the required transport block + /// size for an UL grant. + /// \return The number of UL pending bytes in SRBs. + /// \remark The returned UL pending bytes does not exclude already allocated bytes in UL HARQ(s). + unsigned pending_ul_srb_newtx_bytes() const; + +private: + const ue& u; + bounded_bitset bearers; +}; + /// Container that store all UEs belonging to a slice. -using slice_ue_repository = slotted_id_table; +using slice_ue_repository = slotted_id_table; } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index aa13d67aad..4fc4afca70 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -60,7 +60,7 @@ void ue_cell_grid_allocator::slot_indication(slot_point sl) alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& grant) { - srsran_assert(ues.contains(grant.user->ue_index), "Invalid UE candidate index={}", grant.user->ue_index); + srsran_assert(ues.contains(grant.user->ue_index()), "Invalid UE candidate index={}", grant.user->ue_index()); srsran_assert(has_cell(grant.cell_index), "Invalid UE candidate cell_index={}", grant.cell_index); if (dl_attempts_count++ >= expert_cfg.max_pdcch_alloc_attempts_per_slot) { @@ -69,7 +69,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra return {alloc_status::skip_slot}; } - ue& u = ues[grant.user->ue_index]; + ue& u = ues[grant.user->ue_index()]; // Verify UE carrier is active. ue_cell* ue_cc = u.find_cell(grant.cell_index); @@ -495,7 +495,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant) { - srsran_assert(ues.contains(grant.user->ue_index), "Invalid UE candidate index={}", grant.user->ue_index); + srsran_assert(ues.contains(grant.user->ue_index()), "Invalid UE candidate index={}", grant.user->ue_index()); srsran_assert(has_cell(grant.cell_index), "Invalid UE candidate cell_index={}", grant.cell_index); constexpr static unsigned pdcch_delay_in_slots = 0; @@ -505,7 +505,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra return {alloc_status::skip_slot}; } - ue& u = ues[grant.user->ue_index]; + ue& u = ues[grant.user->ue_index()]; // Verify UE carrier is active. ue_cell* ue_cc = u.find_cell(grant.cell_index); diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index 9ce0e7fd85..ccdcd5f033 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -115,7 +115,7 @@ class base_scheduler_policy_test ues.add_ue(std::make_unique( ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, harq_timeout_handler})); for (const auto& lc_cfg : *ue_req.cfg.lc_config_list) { - slice_instance.add_logical_channel(&ues[ue_req.ue_index], lc_cfg.lcid); + slice_instance.add_logical_channel(ues[ue_req.ue_index], lc_cfg.lcid); } return ues[ue_req.ue_index]; } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 5a64d9a98a..3f2aa6bb28 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -100,6 +100,10 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam auto ev = cfg_mng.add_ue(ue_creation_req); ues.add_ue(std::make_unique( ue_creation_command{ev.next_config(), ue_creation_req.starts_in_fallback, harq_timeout_handler})); + slice_ues.emplace(ue_creation_req.ue_index, ues[ue_creation_req.ue_index]); + for (const auto& lc_cfg : *ue_creation_req.cfg.lc_config_list) { + slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid); + } return ues[ue_creation_req.ue_index]; } @@ -124,6 +128,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam scheduler_result_logger res_logger{false, cell_cfg.pci}; ue_repository ues; + slice_ue_repository slice_ues; ue_cell_grid_allocator alloc{expert_cfg, ues, logger}; slot_point current_slot; @@ -150,7 +155,7 @@ TEST_P(ue_grid_allocator_tester, const crb_interval crb_lims = { crbs.start(), crbs.start() + cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common.coreset0->coreset0_crbs().length()}; - ue_pdsch_grant grant{.user = &u, + ue_pdsch_grant grant{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -174,7 +179,7 @@ TEST_P(ue_grid_allocator_tester, when_using_non_fallback_dci_format_use_mcs_tabl const ue& u = add_ue(ue_creation_req); // SearchSpace#2 uses non-fallback DCI format hence the MCS table set in dedicated PDSCH configuration must be used. - const ue_pdsch_grant grant{.user = &u, + const ue_pdsch_grant grant{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -196,7 +201,7 @@ TEST_P(ue_grid_allocator_tester, allocates_pdsch_restricted_to_recommended_max_n static const unsigned sched_bytes = 2000U; const unsigned max_nof_rbs_to_schedule = 10U; - const ue_pdsch_grant grant1{.user = &u1, + const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes, @@ -220,7 +225,7 @@ TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_n const unsigned recommended_nof_bytes_to_schedule = 2000U; const unsigned max_nof_rbs_to_schedule = 10U; - const ue_pusch_grant grant1{.user = &u1, + const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, @@ -242,7 +247,7 @@ TEST_P(ue_grid_allocator_tester, does_not_allocate_pusch_with_all_remaining_rbs_ // Trigger a SR indication. u1.handle_sr_indication(); - const ue_pusch_grant grant1{.user = &u1, + const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = u1.pending_ul_newtx_bytes()}; @@ -266,13 +271,13 @@ TEST_P(ue_grid_allocator_tester, no_two_pdschs_are_allocated_in_same_slot_for_a_ const ue& u = add_ue(ue_creation_req); // First PDSCH grant for the UE. - const ue_pdsch_grant grant1{.user = &u, + const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; // Second PDSCH grant for the UE. - const ue_pdsch_grant grant2{.user = &u, + const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -297,13 +302,13 @@ TEST_P(ue_grid_allocator_tester, no_two_puschs_are_allocated_in_same_slot_for_a_ const ue& u = add_ue(ue_creation_req); // First PUSCH grant for the UE. - const ue_pusch_grant grant1{.user = &u, + const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; // Second PUSCH grant for the UE. - const ue_pusch_grant grant2{.user = &u, + const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -328,7 +333,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in const ue& u = add_ue(ue_creation_req); // First PUSCH grant for the UE. - const ue_pusch_grant grant1{.user = &u, + const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -340,7 +345,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in run_slot(); // Second PUSCH grant for the UE. - const ue_pusch_grant grant2{.user = &u, + const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -360,7 +365,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_in const ue& u = add_ue(ue_creation_req); // First PDSCH grant for the UE. - const ue_pdsch_grant grant1{.user = &u, + const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -372,7 +377,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_in run_slot(); // Second PDSCH grant in the same slot for the UE. - const ue_pdsch_grant grant2{.user = &u, + const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -393,7 +398,7 @@ TEST_P(ue_grid_allocator_tester, const ue& u = add_ue(ue_creation_req); // First PDSCH grant for the UE. - const ue_pdsch_grant grant1{.user = &u, + const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -405,7 +410,7 @@ TEST_P(ue_grid_allocator_tester, run_slot(); // Second PDSCH grant in the same slot for the UE. - const ue_pdsch_grant grant2{.user = &u, + const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -431,7 +436,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga } // First PDSCH grant for the UE. - const ue_pdsch_grant grant1{.user = &u, + const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -446,7 +451,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga } // Next PDSCH grant to be allocated. - const ue_pdsch_grant grant2{.user = &u, + const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -471,7 +476,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga } // First PUSCH grant for the UE. - const ue_pusch_grant grant1{.user = &u, + const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -486,7 +491,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga } // Second PUSCH grant for the UE. - const ue_pusch_grant grant2{.user = &u, + const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; @@ -521,13 +526,17 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_dl_rbs_are_alloca const ue& u2 = add_ue(ue_creation_req); static const unsigned sched_bytes = 20U; - const ue_pdsch_grant grant1{ - .user = &u1, .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes}; + const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = sched_bytes}; // Since UE dedicated SearchSpace is a UE specific SearchSpace (Not CSS). Entire BWP CRBs can be used for allocation. const unsigned total_crbs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(); - const ue_pdsch_grant grant2{ - .user = &u2, .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes}; + const ue_pdsch_grant grant2{.user = &slice_ues[u2.ue_index], + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = sched_bytes}; ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success and @@ -565,11 +574,11 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_ul_rbs_are_alloca const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; - const ue_pusch_grant grant1{.user = &u1, + const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; - const ue_pusch_grant grant2{.user = &u2, + const ue_pusch_grant grant2{.user = &slice_ues[u2.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; @@ -618,7 +627,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, static const unsigned sched_bytes = 20U; const unsigned max_nof_rbs_to_schedule = 10U; - const ue_pdsch_grant grant1{.user = &u1, + const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes, @@ -644,7 +653,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, static const unsigned sched_bytes = 20000U; const unsigned max_nof_rbs_to_schedule = 273U; - const ue_pdsch_grant grant1{.user = &u1, + const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes, @@ -670,7 +679,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const unsigned recommended_nof_bytes_to_schedule = 20U; const unsigned max_nof_rbs_to_schedule = 10U; - const ue_pusch_grant grant1{.user = &u1, + const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, @@ -696,7 +705,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const unsigned recommended_nof_bytes_to_schedule = 200000U; const unsigned max_nof_rbs_to_schedule = 273U; - const ue_pusch_grant grant1{.user = &u1, + const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, @@ -745,7 +754,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit static const unsigned sched_bytes = 20000U; const unsigned max_nof_rbs_to_schedule = 273U; - const ue_pdsch_grant grant1{.user = &u1, + const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes, @@ -769,7 +778,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit const unsigned recommended_nof_bytes_to_schedule = 200000U; const unsigned max_nof_rbs_to_schedule = 273U; - const ue_pusch_grant grant1{.user = &u1, + const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, From 8124f234ee0bf6069f1dd934711921b039f61d32 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 23 Jul 2024 17:55:05 +0100 Subject: [PATCH 046/407] rlc: add pull_pdu latency measurements --- include/srsran/rlc/rlc_tx_metrics.h | 12 +++++++++-- lib/rlc/rlc_tx_am_entity.cpp | 29 ++++++++++++++++++++++--- lib/rlc/rlc_tx_metrics_container.h | 12 +++++++++++ lib/rlc/rlc_tx_tm_entity.cpp | 15 ++++++++++--- lib/rlc/rlc_tx_um_entity.cpp | 33 ++++++++++++++++++++--------- 5 files changed, 83 insertions(+), 18 deletions(-) diff --git a/include/srsran/rlc/rlc_tx_metrics.h b/include/srsran/rlc/rlc_tx_metrics.h index a86fab3771..cb3b65520a 100644 --- a/include/srsran/rlc/rlc_tx_metrics.h +++ b/include/srsran/rlc/rlc_tx_metrics.h @@ -86,6 +86,7 @@ struct rlc_tx_metrics_lower { size_t num_pdu_bytes_no_segmentation; ///< Number of transmitted PDU bytes without segmentation uint32_t num_of_pulled_sdus; ///< Number of pulled SDUs uint32_t sum_sdu_latency_us; ///< total SDU latency (in us)> + uint32_t sum_pdu_latency_ns; ///< total PDU latency (in ns)> /// RLC mode of the entity rlc_mode mode; @@ -115,6 +116,7 @@ struct rlc_tx_metrics_lower { num_pdu_bytes_no_segmentation = {}; num_of_pulled_sdus = {}; sum_sdu_latency_us = {}; + sum_pdu_latency_ns = {}; // reset mode-specific values switch (mode) { @@ -181,7 +183,7 @@ inline std::string format_rlc_tx_metrics(timer_duration metrics_period, const rl } else if (m.tx_low.mode == rlc_mode::am) { fmt::format_to(buffer, " num_pdus_with_segm={} pdu_rate_with_segm={}bps num_retx={} " - "retx_rate={}bps ctrl_pdus={} ctrl_rate={}bps", + "retx_rate={}bps ctrl_pdus={} ctrl_rate={}bps pull_latency_avg={}", scaled_fmt_integer(m.tx_low.mode_specific.am.num_pdus_with_segmentation, false), float_to_eng_string(static_cast(m.tx_low.mode_specific.am.num_pdu_bytes_with_segmentation) * 8 * 1000 / metrics_period.count(), @@ -196,7 +198,13 @@ inline std::string format_rlc_tx_metrics(timer_duration metrics_period, const rl float_to_eng_string(static_cast(m.tx_low.mode_specific.am.num_ctrl_pdu_bytes) * 8 * 1000 / (double)metrics_period.count(), 1, - false)); + false), + float_to_eng_string( + static_cast(m.tx_low.sum_pdu_latency_ns * 1e-9) / + (m.tx_low.num_pdus_no_segmentation + m.tx_low.mode_specific.am.num_pdus_with_segmentation + + m.tx_low.mode_specific.am.num_retx_pdus + m.tx_low.mode_specific.am.num_ctrl_pdus), + 1, + false)); } return to_c_str(buffer); } diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index ab74c790c5..a929f679fe 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -134,6 +134,11 @@ void rlc_tx_am_entity::discard_sdu(uint32_t pdcp_sn) // TS 38.322 v16.2.0 Sec. 5.2.3.1 size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) { + std::chrono::time_point pull_begin; + if (metrics_low.is_enabled()) { + pull_begin = std::chrono::steady_clock::now(); + } + std::lock_guard lock(mutex); const size_t grant_len = rlc_pdu_buf.size(); @@ -162,13 +167,19 @@ size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) } logger.log_info(rlc_pdu_buf.data(), pdu_len, "TX status PDU. pdu_len={} grant_len={}", pdu_len, grant_len); - // Update metrics - metrics_low.metrics_add_ctrl_pdus(1, pdu_len); - // Log state log_state(srslog::basic_levels::debug); + // Write PCAP pcap.push_pdu(pcap_context, rlc_pdu_buf.subspan(0, pdu_len)); + + // Update metrics + metrics_low.metrics_add_ctrl_pdus(1, pdu_len); + if (metrics_low.is_enabled()) { + auto pdu_latency = + std::chrono::duration_cast(std::chrono::steady_clock::now() - pull_begin); + metrics_low.metrics_add_pdu_latency_ns(pdu_latency.count()); + } return pdu_len; } @@ -178,6 +189,13 @@ size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) size_t pdu_len = build_retx_pdu(rlc_pdu_buf); pcap.push_pdu(pcap_context, rlc_pdu_buf.subspan(0, pdu_len)); + + // Update metrics + if (metrics_low.is_enabled()) { + auto pdu_latency = + std::chrono::duration_cast(std::chrono::steady_clock::now() - pull_begin); + metrics_low.metrics_add_pdu_latency_ns(pdu_latency.count()); + } return pdu_len; } @@ -201,6 +219,11 @@ size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) size_t pdu_len = build_new_pdu(rlc_pdu_buf); pcap.push_pdu(pcap_context, rlc_pdu_buf.subspan(0, pdu_len)); + if (metrics_low.is_enabled()) { + auto pdu_latency = + std::chrono::duration_cast(std::chrono::steady_clock::now() - pull_begin); + metrics_low.metrics_add_pdu_latency_ns(pdu_latency.count()); + } return pdu_len; } diff --git a/lib/rlc/rlc_tx_metrics_container.h b/lib/rlc/rlc_tx_metrics_container.h index 4ce59b0275..56bacad682 100644 --- a/lib/rlc/rlc_tx_metrics_container.h +++ b/lib/rlc/rlc_tx_metrics_container.h @@ -22,6 +22,8 @@ class rlc_tx_metrics_high_container public: rlc_tx_metrics_high_container(bool enabled_) : enabled(enabled_) {} + bool is_enabled() const { return enabled; } + void metrics_add_sdus(uint32_t num_sdus, size_t num_sdu_bytes) { if (not enabled) { @@ -94,6 +96,8 @@ class rlc_tx_metrics_low_container public: rlc_tx_metrics_low_container(bool enabled_) : enabled(enabled_) {} + bool is_enabled() const { return enabled; } + void metrics_set_mode(rlc_mode mode) { if (not enabled) { @@ -127,6 +131,14 @@ class rlc_tx_metrics_low_container metrics_lo.sum_sdu_latency_us += sdu_latency; } + void metrics_add_pdu_latency_ns(uint32_t pdu_latency) + { + if (not enabled) { + return; + } + metrics_lo.sum_pdu_latency_ns += pdu_latency; + } + // TM specific metrics void metrics_add_small_alloc(uint32_t num_allocs) { diff --git a/lib/rlc/rlc_tx_tm_entity.cpp b/lib/rlc/rlc_tx_tm_entity.cpp index 796d169739..44ad204b3b 100644 --- a/lib/rlc/rlc_tx_tm_entity.cpp +++ b/lib/rlc/rlc_tx_tm_entity.cpp @@ -80,6 +80,10 @@ size_t rlc_tx_tm_entity::pull_pdu(span mac_sdu_buf) { size_t grant_len = mac_sdu_buf.size(); logger.log_debug("MAC opportunity. grant_len={}", grant_len); + std::chrono::time_point pull_begin; + if (metrics_high.is_enabled()) { + pull_begin = std::chrono::steady_clock::now(); + } // Get a new SDU, if none is currently being transmitted if (sdu.buf.empty()) { @@ -114,12 +118,17 @@ size_t rlc_tx_tm_entity::pull_pdu(span mac_sdu_buf) // Release SDU sdu.buf.clear(); - // Update metrics - metrics_low.metrics_add_pdus_no_segmentation(1, sdu_len); - // Push PDU into PCAP. pcap.push_pdu(pcap_context, mac_sdu_buf.subspan(0, pdu_len)); + // Update metrics + metrics_low.metrics_add_pdus_no_segmentation(1, sdu_len); + if (metrics_low.is_enabled()) { + std::chrono::time_point pull_end = std::chrono::steady_clock::now(); + auto pull_delta = std::chrono::duration_cast(pull_end - pull_begin); + metrics_low.metrics_add_pdu_latency_ns(pull_delta.count()); + } + return pdu_len; } diff --git a/lib/rlc/rlc_tx_um_entity.cpp b/lib/rlc/rlc_tx_um_entity.cpp index 66bd18b3d5..2a41332320 100644 --- a/lib/rlc/rlc_tx_um_entity.cpp +++ b/lib/rlc/rlc_tx_um_entity.cpp @@ -110,6 +110,11 @@ size_t rlc_tx_um_entity::pull_pdu(span mac_sdu_buf) uint32_t grant_len = mac_sdu_buf.size(); logger.log_debug("MAC opportunity. grant_len={}", grant_len); + std::chrono::time_point pull_begin; + if (metrics_low.is_enabled()) { + pull_begin = std::chrono::steady_clock::now(); + } + // Check available space -- we need at least the minimum header + 1 payload Byte if (grant_len <= head_len_full) { logger.log_debug("Cannot fit SDU into grant_len={}. head_len_full={}", grant_len, head_len_full); @@ -184,11 +189,13 @@ size_t rlc_tx_um_entity::pull_pdu(span mac_sdu_buf) // Release SDU if needed if (header.si == rlc_si_field::full_sdu || header.si == rlc_si_field::last_segment) { sdu.buf.clear(); - next_so = 0; - auto latency = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - - sdu.time_of_arrival); - metrics_low.metrics_add_sdu_latency_us(latency.count() / 1000); - metrics_low.metrics_add_pulled_sdus(1); + next_so = 0; + if (metrics_low.is_enabled()) { + auto sdu_latency = std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - sdu.time_of_arrival); + metrics_low.metrics_add_sdu_latency_us(sdu_latency.count() / 1000); + metrics_low.metrics_add_pulled_sdus(1); + } } else { // advance SO offset next_so += payload_len; @@ -199,17 +206,23 @@ size_t rlc_tx_um_entity::pull_pdu(span mac_sdu_buf) st.tx_next = (st.tx_next + 1) % mod; } + // Log state + log_state(srslog::basic_levels::debug); + + // Write PCAP + pcap.push_pdu(pcap_context, mac_sdu_buf.subspan(0, pdu_size)); + // Update metrics if (header.si == rlc_si_field::full_sdu) { metrics_low.metrics_add_pdus_no_segmentation(1, pdu_size); } else { metrics_low.metrics_add_pdus_with_segmentation_um(1, pdu_size); } - - // Log state - log_state(srslog::basic_levels::debug); - - pcap.push_pdu(pcap_context, mac_sdu_buf.subspan(0, pdu_size)); + if (metrics_low.is_enabled()) { + auto pdu_latency = + std::chrono::duration_cast(std::chrono::steady_clock::now() - pull_begin); + metrics_low.metrics_add_pdu_latency_ns(pdu_latency.count()); + } return pdu_size; } From 28a2f4b9dc03c5acfaa746b2d9aea3ecafc90404 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 24 Jul 2024 14:40:16 +0100 Subject: [PATCH 047/407] rlc: add pull pdu latency histogram --- include/srsran/rlc/rlc_tx_metrics.h | 11 +++++++++++ lib/rlc/rlc_tx_metrics_container.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/include/srsran/rlc/rlc_tx_metrics.h b/include/srsran/rlc/rlc_tx_metrics.h index cb3b65520a..7b9c791312 100644 --- a/include/srsran/rlc/rlc_tx_metrics.h +++ b/include/srsran/rlc/rlc_tx_metrics.h @@ -88,6 +88,11 @@ struct rlc_tx_metrics_lower { uint32_t sum_sdu_latency_us; ///< total SDU latency (in us)> uint32_t sum_pdu_latency_ns; ///< total PDU latency (in ns)> + // Histogram of pull pdus + static constexpr unsigned pdu_latency_hist_bins = 8; + constexpr static unsigned nof_usec_per_bin = 10; + std::array pdu_latency_hist_ns; + /// RLC mode of the entity rlc_mode mode; @@ -117,6 +122,7 @@ struct rlc_tx_metrics_lower { num_of_pulled_sdus = {}; sum_sdu_latency_us = {}; sum_pdu_latency_ns = {}; + pdu_latency_hist_ns = {}; // reset mode-specific values switch (mode) { @@ -206,6 +212,11 @@ inline std::string format_rlc_tx_metrics(timer_duration metrics_period, const rl 1, false)); } + fmt::format_to(buffer, " pdu_latency_hist=["); + for (unsigned i = 0; i < rlc_tx_metrics_lower::pdu_latency_hist_bins; i++) { + fmt::format_to(buffer, " {}", float_to_eng_string(m.tx_low.pdu_latency_hist_ns[i], 1, false)); + } + fmt::format_to(buffer, "] "); return to_c_str(buffer); } } // namespace srsran diff --git a/lib/rlc/rlc_tx_metrics_container.h b/lib/rlc/rlc_tx_metrics_container.h index 56bacad682..d0630bb53e 100644 --- a/lib/rlc/rlc_tx_metrics_container.h +++ b/lib/rlc/rlc_tx_metrics_container.h @@ -137,6 +137,11 @@ class rlc_tx_metrics_low_container return; } metrics_lo.sum_pdu_latency_ns += pdu_latency; + + unsigned bin_idx = pdu_latency / (1000 * rlc_tx_metrics_lower::nof_usec_per_bin); + + bin_idx = std::min(bin_idx, rlc_tx_metrics_lower::pdu_latency_hist_bins - 1); + metrics_lo.pdu_latency_hist_ns[bin_idx]++; } // TM specific metrics From 5a32c6e1b1b6085448f6b54ab36d4fb88a19b5d5 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 26 Jul 2024 11:15:48 +0100 Subject: [PATCH 048/407] rlc: keep track of mac pull_pdu latency --- include/srsran/rlc/rlc_tx_metrics.h | 4 +++- lib/rlc/rlc_tx_metrics_container.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/srsran/rlc/rlc_tx_metrics.h b/include/srsran/rlc/rlc_tx_metrics.h index 7b9c791312..4b4dde9d44 100644 --- a/include/srsran/rlc/rlc_tx_metrics.h +++ b/include/srsran/rlc/rlc_tx_metrics.h @@ -92,6 +92,7 @@ struct rlc_tx_metrics_lower { static constexpr unsigned pdu_latency_hist_bins = 8; constexpr static unsigned nof_usec_per_bin = 10; std::array pdu_latency_hist_ns; + uint32_t max_pdu_latency_ns; /// RLC mode of the entity rlc_mode mode; @@ -123,6 +124,7 @@ struct rlc_tx_metrics_lower { sum_sdu_latency_us = {}; sum_pdu_latency_ns = {}; pdu_latency_hist_ns = {}; + max_pdu_latency_ns = {}; // reset mode-specific values switch (mode) { @@ -216,7 +218,7 @@ inline std::string format_rlc_tx_metrics(timer_duration metrics_period, const rl for (unsigned i = 0; i < rlc_tx_metrics_lower::pdu_latency_hist_bins; i++) { fmt::format_to(buffer, " {}", float_to_eng_string(m.tx_low.pdu_latency_hist_ns[i], 1, false)); } - fmt::format_to(buffer, "] "); + fmt::format_to(buffer, "] max_pull_latency={}us", m.tx_low.max_pdu_latency_ns * 1e-3); return to_c_str(buffer); } } // namespace srsran diff --git a/lib/rlc/rlc_tx_metrics_container.h b/lib/rlc/rlc_tx_metrics_container.h index d0630bb53e..a111d0ab26 100644 --- a/lib/rlc/rlc_tx_metrics_container.h +++ b/lib/rlc/rlc_tx_metrics_container.h @@ -142,6 +142,8 @@ class rlc_tx_metrics_low_container bin_idx = std::min(bin_idx, rlc_tx_metrics_lower::pdu_latency_hist_bins - 1); metrics_lo.pdu_latency_hist_ns[bin_idx]++; + + metrics_lo.max_pdu_latency_ns = std::max(pdu_latency, metrics_lo.max_pdu_latency_ns); } // TM specific metrics From bae41d14ec4ca6264cdcbeacde76d01e5b96779b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 31 Jul 2024 15:20:22 +0200 Subject: [PATCH 049/407] du-high: add test for repeated cu-ue-f1ap-id during rrc reestablishment --- .../integrationtests/du_high/du_high_test.cpp | 48 ++++++++++++++++++ .../test_utils/du_high_env_simulator.cpp | 49 ++++++++++++++++--- .../test_utils/du_high_env_simulator.h | 6 ++- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index 230059e817..e386bff7c6 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -255,3 +255,51 @@ TEST_F(du_high_tester, when_ue_context_modification_with_rem_drbs_is_received_th ASSERT_EQ(cell_grp_cfg.rlc_bearer_to_release_list[0], 4) << "DRB1 with LCID=4 should have been removed"; } } + +TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_then_old_ue_traffic_stops) +{ + // Create UE1. + rnti_t rnti = to_rnti(0x4601); + ASSERT_TRUE(add_ue(rnti)); + ASSERT_TRUE(run_rrc_setup(rnti)); + ASSERT_TRUE(run_ue_context_setup(rnti)); + + // CU-UP forwards many DRB PDUs. + const unsigned nof_pdcp_pdus = 100, pdcp_pdu_size = 32; + for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { + nru_dl_message f1u_pdu{ + .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; + cu_up_sim.created_du_notifs[0]->on_new_pdu(f1u_pdu); + } + + // Send DL RRC Message Transfer with old gNB-DU-UE-F1AP-ID. + rnti_t rnti2 = to_rnti(0x4602); + ASSERT_TRUE(add_ue(rnti2)); + ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti)); + + ASSERT_FALSE(this->run_until( + [this, rnti]() { + const dl_msg_alloc* pdsch = find_ue_pdsch(rnti, phy.cells[0].last_dl_res.value().dl_res->ue_grants); + if (pdsch != nullptr and pdsch->pdsch_cfg.codewords[0].new_data) { + return true; + } + return false; + }, + 100)); +} + +TEST_F(du_high_tester, + when_dl_rrc_message_with_old_du_ue_id_received_but_same_cu_ue_f1ap_id_then_cu_ue_f1ap_id_is_reused) +{ + // Create UE1. + rnti_t rnti1 = to_rnti(0x4601); + ASSERT_TRUE(add_ue(rnti1)); + ASSERT_TRUE(run_rrc_setup(rnti1)); + ASSERT_TRUE(run_ue_context_setup(rnti1)); + + // Send DL RRC Message Transfer with old gNB-DU-UE-F1AP-ID and same gNB-CU-UE-F1AP-ID. + this->next_cu_ue_id--; + rnti_t rnti2 = to_rnti(0x4602); + ASSERT_TRUE(add_ue(rnti2)); + ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti1)); +} diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 6ae4a1748b..23be3d0f86 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -276,24 +276,58 @@ bool du_high_env_simulator::run_rrc_setup(rnti_t rnti) test_logger.error("rnti={}: Failed to run RRC Setup procedure. Cause: UE not found", rnti); return false; } - const ue_sim_context& u = it->second; - const auto& phy_cell = phy.cells[u.pcell_index]; + const ue_sim_context& u = it->second; // Send DL RRC Message which contains RRC Setup. f1ap_message msg = generate_dl_rrc_message_transfer( *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb0, byte_buffer::create({0x1, 0x2, 0x3}).value()); du_hi->get_f1ap_message_handler().handle_message(msg); + return run_msg4_and_await_msg5(u, msg); +} + +bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti) +{ + auto it = ues.find(rnti); + if (it == ues.end()) { + test_logger.error("rnti={}: Failed to run RRC Reestablishment. Cause: UE not found", rnti); + return false; + } + const ue_sim_context& u = it->second; + auto old_it = ues.find(old_rnti); + if (old_it == ues.end()) { + test_logger.error( + "rnti={}: Failed to run RRC Reestablishment. Cause: Old UE with c-rnti={} not found", rnti, old_rnti); + return false; + } + const ue_sim_context& old_u = old_it->second; + + f1ap_message msg = generate_dl_rrc_message_transfer( + *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb1, byte_buffer::create({0x1, 0x2, 0x3}).value()); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id_present = true; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id = (uint64_t)old_u.du_ue_id.value(); + + return run_msg4_and_await_msg5(u, msg); +} + +bool du_high_env_simulator::run_msg4_and_await_msg5(const ue_sim_context& u, const f1ap_message& msg) +{ + const auto& phy_cell = phy.cells[u.pcell_index]; + + du_hi->get_f1ap_message_handler().handle_message(msg); + + lcid_t msg4_lcid = msg.pdu.init_msg().value.dl_rrc_msg_transfer()->srb_id == 0 ? LCID_SRB0 : LCID_SRB1; + // Wait for Msg4 to be sent to the PHY. bool ret = run_until([&]() { if (phy_cell.last_dl_res.has_value() and phy_cell.last_dl_res.value().dl_res != nullptr) { auto& dl_res = *phy_cell.last_dl_res.value().dl_res; - return find_ue_pdsch_with_lcid(rnti, LCID_SRB0, dl_res.ue_grants) != nullptr; + return find_ue_pdsch_with_lcid(u.rnti, msg4_lcid, dl_res.ue_grants) != nullptr; } return false; }); if (not ret) { - test_logger.error("rnti={}: Msg4 not sent to the PHY", rnti); + test_logger.error("rnti={}: Msg4 not sent to the PHY", u.rnti); return false; } @@ -303,15 +337,16 @@ bool du_high_env_simulator::run_rrc_setup(rnti_t rnti) run_slot(); } - // UE sends RRC Setup Complete. Wait until F1AP forwards UL RRC Message to CU-CP. + // UE sends Msg5. Wait until F1AP forwards UL RRC Message to CU-CP. cu_notifier.last_f1ap_msgs.clear(); du_hi->get_pdu_handler().handle_rx_data_indication( - test_helpers::create_pdu_with_sdu(next_slot, rnti, lcid_t::LCID_SRB1)); + test_helpers::create_pdu_with_sdu(next_slot, u.rnti, lcid_t::LCID_SRB1)); ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); if (not ret or not test_helpers::is_ul_rrc_msg_transfer_valid(cu_notifier.last_f1ap_msgs.back(), srb_id_t::srb1)) { - test_logger.error("rnti={}: F1AP UL RRC Message (containing rrcSetupComplete) not sent or is invalid", rnti); + test_logger.error("rnti={}: F1AP UL RRC Message (containing Msg5) not sent or is invalid", u.rnti); return false; } + return true; } diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index 05234afaf2..f550183cc8 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -57,6 +57,8 @@ class du_high_env_simulator /// Transfer) until the CU receives the RRC Setup Complete (via UL RRC Message Transfer). bool run_rrc_setup(rnti_t rnti); + bool run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti); + bool run_ue_context_setup(rnti_t rnti); void run_slot(); @@ -80,7 +82,7 @@ class du_high_env_simulator srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); -private: +protected: struct ue_sim_context { struct srb_context { uint32_t next_pdcp_sn = 0; @@ -93,6 +95,8 @@ class du_high_env_simulator std::array srbs; }; + bool run_msg4_and_await_msg5(const ue_sim_context& u, const f1ap_message& msg); + std::unordered_map ues; unsigned next_cu_ue_id = 0; From ef987a840f6e2a09f393e79ea164a474c86cdcd6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 31 Jul 2024 15:51:19 +0200 Subject: [PATCH 050/407] f1ap-du: implement new unit tests for dl rrc message transfer dealing with repeated gnb-cu-ue-f1ap-id --- .../f1ap_du_dl_rrc_message_transfer_test.cpp | 118 ++++++++++++++++++ .../f1ap/du/f1ap_du_test_helpers.cpp | 3 + .../unittests/f1ap/du/f1ap_du_test_helpers.h | 14 ++- 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp b/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp index e103116f07..4abceb36ed 100644 --- a/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp @@ -48,3 +48,121 @@ TEST_F(f1ap_du_test, when_dl_rrc_message_transfer_is_received_gnb_cu_ue_f1ap_id_ msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id) << "Invalid gNB-CU UE F1AP ID"; } + +TEST_F(f1ap_du_test, + when_dl_rrc_message_transfer_contains_cu_ue_id_that_does_not_match_then_error_indication_is_sent_to_cu) +{ + // Run Test Preamble. + run_f1_setup_procedure(); + // > create UE1 + ue_test_context* ue1 = run_f1ap_ue_create(to_du_ue_index(0)); + ASSERT_NE(ue1, nullptr); + // > run DL rrc message for UE1 that will set the gnb-cu-ue-f1ap-id. + byte_buffer test_rrc_msg = byte_buffer::create({0x1, 0x2, 0x3}).value(); + f1ap_message msg = generate_f1ap_dl_rrc_message_transfer(srb_id_t::srb1, test_rrc_msg); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id = 0; + ASSERT_TRUE(ue1->f1c_bearers[1].rx_sdu_notifier.last_pdu.empty()); + f1ap->handle_message(msg); + ASSERT_FALSE(ue1->f1c_bearers[1].rx_sdu_notifier.last_pdu.empty()); + // > send DL RRC Message with invalid gNB CU UE F1AP ID. + ue1->f1c_bearers[1].rx_sdu_notifier.last_pdu.clear(); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id = 1; + f1ap->handle_message(msg); + + // Test Section + + // > No RRC container is forwarded. + ASSERT_TRUE(ue1->f1c_bearers[1].rx_sdu_notifier.last_pdu.empty()); + // > Error Indication is sent to CU. + ASSERT_EQ(f1c_gw.last_tx_f1ap_pdu.pdu.init_msg().value.type().value, + asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::error_ind); + const auto& err_ind = f1c_gw.last_tx_f1ap_pdu.pdu.init_msg().value.error_ind(); + ASSERT_TRUE(err_ind->gnb_du_ue_f1ap_id_present); + ASSERT_EQ(err_ind->gnb_du_ue_f1ap_id, 0); + ASSERT_TRUE(err_ind->cause_present); + ASSERT_EQ(err_ind->cause.radio_network().value, + asn1::f1ap::cause_radio_network_opts::unknown_or_already_allocated_gnb_cu_ue_f1ap_id); +} + +TEST_F(f1ap_du_test, + when_dl_rrc_message_transfer_with_old_gnb_du_ue_id_then_du_is_notified_and_rrc_container_is_forwarded) +{ + // Run Test Preamble. + run_f1_setup_procedure(); + // > create UE1 + ue_test_context* ue1 = run_f1ap_ue_create(to_du_ue_index(0)); + ASSERT_NE(ue1, nullptr); + // > run DL rrc message for UE1 that will set the gnb-cu-ue-f1ap-id. + byte_buffer test_rrc_msg = byte_buffer::create({0x1, 0x2, 0x3}).value(); + f1ap_message msg = generate_f1ap_dl_rrc_message_transfer(srb_id_t::srb0, test_rrc_msg); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id = 0; + f1ap->handle_message(msg); + // > create UE2 + ue_test_context* ue2 = run_f1ap_ue_create(to_du_ue_index(1)); + ASSERT_NE(ue2, nullptr); + // > Send DL RRC Message Transfer for UE2 (containing old gNB DU UE ID). + msg = generate_f1ap_dl_rrc_message_transfer(srb_id_t::srb1, test_rrc_msg); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_du_ue_f1ap_id = 1; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id = 1; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id_present = true; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id = 0; + ASSERT_FALSE(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.has_value()); + f1ap->handle_message(msg); + + // Test Section. + + // > DU was notified of reestablishment. + ASSERT_TRUE(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.has_value()); + ASSERT_EQ(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.value().first, to_du_ue_index(1)); + ASSERT_EQ(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.value().second, to_du_ue_index(0)); + + // > RRC container is forwarded. + ASSERT_FALSE(ue2->f1c_bearers[1].rx_sdu_notifier.last_pdu.empty()); + ASSERT_EQ(ue2->f1c_bearers[1].rx_sdu_notifier.last_pdu, test_rrc_msg); + + // > gNB-CU-UE-F1AP-Id is updated. + ue2->f1c_bearers[1].bearer->handle_sdu(byte_buffer_chain::create(test_rrc_msg.copy()).value()); + ASSERT_EQ(f1c_gw.last_tx_f1ap_pdu.pdu.init_msg().value.ul_rrc_msg_transfer()->gnb_cu_ue_f1ap_id, + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id) + << "Invalid gNB-CU UE F1AP ID"; +} + +TEST_F(f1ap_du_test, when_dl_rrc_message_transfer_has_duplicate_cu_ue_id_and_old_gnb_du_ue_id_then_cu_ue_id_is_updated) +{ + // Run Test Preamble. + run_f1_setup_procedure(); + // > create UE1 + ue_test_context* ue1 = run_f1ap_ue_create(to_du_ue_index(0)); + ASSERT_NE(ue1, nullptr); + // > run DL rrc message for UE1 that will set the gnb-cu-ue-f1ap-id. + byte_buffer test_rrc_msg = byte_buffer::create({0x1, 0x2, 0x3}).value(); + f1ap_message msg = generate_f1ap_dl_rrc_message_transfer(srb_id_t::srb0, test_rrc_msg); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id = 5; + f1ap->handle_message(msg); + // > create UE2 + ue_test_context* ue2 = run_f1ap_ue_create(to_du_ue_index(1)); + ASSERT_NE(ue2, nullptr); + // > Send DL RRC Message Transfer for UE2 (containing old gNB DU UE ID). + msg = generate_f1ap_dl_rrc_message_transfer(srb_id_t::srb1, test_rrc_msg); + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_du_ue_f1ap_id = 1; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id = 5; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id_present = true; + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id = 0; + ASSERT_FALSE(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.has_value()); + f1ap->handle_message(msg); + + // Test Section. + + // > DU was notified of reestablishment. + ASSERT_TRUE(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.has_value()); + ASSERT_EQ(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.value().first, to_du_ue_index(1)); + ASSERT_EQ(this->f1ap_du_cfg_handler.last_reestablishment_ue_indexes.value().second, to_du_ue_index(0)); + // > RRC container is forwarded. + ASSERT_FALSE(ue2->f1c_bearers[1].rx_sdu_notifier.last_pdu.empty()); + ASSERT_EQ(ue2->f1c_bearers[1].rx_sdu_notifier.last_pdu, test_rrc_msg); + // > gNB-CU-UE-F1AP-Id is updated. + ue2->f1c_bearers[1].bearer->handle_sdu(byte_buffer_chain::create(test_rrc_msg.copy()).value()); + ASSERT_EQ(f1c_gw.last_tx_f1ap_pdu.pdu.init_msg().value.ul_rrc_msg_transfer()->gnb_cu_ue_f1ap_id, + msg.pdu.init_msg().value.dl_rrc_msg_transfer()->gnb_cu_ue_f1ap_id) + << "Invalid gNB-CU UE F1AP ID"; +} \ No newline at end of file diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index 8d0e176c43..faef15e77b 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -260,10 +260,13 @@ void f1ap_du_test::run_f1_removal_procedure() f1ap_du_test::ue_test_context* f1ap_du_test::run_f1ap_ue_create(du_ue_index_t ue_index) { + unsigned srb0_idx = srb_id_to_uint(srb_id_t::srb0); unsigned srb1_idx = srb_id_to_uint(srb_id_t::srb1); test_ues.emplace(ue_index); test_ues[ue_index].crnti = to_rnti(0x4601 + ue_index); test_ues[ue_index].ue_index = ue_index; + test_ues[ue_index].f1c_bearers.emplace(srb_id_to_uint(srb_id_t::srb0)); + test_ues[ue_index].f1c_bearers[srb0_idx].srb_id = srb_id_t::srb0; test_ues[ue_index].f1c_bearers.emplace(srb_id_to_uint(srb_id_t::srb1)); test_ues[ue_index].f1c_bearers[srb1_idx].srb_id = srb_id_t::srb1; diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.h b/tests/unittests/f1ap/du/f1ap_du_test_helpers.h index e1eefa4529..025f022c46 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.h +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.h @@ -49,10 +49,11 @@ class dummy_f1ap_du_configurator : public f1ap_du_configurator f1ap_du* f1ap; // DU manager -> F1AP. - f1ap_ue_creation_request next_ue_creation_req; - std::optional last_ue_creation_response; - f1ap_ue_configuration_request next_ue_cfg_req; - std::optional last_ue_cfg_response; + f1ap_ue_creation_request next_ue_creation_req; + std::optional last_ue_creation_response; + f1ap_ue_configuration_request next_ue_cfg_req; + std::optional last_ue_cfg_response; + std::optional> last_reestablishment_ue_indexes; // F1AP procedures. std::optional last_ue_context_creation_req; @@ -109,7 +110,10 @@ class dummy_f1ap_du_configurator : public f1ap_du_configurator async_task request_ue_drb_deactivation(du_ue_index_t ue_index) override { return launch_no_op_task(); } - void notify_reestablishment_of_old_ue(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) override {} + void notify_reestablishment_of_old_ue(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) override + { + last_reestablishment_ue_indexes = std::make_pair(new_ue_index, old_ue_index); + } /// \brief Retrieve task scheduler specific to a given UE. f1ap_ue_task_scheduler& get_ue_handler(du_ue_index_t ue_index) override { return ue_sched; } From 0b8bc9179f6e4873a06d7df6593c4d0d0d732d35 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 31 Jul 2024 16:55:45 +0200 Subject: [PATCH 051/407] f1ap-du: send error indication when the ue-f1ap-id pair is inconsistent --- lib/f1ap/du/f1ap_du_impl.cpp | 46 ++++++++++++++++--- lib/f1ap/du/f1ap_du_impl.h | 5 +- .../f1ap_du_dl_rrc_message_transfer_test.cpp | 2 +- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/lib/f1ap/du/f1ap_du_impl.cpp b/lib/f1ap/du/f1ap_du_impl.cpp index c088bafca3..7e74e29f23 100644 --- a/lib/f1ap/du/f1ap_du_impl.cpp +++ b/lib/f1ap/du/f1ap_du_impl.cpp @@ -417,8 +417,6 @@ bool f1ap_du_impl::handle_rx_message_gnb_cu_ue_f1ap_id(f1ap_du_ue& ue, gnb_cu_ue return true; } - // [TS38.473, Cause IE] The action failed because the gNB-CU UE F1AP ID is either unknown, or (for a first - // message received at the gNB-CU) is known and already allocated to an existing context. const f1ap_du_ue* ue_cu_id = ues.find(gnb_cu_ue_f1ap_id); if (ue.context.gnb_cu_ue_f1ap_id == gnb_cu_ue_f1ap_id_t::invalid and ue_cu_id == nullptr) { // First message from the gNB-CU for this UE. Update gNB-CU-UE-F1AP-ID. @@ -426,22 +424,56 @@ bool f1ap_du_impl::handle_rx_message_gnb_cu_ue_f1ap_id(f1ap_du_ue& ue, gnb_cu_ue return true; } cause_c cause; - cause.set_radio_network().value = cause_radio_network_opts::unknown_or_already_allocated_gnb_cu_ue_f1ap_id; if (ue_cu_id == nullptr) { - logger.warning("Discarding message cause=gNB-CU UE F1AP ID={} is unknown"); + cause.set_radio_network().value = cause_radio_network_opts::unknown_or_inconsistent_pair_of_ue_f1ap_id; + logger.warning("Discarding message. Cause: gNB-CU UE F1AP ID={} does not match existing context", + gnb_cu_ue_f1ap_id); } else { + // [TS38.473, Cause IE] The action failed because the gNB-CU UE F1AP ID is either unknown, or (for a first + // message received at the gNB-CU) is known and already allocated to an existing context. + cause.set_radio_network().value = cause_radio_network_opts::unknown_or_already_allocated_gnb_cu_ue_f1ap_id; logger.warning("Discarding message cause=gNB-CU UE F1AP ID={} is known and already allocated to an existing " "context with gNB-DU UE F1AP ID={}", gnb_cu_ue_f1ap_id, ue_cu_id->context.gnb_du_ue_f1ap_id); } - send_error_indication(cause); + send_error_indication(cause, std::nullopt, ue.context.gnb_du_ue_f1ap_id, ue.context.gnb_cu_ue_f1ap_id); return false; } -void f1ap_du_impl::send_error_indication(const asn1::f1ap::cause_c& cause) +void f1ap_du_impl::send_error_indication(const asn1::f1ap::cause_c& cause, + std::optional transaction_id, + std::optional du_ue_id, + std::optional cu_ue_id) { - // TODO + f1ap_message msg; + msg.pdu.set_init_msg().load_info_obj(ASN1_F1AP_ID_ERROR_IND); + auto& err_ind = msg.pdu.init_msg().value.error_ind(); + + if (transaction_id.has_value()) { + err_ind->transaction_id = transaction_id.value(); + } else { + auto transaction = events->transactions.create_transaction(); + err_ind->transaction_id = transaction.id(); + } + + // Set cause. + err_ind->cause_present = true; + err_ind->cause = cause; + + // [TS 38.473, 8.2.2.2] In case the Error Indication procedure is triggered by utilising UE associated signalling + // the gNB-CU UE F1AP ID IE and gNBDU UE F1AP ID IE shall be included in the ERROR INDICATION message. + err_ind->gnb_cu_ue_f1ap_id_present = cu_ue_id.has_value(); + if (err_ind->gnb_cu_ue_f1ap_id_present) { + err_ind->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(*cu_ue_id); + } + err_ind->gnb_du_ue_f1ap_id_present = du_ue_id.has_value(); + if (err_ind->gnb_du_ue_f1ap_id_present) { + err_ind->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(*du_ue_id); + } + + // Send message to CU. + tx_pdu_notifier->on_new_message(msg); } void f1ap_du_impl::handle_paging_request(const asn1::f1ap::paging_s& msg) diff --git a/lib/f1ap/du/f1ap_du_impl.h b/lib/f1ap/du/f1ap_du_impl.h index fea3545862..e67caa2ee6 100644 --- a/lib/f1ap/du/f1ap_du_impl.h +++ b/lib/f1ap/du/f1ap_du_impl.h @@ -98,7 +98,10 @@ class f1ap_du_impl final : public f1ap_du bool handle_rx_message_gnb_cu_ue_f1ap_id(f1ap_du_ue& ue, gnb_cu_ue_f1ap_id_t cu_ue_id); - void send_error_indication(const asn1::f1ap::cause_c& cause); + void send_error_indication(const asn1::f1ap::cause_c& cause, + std::optional transaction_id = {}, + std::optional du_ue_id = {}, + std::optional cu_ue_id = {}); /// \brief Handle Paging as per TS38.473, Section 8.7. void handle_paging_request(const asn1::f1ap::paging_s& msg); diff --git a/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp b/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp index 4abceb36ed..7acafc66e7 100644 --- a/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_dl_rrc_message_transfer_test.cpp @@ -81,7 +81,7 @@ TEST_F(f1ap_du_test, ASSERT_EQ(err_ind->gnb_du_ue_f1ap_id, 0); ASSERT_TRUE(err_ind->cause_present); ASSERT_EQ(err_ind->cause.radio_network().value, - asn1::f1ap::cause_radio_network_opts::unknown_or_already_allocated_gnb_cu_ue_f1ap_id); + asn1::f1ap::cause_radio_network_opts::unknown_or_inconsistent_pair_of_ue_f1ap_id); } TEST_F(f1ap_du_test, From 43223cdec61e03f739117165366a46f8a40b91a5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 31 Jul 2024 17:09:52 +0200 Subject: [PATCH 052/407] f1ap-du: fix handling of repeated gnb-cu-ue-f1ap-id during rrc reestablishment --- lib/f1ap/du/f1ap_du_impl.cpp | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/f1ap/du/f1ap_du_impl.cpp b/lib/f1ap/du/f1ap_du_impl.cpp index 7e74e29f23..486cb7e749 100644 --- a/lib/f1ap/du/f1ap_du_impl.cpp +++ b/lib/f1ap/du/f1ap_du_impl.cpp @@ -211,7 +211,7 @@ void f1ap_du_impl::handle_dl_rrc_message_transfer(const asn1::f1ap::dl_rrc_msg_t gnb_du_ue_f1ap_id_t gnb_du_ue_f1ap_id = int_to_gnb_du_ue_f1ap_id(msg->gnb_du_ue_f1ap_id); // [TS38.473, 8.4.2.2.] If a UE-associated logical F1-connection exists, the DL RRC MESSAGE TRANSFER message shall - // contain the gNBDU UE F1AP ID IE, which should be used by gNB-DU to lookup the stored UE context. + // contain the gNB DU UE F1AP ID IE, which should be used by gNB-DU to lookup the stored UE context. f1ap_du_ue* ue = ues.find(gnb_du_ue_f1ap_id); if (ue == nullptr) { @@ -223,6 +223,25 @@ void f1ap_du_impl::handle_dl_rrc_message_transfer(const asn1::f1ap::dl_rrc_msg_t return; } + if (msg->old_gnb_du_ue_f1ap_id_present) { + // [TS38.473, 8.4.2.2] If the gNB-DU identifies the UE-associated logical F1-connection by the gNB-DU UE F1AP ID IE + // in the DL RRC MESSAGE TRANSFER message and the old gNB-DU UE F1AP ID IE is included, it shall release the old + // gNB-DU UE F1AP ID and the related configurations associated with the old gNB-DU UE F1AP ID. + const gnb_du_ue_f1ap_id_t old_gnb_du_ue_f1ap_id = int_to_gnb_du_ue_f1ap_id(msg->old_gnb_du_ue_f1ap_id); + f1ap_du_ue* old_ue = ues.find(old_gnb_du_ue_f1ap_id); + if (old_ue != nullptr) { + // Delete gNB-CU-UE-F1AP-Id so that the UE is not reachable by the CU, and the gNB-CU-UE-F1AP-Id can be reused. + old_ue->context.gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_t::invalid; + // Mark the old UE so that no UE context release procedure gets initiated. + old_ue->context.marked_for_release = true; + + // Notify DU that the old UE needs to be released. + du_mng.notify_reestablishment_of_old_ue(ue->context.ue_index, old_ue->context.ue_index); + } else { + logger.warning("old gNB-DU UE F1AP ID={} not found", old_gnb_du_ue_f1ap_id); + } + } + // Handle gNB-CU UE F1AP ID. if (not handle_rx_message_gnb_cu_ue_f1ap_id(*ue, int_to_gnb_cu_ue_f1ap_id(msg->gnb_cu_ue_f1ap_id))) { return; @@ -235,19 +254,6 @@ void f1ap_du_impl::handle_dl_rrc_message_transfer(const asn1::f1ap::dl_rrc_msg_t ue->context.gnb_cu_ue_f1ap_id = int_to_gnb_cu_ue_f1ap_id(msg->new_gnb_cu_ue_f1ap_id); } - if (msg->old_gnb_du_ue_f1ap_id_present) { - // > If the gNB-DU identifies the UE-associated logical F1-connection by the gNB-DU UE F1AP ID IE in the - // DL RRC MESSAGE TRANSFER message and the old gNB-DU UE F1AP ID IE is included, it shall release the old gNB-DU - // UE F1AP ID and the related configurations associated with the old gNB-DU UE F1AP ID. - const gnb_du_ue_f1ap_id_t old_gnb_du_ue_f1ap_id = int_to_gnb_du_ue_f1ap_id(msg->old_gnb_du_ue_f1ap_id); - f1ap_du_ue* old_ue = ues.find(old_gnb_du_ue_f1ap_id); - if (old_ue != nullptr) { - du_mng.notify_reestablishment_of_old_ue(ue->context.ue_index, old_ue->context.ue_index); - } else { - logger.warning("old gNB-DU UE F1AP ID={} not found", old_gnb_du_ue_f1ap_id); - } - } - if (ue->context.rrc_state == f1ap_ue_context::ue_rrc_state::no_config and not msg->old_gnb_du_ue_f1ap_id_present) { // If the UE has no dedicated configuration yet, we assume that this DL RRC Message Transfer contains it (e.g. // RRC Setup or RRC Reconfiguration). The only exception is when this DL RRC Message Transfer is an RRC @@ -259,18 +265,15 @@ void f1ap_du_impl::handle_dl_rrc_message_transfer(const asn1::f1ap::dl_rrc_msg_t const srb_id_t srb_id = int_to_srb_id(msg->srb_id); f1c_bearer* srb_bearer = ue->bearers.find_srb(srb_id); if (srb_bearer == nullptr) { - logger.warning("Discarding DlRrcMessageTransfer cause=SRB-ID={} not found", srb_id); - // TODO: Handle error. + logger.warning("Discarding DLRRCMessageTransfer cause=SRB-ID={} not found", srb_id); + cause_c cause; + cause.set_radio_network().value = asn1::f1ap::cause_radio_network_opts::no_radio_res_available; + send_error_indication(cause, std::nullopt, gnb_du_ue_f1ap_id, ue->context.gnb_cu_ue_f1ap_id); return; } // Forward SDU to lower layers. - byte_buffer sdu; - if (not sdu.append(msg->rrc_container)) { - logger.error("Discarding DlRrcMessageTransfer, could not append RRC container to SDU. srb_id={}", srb_id); - return; - } - srb_bearer->handle_pdu(std::move(sdu)); + srb_bearer->handle_pdu(msg->rrc_container.copy()); } void f1ap_du_impl::handle_ue_context_release_request(const f1ap_ue_context_release_request& request) From 06b46de13d639e76c677c928596f1cf09f348e9b Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 1 Aug 2024 13:04:33 +0100 Subject: [PATCH 053/407] rlc: remove old lock based RLC queue --- lib/rlc/rlc_sdu_queue.h | 138 ----------------- tests/unittests/rlc/CMakeLists.txt | 5 - tests/unittests/rlc/rlc_sdu_queue_test.cpp | 172 --------------------- 3 files changed, 315 deletions(-) delete mode 100644 lib/rlc/rlc_sdu_queue.h delete mode 100644 tests/unittests/rlc/rlc_sdu_queue_test.cpp diff --git a/lib/rlc/rlc_sdu_queue.h b/lib/rlc/rlc_sdu_queue.h deleted file mode 100644 index d59b4d1f94..0000000000 --- a/lib/rlc/rlc_sdu_queue.h +++ /dev/null @@ -1,138 +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/blocking_queue.h" -#include "srsran/adt/byte_buffer.h" -#include "srsran/rlc/rlc_tx.h" -#include "fmt/format.h" -#include -#include - -namespace srsran { - -/// This class will hold RLC SDUs from upper layers. -/// It provides methods for thread-safe read/writing of SDUs -/// and discarding SDUs, if requested by the higher layers. -class rlc_sdu_queue -{ -public: - explicit rlc_sdu_queue(uint16_t capacity_ = 4096) : - capacity(capacity_), queue(capacity_, push_callback(unread_bytes, n_sdus), pop_callback(unread_bytes, n_sdus)) - { - } - - bool write(rlc_sdu sdu) - { - if (queue.size() >= capacity) { - return false; - } - queue.push_blocking(std::move(sdu)); - return true; - } - - bool read(rlc_sdu& sdu) - { - // The SDU byte_buffer might be empty, due to having been discarded. - // We try to read the next one if that is the case. - std::optional popped_elem = - queue.pop_and_discard_until([](const rlc_sdu& elem) { return not elem.buf.empty(); }); - if (popped_elem.has_value()) { - sdu = std::move(*popped_elem); - return true; - } - return false; - } - - uint32_t size_sdus() const { return n_sdus; } - - uint32_t size_bytes() const { return unread_bytes; } - - bool front_size_bytes(uint32_t& size) - { - return queue.try_call_on_front([&size](const rlc_sdu& sdu) { size = sdu.buf.length(); }); - } - - bool is_empty() { return queue.empty(); } - - bool is_full() { return queue.size() >= capacity; } - - // Marks a packet as discarded by calling `clear` on it. - bool discard(uint32_t pdcp_sn) - { - bool discarded = queue.apply_first([&pdcp_sn, this](rlc_sdu& sdu) { - if (!sdu.buf.empty() && sdu.pdcp_sn == pdcp_sn) { - queue.pop_func(sdu); - sdu.buf.clear(); - return true; - } - return false; - }); - return discarded; - } - -private: - struct push_callback { - explicit push_callback(std::atomic& unread_bytes_, std::atomic& n_sdus_) : - unread_bytes(unread_bytes_), n_sdus(n_sdus_) - { - } - void operator()(const rlc_sdu& sdu) - { - unread_bytes.fetch_add(sdu.buf.length(), std::memory_order_relaxed); - n_sdus.fetch_add(1, std::memory_order_relaxed); - } - std::atomic& unread_bytes; - std::atomic& n_sdus; - }; - struct pop_callback { - explicit pop_callback(std::atomic& unread_bytes_, std::atomic& n_sdus_) : - unread_bytes(unread_bytes_), n_sdus(n_sdus_) - { - } - void operator()(const rlc_sdu& sdu) - { - if (sdu.buf.empty()) { - return; - } - // non-atomic update of both state variables - unread_bytes.fetch_sub(std::min((uint32_t)sdu.buf.length(), unread_bytes.load(std::memory_order_relaxed)), - std::memory_order_relaxed); - n_sdus.store(std::max(0, (int32_t)(n_sdus.load(std::memory_order_relaxed)) - 1), std::memory_order_relaxed); - } - std::atomic& unread_bytes; - std::atomic& n_sdus; - }; - uint16_t capacity = 256; - std::atomic unread_bytes = {0}; - std::atomic n_sdus = {0}; - - blocking_queue queue; -}; - -} // namespace srsran - -namespace fmt { -template <> -struct formatter { - template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) - { - return ctx.begin(); - } - - template - auto format(const srsran::rlc_sdu_queue& q, FormatContext& ctx) -> decltype(std::declval().out()) - { - return format_to(ctx.out(), "queued_sdus={} queued_bytes={}", q.size_sdus(), q.size_bytes()); - } -}; -} // namespace fmt diff --git a/tests/unittests/rlc/CMakeLists.txt b/tests/unittests/rlc/CMakeLists.txt index 7023f5a014..c215d74dc8 100644 --- a/tests/unittests/rlc/CMakeLists.txt +++ b/tests/unittests/rlc/CMakeLists.txt @@ -48,11 +48,6 @@ target_link_libraries(rlc_pdu_recycler_test srsran_instrumentation srsran_suppor target_include_directories(rlc_pdu_recycler_test PRIVATE ${CMAKE_SOURCE_DIR}) gtest_discover_tests(rlc_pdu_recycler_test) -add_executable(rlc_sdu_queue_test rlc_sdu_queue_test.cpp) -target_link_libraries(rlc_sdu_queue_test srsran_support srslog) -target_include_directories(rlc_sdu_queue_test PRIVATE ${CMAKE_SOURCE_DIR}) -add_test(rlc_sdu_queue_test rlc_sdu_queue_test) - add_executable(rlc_sdu_queue_lockfree_test rlc_sdu_queue_lockfree_test.cpp) target_link_libraries(rlc_sdu_queue_lockfree_test srsran_support srslog) target_include_directories(rlc_sdu_queue_lockfree_test PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/tests/unittests/rlc/rlc_sdu_queue_test.cpp b/tests/unittests/rlc/rlc_sdu_queue_test.cpp deleted file mode 100644 index cc21bcb3a0..0000000000 --- a/tests/unittests/rlc/rlc_sdu_queue_test.cpp +++ /dev/null @@ -1,172 +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 "lib/rlc/rlc_sdu_queue.h" -#include "srsran/adt/byte_buffer.h" -#include "srsran/support/test_utils.h" - -namespace srsran { - -void queue_unqueue_test() -{ - test_delimit_logger delimiter{"RLC SDU queue unqueue test"}; - rlc_sdu_queue tx_queue; - - // Write 1 SDU - byte_buffer buf = byte_buffer::create({0x00, 0x01}).value(); - rlc_sdu write_sdu = {std::move(buf), 10}; - TESTASSERT(tx_queue.write(std::move(write_sdu))); - - // Check basic stats - TESTASSERT_EQ(1, tx_queue.size_sdus()); - TESTASSERT_EQ(2, tx_queue.size_bytes()); - - // Read one SDU - rlc_sdu read_sdu; - TESTASSERT(tx_queue.read(read_sdu)); - - // Check basic stats - TESTASSERT_EQ(0, tx_queue.size_sdus()); - TESTASSERT_EQ(0, tx_queue.size_bytes()); - - // Check SDU - byte_buffer expected_msg = byte_buffer::create({0x00, 0x01}).value(); - TESTASSERT(read_sdu.pdcp_sn.has_value()); - TESTASSERT_EQ(10, read_sdu.pdcp_sn.value()); - TESTASSERT(expected_msg == read_sdu.buf); -} - -void full_capacity_test() -{ - test_delimit_logger delimiter{"RLC SDU capacity test"}; - unsigned capacity = 5; - rlc_sdu_queue tx_queue(capacity); - - // Write Capacity + 1 SDUs - for (uint32_t pdcp_sn = 0; pdcp_sn < capacity + 1; pdcp_sn++) { - byte_buffer buf = {}; - TESTASSERT(buf.append(pdcp_sn)); - TESTASSERT(buf.append(pdcp_sn)); - rlc_sdu write_sdu = {std::move(buf), pdcp_sn}; - if (pdcp_sn != capacity) { - TESTASSERT(tx_queue.write(std::move(write_sdu)) == true); - } else { - TESTASSERT(tx_queue.write(std::move(write_sdu)) == false); - } - } - TESTASSERT_EQ(capacity, tx_queue.size_sdus()); - TESTASSERT_EQ(2 * capacity, tx_queue.size_bytes()); - - // Read all SDUs and try to read on SDU over capacity - for (uint32_t pdcp_sn = 0; pdcp_sn < capacity + 1; pdcp_sn++) { - byte_buffer expected_msg = {}; - TESTASSERT(expected_msg.append(pdcp_sn)); - TESTASSERT(expected_msg.append(pdcp_sn)); - rlc_sdu read_sdu = {}; - if (pdcp_sn != capacity) { - TESTASSERT(tx_queue.read(read_sdu)); - TESTASSERT(expected_msg == read_sdu.buf); - } else { - TESTASSERT(false == tx_queue.read(read_sdu)); - } - } - - TESTASSERT_EQ(0, tx_queue.size_sdus()); - TESTASSERT_EQ(0, tx_queue.size_bytes()); -} - -void discard_test() -{ - test_delimit_logger delimiter{"RLC SDU discard test"}; - unsigned capacity = 10; - unsigned n_sdus = capacity; - rlc_sdu_queue tx_queue(capacity); - - // Fill SDU queue with SDUs - for (uint32_t pdcp_sn = 0; pdcp_sn < n_sdus; pdcp_sn++) { - byte_buffer buf = {}; - TESTASSERT(buf.append(pdcp_sn)); - TESTASSERT(buf.append(pdcp_sn)); - rlc_sdu write_sdu = {std::move(buf), pdcp_sn}; - TESTASSERT(tx_queue.write(std::move(write_sdu)) == true); - } - TESTASSERT_EQ(n_sdus, tx_queue.size_sdus()); - TESTASSERT_EQ(2 * n_sdus, tx_queue.size_bytes()); - - // Discard pdcp_sn 2 and 4 - TESTASSERT(tx_queue.discard(2)); - TESTASSERT(tx_queue.discard(4)); - - // Try to discard non-existing pdcp_sn - TESTASSERT(false == tx_queue.discard(16)); - - // Double check correct number of SDUs and SDU bytes - unsigned leftover_sdus = n_sdus - 2; - TESTASSERT_EQ(leftover_sdus, tx_queue.size_sdus()); - TESTASSERT_EQ(leftover_sdus * 2, tx_queue.size_bytes()); - - // Read SDUs - for (uint32_t n = 0; n < leftover_sdus; n++) { - rlc_sdu read_sdu = {}; - TESTASSERT(tx_queue.read(read_sdu)); - } - TESTASSERT_EQ(0, tx_queue.size_sdus()); - TESTASSERT_EQ(0, tx_queue.size_bytes()); -} - -void discard_all_test() -{ - test_delimit_logger delimiter{"RLC SDU discard all test"}; - unsigned capacity = 10; - unsigned n_sdus = capacity / 2; - rlc_sdu_queue tx_queue(capacity); - - // Fill SDU queue with SDUs - for (uint32_t pdcp_sn = 0; pdcp_sn < n_sdus; pdcp_sn++) { - byte_buffer buf = {}; - TESTASSERT(buf.append(pdcp_sn)); - TESTASSERT(buf.append(pdcp_sn)); - rlc_sdu write_sdu = {std::move(buf), pdcp_sn}; - TESTASSERT(tx_queue.write(std::move(write_sdu)) == true); - } - TESTASSERT_EQ(n_sdus, tx_queue.size_sdus()); - TESTASSERT_EQ(2 * n_sdus, tx_queue.size_bytes()); - - // Discard all SDUs - for (uint32_t pdcp_sn = 0; pdcp_sn < n_sdus; pdcp_sn++) { - TESTASSERT(tx_queue.discard(pdcp_sn)); - } - - TESTASSERT_EQ(0, tx_queue.size_sdus()); - TESTASSERT_EQ(0, tx_queue.size_bytes()); - - // Read SDU - { - rlc_sdu read_sdu = {}; - TESTASSERT(tx_queue.read(read_sdu) == false); - } - TESTASSERT_EQ(0, tx_queue.size_sdus()); - TESTASSERT_EQ(0, tx_queue.size_bytes()); -} -} // namespace srsran - -int main() -{ - srslog::init(); - srslog::fetch_basic_logger("TEST", false).set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("RLC", false).set_level(srslog::basic_levels::debug); - fprintf(stdout, "Testing RLC SDU queue\n"); - - srsran::queue_unqueue_test(); - srsran::full_capacity_test(); - srsran::discard_test(); - srsran::discard_all_test(); -} From 36218d051bf09fefd3fb07ff7da08f2a0f32b1c6 Mon Sep 17 00:00:00 2001 From: Oriol Font-Bach Date: Thu, 1 Aug 2024 18:02:16 +0000 Subject: [PATCH 054/407] hal: fix du_low thread config validation --- apps/units/flexible_du/du_low/du_low_config_validator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/units/flexible_du/du_low/du_low_config_validator.cpp b/apps/units/flexible_du/du_low/du_low_config_validator.cpp index a3a14eeeff..0f0b5ab69d 100644 --- a/apps/units/flexible_du/du_low/du_low_config_validator.cpp +++ b/apps/units/flexible_du/du_low/du_low_config_validator.cpp @@ -50,14 +50,14 @@ static bool validate_upper_phy_threads_appconfig(const du_low_unit_expert_thread } #ifdef DPDK_FOUND - if (config.nof_dl_threads > nof_hwacc_pdsch) { + if ((nof_hwacc_pdsch > 0) && (config.nof_dl_threads > nof_hwacc_pdsch)) { fmt::print("Not enough hardware-accelerated PDSCH encoder functions. Number of PHY DL threads (i.e., {}) must be " "in range {}.\n", config.nof_dl_threads, nof_hwacc_pdsch); valid = false; } - if ((config.nof_ul_threads + config.nof_pusch_decoder_threads) > nof_hwacc_pusch) { + if ((nof_hwacc_pusch > 0) && ((config.nof_ul_threads + config.nof_pusch_decoder_threads) > nof_hwacc_pusch)) { fmt::print("Not enough hardware-accelerated PUSCH decoder functions. Combined number of PHY UL threads (i.e., {}) " "and PUSCH decoder threads (i.e., {}) must be in range {}.\n", config.nof_ul_threads, From 60f7d2331e9e04fbefd29e6ee2bcfd9d8845b7be Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 1 Aug 2024 08:58:11 +0200 Subject: [PATCH 055/407] phy: optimize LDPC encoder and RM interfaces --- .../upper/channel_coding/ldpc/ldpc_encoder.h | 8 ++-- .../channel_coding/ldpc/ldpc_encoder_buffer.h | 40 ++++++++++++++++ .../channel_coding/ldpc/ldpc_rate_matcher.h | 7 +-- .../channel_coding/ldpc/ldpc_encoder_avx2.cpp | 46 ++++++++++++++----- .../channel_coding/ldpc/ldpc_encoder_avx2.h | 2 +- .../ldpc/ldpc_encoder_generic.cpp | 8 ++-- .../ldpc/ldpc_encoder_generic.h | 2 +- .../channel_coding/ldpc/ldpc_encoder_impl.cpp | 22 ++++----- .../channel_coding/ldpc/ldpc_encoder_impl.h | 16 +++++-- .../channel_coding/ldpc/ldpc_encoder_neon.cpp | 46 ++++++++++++++----- .../channel_coding/ldpc/ldpc_encoder_neon.h | 2 +- .../ldpc/ldpc_rate_matcher_impl.cpp | 14 +++--- .../ldpc/ldpc_rate_matcher_impl.h | 7 +-- .../pdsch_codeblock_processor.cpp | 5 +- .../pdsch_codeblock_processor.h | 2 - .../channel_processors/pdsch_encoder_impl.cpp | 5 +- .../channel_processors/pdsch_encoder_impl.h | 2 - .../pdsch_processor_lite_impl.cpp | 7 +-- .../pdsch_processor_lite_impl.h | 3 +- .../ldpc/ldpc_decoder_benchmark.cpp | 14 ++++-- .../ldpc/ldpc_encoder_benchmark.cpp | 7 +-- .../channel_coding/ldpc/ldpc_enc_dec_test.cpp | 10 ++-- .../channel_coding/ldpc/ldpc_rm_test.cpp | 38 ++++++++++----- 23 files changed, 204 insertions(+), 109 deletions(-) create mode 100644 include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h index dfbfb094c9..b40dd43777 100644 --- a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h @@ -18,6 +18,8 @@ namespace srsran { +class ldpc_encoder_buffer; + /// LDPC encoder interface. class ldpc_encoder { @@ -27,12 +29,12 @@ class ldpc_encoder /// \brief Encodes a message. /// - /// \param[out] output Resulting codeblock. /// \param[in] input Message: original information bits, with the filler bits (if any) set to zero. /// \param[in] cfg Encoder configuration for the current codeblock. + /// \return A reference to the LDPC encoder buffer. /// \note The length of the output codeblock is deduced from the size of parameter \c output. - virtual void - encode(bit_buffer& output, const bit_buffer& input, const codeblock_metadata::tb_common_metadata& cfg) = 0; + virtual const ldpc_encoder_buffer& encode(const bit_buffer& input, + const codeblock_metadata::tb_common_metadata& cfg) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h new file mode 100644 index 0000000000..920186606b --- /dev/null +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h @@ -0,0 +1,40 @@ +/* + * + * 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 + +namespace srsran { + +/// \brief LDPC encoder output buffer interface. +/// +/// This interface allows the LDPC encoder to provide the encoded bits to the rate matcher without using anintermediate +/// buffer. +class ldpc_encoder_buffer +{ +public: + /// Default destructor. + virtual ~ldpc_encoder_buffer() = default; + + /// Gets the encoded codeblock length. + virtual unsigned get_codeblock_length() const = 0; + + /// \brief Reads the encoded codeblock data starting at bit index \c offset. + /// + /// The data size plus the offset shall not exceed the encoded codeblock length. + /// + /// \param[out] data Read destination. + /// \param[in] offset Initial read position. + virtual void write_codeblock(span data, unsigned offset) const = 0; +}; + +} // namespace srsran \ No newline at end of file diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h index b9867be1f2..41ef8bc362 100644 --- a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h @@ -17,6 +17,8 @@ namespace srsran { +class ldpc_encoder_buffer; + /// LDPC rate matching (i.e., bit selection and bit interleaving) interface. class ldpc_rate_matcher { @@ -27,11 +29,10 @@ class ldpc_rate_matcher /// \brief Carries out the rate matching of a codeblock. /// /// \param[out] output Rate matched codeblock. - /// \param[in] input Original, full codeblock (may contain filler bits). Each \c uint8_t entry corresponds to a - /// single bit. + /// \param[in] input Reference to an LDPC encoder buffer. /// \param[in] cfg Configuration parameters. /// \remark The sizes of \c input and \c output determine the behavior of the rate matching algorithm. - virtual void rate_match(bit_buffer& output, const bit_buffer& input, const codeblock_metadata& cfg) = 0; + virtual void rate_match(bit_buffer& output, const ldpc_encoder_buffer& input, const codeblock_metadata& cfg) = 0; }; } // namespace srsran diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp index 4e871c55ce..8791f4caf7 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp @@ -435,23 +435,45 @@ void ldpc_encoder_avx2::ext_region_inner() } } -void ldpc_encoder_avx2::write_codeblock(bit_buffer& out) +void ldpc_encoder_avx2::write_codeblock(span out, unsigned offset) const { - unsigned nof_nodes = codeblock_length / lifting_size; + srsran_assert(out.size() + offset <= bg_N_short * lifting_size, + "The output size (i.e., {}) plus the offset (i.e., {}) exceeds the codeblock length (i.e., {}).", + out.size(), + offset, + bg_N_short * lifting_size); - // The first two blocks are shortened and the last node is not considered, since it can be incomplete. + // Calculate the node size in bytes, considering SIMD alignment. unsigned node_size_byte = node_size_avx2 * AVX2_SIZE_BYTE; - unsigned out_offset = 0; span codeblock(codeblock_buffer); - codeblock = codeblock.last(codeblock.size() - 2 * node_size_byte); - for (unsigned i_node = 2, max_i_node = nof_nodes - 1; i_node != max_i_node; ++i_node) { - srsvec::bit_pack(out, out_offset, codeblock.first(lifting_size)); + // Select the initial node. The first two blocks are shortened and the last node is not considered, since it can be + // incomplete. + unsigned i_node_begin = 2 + offset / lifting_size; + + // Advance the codeblock to the initial node. + codeblock = codeblock.last(codeblock.size() - i_node_begin * node_size_byte); + + // End node. + unsigned i_node_end = i_node_begin + divide_ceil(out.size(), lifting_size); + + // Calculate the offset within the first node. + offset = offset % lifting_size; + + for (unsigned i_node = i_node_begin; i_node != i_node_end; ++i_node) { + // Determine the number of bits to read from this node. + unsigned count = std::min(lifting_size - offset, static_cast(out.size())); + + // Copy node bits. + srsvec::copy(out.first(count), codeblock.subspan(offset, count)); + + // Advance codeblock. codeblock = codeblock.last(codeblock.size() - node_size_byte); - out_offset += lifting_size; - } - // Take care of the last node. - unsigned remainder = out.size() - out_offset; - srsvec::bit_pack(out, out_offset, codeblock.first(remainder)); + // Advance output. + out = out.last(out.size() - count); + + // The offset is no longer required after the first node. + offset = 0; + } } diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h index 9ec2e07b5d..798b02364e 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h @@ -27,7 +27,7 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl void preprocess_systematic_bits() override { (this->*systematic_bits)(); } void encode_high_rate() override { (this->*high_rate)(); } void encode_ext_region() override { (this->*ext_region)(); } - void write_codeblock(bit_buffer& out) override; + void write_codeblock(span out, unsigned offset) const override; /// Alias for pointer to private methods. using strategy_method = void (ldpc_encoder_avx2::*)(); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp index 6d81ddc670..fbec570e95 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp @@ -10,7 +10,6 @@ #include "ldpc_encoder_generic.h" #include "srsran/srsvec/binary.h" -#include "srsran/srsvec/bit.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/zero.h" @@ -105,12 +104,11 @@ void ldpc_encoder_generic::encode_ext_region() } } -void ldpc_encoder_generic::write_codeblock(bit_buffer& out) +void ldpc_encoder_generic::write_codeblock(span out, unsigned offset) const { // The encoder shortens the codeblock by discarding the first 2 * LS bits. - uint8_t* first = &codeblock[2UL * lifting_size]; - - srsvec::bit_pack(out, span{first, out.size()}); + span first = span(codeblock).subspan(2UL * lifting_size + offset, out.size()); + srsvec::copy(out, first); } void ldpc_encoder_generic::high_rate_bg1_i6() diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h index 2c75c21a2c..80d62c3a4f 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h @@ -32,7 +32,7 @@ class ldpc_encoder_generic : public ldpc_encoder_impl void preprocess_systematic_bits() override; void encode_high_rate() override { (this->*high_rate)(); } void encode_ext_region() override; - void write_codeblock(bit_buffer& out) override; + void write_codeblock(span out, unsigned offset) const override; /// Pointer type shortcut. using high_rate_strategy = void (ldpc_encoder_generic::*)(); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp index 04c2e60f24..6a91f861f3 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp @@ -29,29 +29,24 @@ void ldpc_encoder_impl::init(const codeblock_metadata::tb_common_metadata& cfg) select_strategy(); } -void ldpc_encoder_impl::encode(bit_buffer& output, - const bit_buffer& input, - const codeblock_metadata::tb_common_metadata& cfg) +ldpc_encoder_buffer& ldpc_encoder_impl::encode(const bit_buffer& input, + const codeblock_metadata::tb_common_metadata& cfg) { init(cfg); - uint16_t message_length = bg_K * lifting_size; - uint16_t max_output_length = bg_N_short * lifting_size; + uint16_t message_length = bg_K * lifting_size; + uint16_t cb_length = bg_N_short * lifting_size; srsran_assert(input.size() == message_length, "Input size ({}) and message length ({}) must be equal", input.size(), message_length); - srsran_assert(output.size() <= max_output_length, - "Output size ({}) must be equal to or greater than {}", - output.size(), - max_output_length); // The minimum codeblock length is message_length + four times the lifting size // (that is, the length of the high-rate region). uint16_t min_codeblock_length = message_length + 4 * lifting_size; // The encoder works with at least min_codeblock_length bits. Recall that the encoder also shortens // the codeblock by 2 * lifting size before returning it as output. - codeblock_length = std::max(output.size() + 2UL * lifting_size, static_cast(min_codeblock_length)); + codeblock_length = std::max(cb_length + 2UL * lifting_size, static_cast(min_codeblock_length)); // The encoder works with a codeblock length that is a multiple of the lifting size. if (codeblock_length % lifting_size != 0) { codeblock_length = (codeblock_length / lifting_size + 1) * lifting_size; @@ -65,5 +60,10 @@ void ldpc_encoder_impl::encode(bit_buffer& out encode_ext_region(); - write_codeblock(output); + return *this; +} + +unsigned ldpc_encoder_impl::get_codeblock_length() const +{ + return bg_N_short * lifting_size; } diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h index d9d40c966d..e97733594a 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h @@ -14,15 +14,19 @@ #include "ldpc_graph_impl.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h" namespace srsran { -/// Template LDPC encoder. -class ldpc_encoder_impl : public ldpc_encoder +/// \brief LDPC encoder implementation outline. +/// +/// This class defines the main steps of the encoder algorithm by means of virtual methods. Derived classes provide +/// a number of implementations of these methods that leverage different instruction sets. +class ldpc_encoder_impl : public ldpc_encoder, private ldpc_encoder_buffer { public: // See interface for the documentation. - void encode(bit_buffer& output, const bit_buffer& input, const codeblock_metadata::tb_common_metadata& cfg) override; + ldpc_encoder_buffer& encode(const bit_buffer& input, const codeblock_metadata::tb_common_metadata& cfg) override; private: /// Initializes the encoder inner variables. @@ -38,8 +42,10 @@ class ldpc_encoder_impl : public ldpc_encoder virtual void encode_high_rate() = 0; /// Computes the rest of the redundancy bits (extension region). virtual void encode_ext_region() = 0; - /// Moves relevant encoded bits from the internal register to the output vector. - virtual void write_codeblock(bit_buffer& out) = 0; + // See ldpc_encoder_buffer interface for documentation. + virtual void write_codeblock(span data, unsigned offset) const override = 0; + // See ldpc_encoder_buffer interface for documentation. + unsigned get_codeblock_length() const override; protected: /// Number of base graph parity nodes in the high-rate region. diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp index e7bd3e899b..5c28669bab 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp @@ -412,23 +412,45 @@ void ldpc_encoder_neon::ext_region_inner() } } -void ldpc_encoder_neon::write_codeblock(bit_buffer& out) +void ldpc_encoder_neon::write_codeblock(span out, unsigned offset) const { - unsigned nof_nodes = codeblock_length / lifting_size; + srsran_assert(out.size() + offset <= bg_N_short * lifting_size, + "The output size (i.e., {}) plus the offset (i.e., {}) exceeds the codeblock length (i.e., {}).", + out.size(), + offset, + bg_N_short * lifting_size); - // The first two blocks are shortened and the last node is not considered, since it can be incomplete. + // Calculate the node size in bytes, considering SIMD alignment. unsigned node_size_byte = node_size_neon * NEON_SIZE_BYTE; - unsigned out_offset = 0; span codeblock(codeblock_buffer); - codeblock = codeblock.last(codeblock.size() - 2 * node_size_byte); - for (unsigned i_node = 2, max_i_node = nof_nodes - 1; i_node != max_i_node; ++i_node) { - srsvec::bit_pack(out, out_offset, codeblock.first(lifting_size)); + // Select the initial node. The first two blocks are shortened and the last node is not considered, since it can be + // incomplete. + unsigned i_node_begin = 2 + offset / lifting_size; + + // Advance the codeblock to the initial node. + codeblock = codeblock.last(codeblock.size() - i_node_begin * node_size_byte); + + // End node. + unsigned i_node_end = i_node_begin + divide_ceil(out.size(), lifting_size); + + // Calculate the offset within the first node. + offset = offset % lifting_size; + + for (unsigned i_node = i_node_begin; i_node != i_node_end; ++i_node) { + // Determine the number of bits to read from this node. + unsigned count = std::min(lifting_size - offset, static_cast(out.size())); + + // Copy node bits. + srsvec::copy(out.first(count), codeblock.subspan(offset, count)); + + // Advance codeblock. codeblock = codeblock.last(codeblock.size() - node_size_byte); - out_offset += lifting_size; - } - // Take care of the last node. - unsigned remainder = out.size() - out_offset; - srsvec::bit_pack(out, out_offset, codeblock.first(remainder)); + // Advance output. + out = out.last(out.size() - count); + + // The offset is no longer required after the first node. + offset = 0; + } } diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h index f110d97630..366bb39a33 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h @@ -27,7 +27,7 @@ class ldpc_encoder_neon : public ldpc_encoder_impl void preprocess_systematic_bits() override { (this->*systematic_bits)(); } void encode_high_rate() override { (this->*high_rate)(); } void encode_ext_region() override { (this->*ext_region)(); } - void write_codeblock(bit_buffer& out) override; + void write_codeblock(span out, unsigned offset) const override; /// Alias for pointer to private methods. using strategy_method = void (ldpc_encoder_neon::*)(); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.cpp index 36ec03faec..94749db5fb 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.cpp @@ -78,16 +78,18 @@ void ldpc_rate_matcher_impl::init(const codeblock_metadata& cfg, unsigned block_ shift_k0 = static_cast(floor(tmp)) * lifting_size; } -void ldpc_rate_matcher_impl::rate_match(bit_buffer& output, const bit_buffer& input, const codeblock_metadata& cfg) +void ldpc_rate_matcher_impl::rate_match(bit_buffer& output, + const ldpc_encoder_buffer& input, + const codeblock_metadata& cfg) { - init(cfg, input.size(), output.size()); + init(cfg, input.get_codeblock_length(), output.size()); span aux = span(auxiliary_buffer).first(output.size()); - select_bits(aux, input.first(buffer_length)); + select_bits(aux, input); interleave_bits(output, aux); } -void ldpc_rate_matcher_impl::select_bits(span out, const bit_buffer& in) const +void ldpc_rate_matcher_impl::select_bits(span out, const ldpc_encoder_buffer& in) const { unsigned output_length = out.size(); unsigned out_index = 0; @@ -114,7 +116,7 @@ void ldpc_rate_matcher_impl::select_bits(span out, const bit_buffer& in } // Select input chunk interval. Stop the chunk at the first filler bit. - interval input_chunk_range(in_index, in.size()); + interval input_chunk_range(in_index, buffer_length); if (!filler_bits_range.empty() && input_chunk_range.contains(filler_bits_range.start())) { input_chunk_range = {in_index, filler_bits_range.start()}; } @@ -123,7 +125,7 @@ void ldpc_rate_matcher_impl::select_bits(span out, const bit_buffer& in unsigned count = std::min(input_chunk_range.length(), output_length - out_index); // Append the consecutive number of bits. - srsvec::bit_unpack(out.subspan(out_index, count), in, in_index); + in.write_codeblock(out.subspan(out_index, count), in_index); out_index += count; // Advance in_index the amount of written bits. diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.h index 95ccb2bfb3..5c5914b9de 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_rate_matcher_impl.h @@ -14,6 +14,7 @@ #pragma once #include "ldpc_graph_impl.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h" namespace srsran { @@ -23,7 +24,7 @@ class ldpc_rate_matcher_impl : public ldpc_rate_matcher { public: // See interface for the documentation. - void rate_match(bit_buffer& output, const bit_buffer& input, const codeblock_metadata& cfg) override; + void rate_match(bit_buffer& output, const ldpc_encoder_buffer& input, const codeblock_metadata& cfg) override; private: /// Initializes the rate matcher internal state. @@ -32,8 +33,8 @@ class ldpc_rate_matcher_impl : public ldpc_rate_matcher /// \brief Carries out bit selection, as per TS38.212 Section 5.4.2.1. /// /// \param[out] out Sequence of selected bits. - /// \param[in] in Input encoded code block. - void select_bits(span out, const bit_buffer& in) const; + /// \param[in] in Input encoded codeblock. + void select_bits(span out, const ldpc_encoder_buffer& in) const; /// \brief Carries out bit interleaving, as per TS38.212 Section 5.4.2.2. /// diff --git a/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp b/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp index df745bde2c..3a8e9c8870 100644 --- a/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp +++ b/lib/phy/upper/channel_processors/pdsch_codeblock_processor.cpp @@ -110,11 +110,8 @@ pdsch_codeblock_processor::result pdsch_codeblock_processor::process(spanencode(rm_buffer, cb_data, config.metadata.tb_common); + const ldpc_encoder_buffer& rm_buffer = encoder->encode(cb_data, config.metadata.tb_common); // Rate match the codeblock. temp_packed_bits.resize(rm_length); diff --git a/lib/phy/upper/channel_processors/pdsch_codeblock_processor.h b/lib/phy/upper/channel_processors/pdsch_codeblock_processor.h index 048953819c..47933ec0a4 100644 --- a/lib/phy/upper/channel_processors/pdsch_codeblock_processor.h +++ b/lib/phy/upper/channel_processors/pdsch_codeblock_processor.h @@ -137,8 +137,6 @@ class pdsch_codeblock_processor static_bit_buffer temp_packed_bits; /// Buffer for storing the codeblock symbols. std::array temp_cb_symbols; - /// Temporary rate match buffer. - static_bit_buffer rm_buffer; }; } // namespace srsran diff --git a/lib/phy/upper/channel_processors/pdsch_encoder_impl.cpp b/lib/phy/upper/channel_processors/pdsch_encoder_impl.cpp index cf342afc87..c2bbdd16c8 100644 --- a/lib/phy/upper/channel_processors/pdsch_encoder_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch_encoder_impl.cpp @@ -36,11 +36,8 @@ void pdsch_encoder_impl::encode(span codeword, // Select segment description. const described_segment& descr_seg = d_segments[i_cb]; - // Prepare rate matching buffer. - rm_buffer.resize(descr_seg.get_metadata().cb_specific.full_length); - // Encode the segment into a codeblock. - encoder->encode(rm_buffer, descr_seg.get_data(), descr_seg.get_metadata().tb_common); + const ldpc_encoder_buffer& rm_buffer = encoder->encode(descr_seg.get_data(), descr_seg.get_metadata().tb_common); // Select the correct chunk of the output codeword. unsigned rm_length = descr_seg.get_metadata().cb_specific.rm_length; diff --git a/lib/phy/upper/channel_processors/pdsch_encoder_impl.h b/lib/phy/upper/channel_processors/pdsch_encoder_impl.h index bfabd44ad3..45b49e2578 100644 --- a/lib/phy/upper/channel_processors/pdsch_encoder_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_encoder_impl.h @@ -59,8 +59,6 @@ class pdsch_encoder_impl : public pdsch_encoder static constexpr units::bits MAX_CB_LENGTH{3 * MAX_SEG_LENGTH.value()}; /// Buffer for storing temporary encoded and packed codeblock. static_bit_buffer codeblock_packed; - /// Temporary rate match buffer. - static_bit_buffer rm_buffer; }; } // namespace srsran diff --git a/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.cpp b/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.cpp index 00cf8c3a17..d1f5056aea 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.cpp @@ -101,11 +101,8 @@ void pdsch_block_processor::new_codeblock() // Number of symbols. unsigned nof_symbols = rm_length / get_bits_per_symbol(modulation); - // Resize internal buffer to match data from the encoder to the rate matcher (all segments have the same length). - rm_buffer.resize(descr_seg.get_metadata().cb_specific.full_length); - // Encode the segment into a codeblock. - encoder.encode(rm_buffer, descr_seg.get_data(), descr_seg.get_metadata().tb_common); + const ldpc_encoder_buffer& rm_buffer = encoder.encode(descr_seg.get_data(), descr_seg.get_metadata().tb_common); // Rate match the codeblock. temp_codeblock.resize(rm_length); @@ -124,7 +121,7 @@ void pdsch_block_processor::new_codeblock() span pdsch_block_processor::pop_symbols(unsigned block_size) { - // Process a new code block if the buffer with code block symbols is empty. + // Process a new codeblock if the buffer with codeblock symbols is empty. if (codeblock_symbols.empty()) { new_codeblock(); } diff --git a/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h b/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h index 6e8bb3be37..7535dd46d6 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h @@ -9,6 +9,7 @@ */ #pragma once +#include "pdsch_codeblock_processor.h" #include "srsran/phy/support/resource_grid_mapper.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h" @@ -76,8 +77,6 @@ class pdsch_block_processor : public resource_grid_mapper::symbol_buffer /// Current codeblock index. unsigned next_i_cb = 0; /// Temporary storage of codeblock symbols. - static_bit_buffer rm_buffer; - /// Temporary storage of codeblock symbols. std::array temp_codeblock_symbols; /// Current view of the codeblock modulated symbols. span codeblock_symbols; diff --git a/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_decoder_benchmark.cpp b/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_decoder_benchmark.cpp index 2937b643f9..209eddad6f 100644 --- a/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_decoder_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_decoder_benchmark.cpp @@ -12,6 +12,7 @@ /// \brief LDPC decoder benchmark. #include "srsran/phy/upper/channel_coding/channel_coding_factories.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h" #include "srsran/srsvec/bit.h" #include "srsran/support/benchmark_utils.h" #include "srsran/support/srsran_test.h" @@ -133,8 +134,8 @@ int main(int argc, char** argv) codeblock.begin(), codeblock.end(), [&]() { return static_cast((rgen() & 1) * 20 - 10); }); } else { // Generate random message, attach its CRC and encode. - dynamic_bit_buffer to_encode(msg_length); - dynamic_bit_buffer encoded(cb_length); + dynamic_bit_buffer to_encode(msg_length); + std::vector encoded(cb_length); // Generate a random message. unsigned msg_len_minus_crc = msg_length - 16; bit_buffer msg_span = to_encode.first(msg_len_minus_crc); @@ -146,12 +147,15 @@ int main(int argc, char** argv) to_encode.insert(checksum, msg_len_minus_crc, 16); // Encode entire message. srsran::codeblock_metadata::tb_common_metadata cfg_enc; - cfg_enc = {bg, ls}; - encoder->encode(encoded, to_encode, cfg_enc); + cfg_enc = {bg, ls}; + const ldpc_encoder_buffer& rm_buffer = encoder->encode(to_encode, cfg_enc); + + // Write codeblock in the encoded intermediate buffer. + rm_buffer.write_codeblock(encoded, 0); // Convert codeblock bits to LLRs. for (unsigned i_bit = 0; i_bit != cb_length; ++i_bit) { - codeblock[i_bit] = log_likelihood_ratio::copysign(10, 1 - 2 * encoded.extract(i_bit, 1)); + codeblock[i_bit] = log_likelihood_ratio::copysign(10, 1 - 2 * encoded[i_bit]); } } diff --git a/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_encoder_benchmark.cpp b/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_encoder_benchmark.cpp index cb0ebd18c2..18820a1d80 100644 --- a/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_encoder_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_coding/ldpc/ldpc_encoder_benchmark.cpp @@ -90,17 +90,14 @@ int main(int argc, char** argv) data.insert(rgen() & 1, i_bit, 1); } - // Generate codeblock. - dynamic_bit_buffer codeblock(cb_length); - srsran::codeblock_metadata::tb_common_metadata cfg_enc = {bg, ls}; fmt::memory_buffer descr_buffer; fmt::format_to(descr_buffer, "BG={} LS={:<3} cb_len={}", bg, ls, cb_length); perf_meas_generic.new_measure(to_string(descr_buffer), data.size(), [&]() { - encoder->encode(codeblock, data, cfg_enc); - do_not_optimize(codeblock); + const ldpc_encoder_buffer& rm_buffer = encoder->encode(data, cfg_enc); + do_not_optimize(&rm_buffer); }); } } diff --git a/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_enc_dec_test.cpp b/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_enc_dec_test.cpp index 8f6eed6e9f..57d5148228 100644 --- a/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_enc_dec_test.cpp +++ b/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_enc_dec_test.cpp @@ -17,6 +17,7 @@ #include "ldpc_encoder_test_data.h" #include "srsran/phy/upper/channel_coding/channel_coding_factories.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h" #include "srsran/srsvec/bit.h" #include "srsran/srsvec/zero.h" #include @@ -261,12 +262,9 @@ TEST_P(LDPCEncDecFixture, LDPCEncTest) span expected_encoded = cblock_i.first(length); // Check the encoder. - std::vector encoded(length); - dynamic_bit_buffer encoded_packed(length); - - encoder_test->encode(encoded_packed, message_packed, cfg_enc); - - srsvec::bit_unpack(encoded, encoded_packed); + std::vector encoded(length); + const ldpc_encoder_buffer& rm_buffer = encoder_test->encode(message_packed, cfg_enc); + rm_buffer.write_codeblock(encoded, 0); ASSERT_EQ(span(encoded), span(expected_encoded)) << "Wrong codeblock."; } } diff --git a/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_rm_test.cpp b/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_rm_test.cpp index c5c8ed4bc1..3d238c4fdf 100644 --- a/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_rm_test.cpp +++ b/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_rm_test.cpp @@ -18,7 +18,9 @@ #include "ldpc_rate_matcher_test_data.h" #include "srsran/phy/upper/channel_coding/channel_coding_factories.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h" #include "srsran/srsvec/bit.h" +#include "srsran/srsvec/copy.h" #include "srsran/support/cpu_features.h" #include "fmt/ostream.h" #include @@ -76,6 +78,25 @@ std::ostream& operator<<(std::ostream& os, const bit_buffer& data) namespace { +/// Implements the LDPC encoder buffer interface. +class ldpc_encoder_buffer_impl : public ldpc_encoder_buffer +{ +public: + ldpc_encoder_buffer_impl(span buffer_) : buffer(buffer_) + { + // Do nothing. + } + + unsigned get_codeblock_length() const override { return buffer.size(); } + void write_codeblock(span data, unsigned offset) const override + { + srsvec::copy(data, buffer.subspan(offset, data.size())); + } + +private: + span buffer; +}; + #ifdef __x86_64__ bool supports_avx2 = cpu_supports_feature(cpu_feature::avx2); bool supports_avx512 = cpu_supports_feature(cpu_feature::avx512bw) && cpu_supports_feature(cpu_feature::avx512f) && @@ -149,17 +170,15 @@ TEST_P(LDPCRateMatchingFixture, LDPCRateMatchingTest) unsigned n_ref = test_data.is_lbrm ? test_data.n_ref : 0; unsigned nof_filler_bits = test_data.nof_filler; - std::vector codeblock = test_data.full_cblock.read(); - codeblock_metadata rm_cfg = {}; + std::vector codeblock = test_data.full_cblock.read(); + ldpc_encoder_buffer_impl rm_buffer(codeblock); + codeblock_metadata rm_cfg = {}; rm_cfg.tb_common.rv = test_data.rv; rm_cfg.tb_common.mod = mod; rm_cfg.tb_common.Nref = n_ref; rm_cfg.cb_specific.nof_filler_bits = nof_filler_bits; - dynamic_bit_buffer codeblock_packed(codeblock.size()); - srsvec::bit_pack(codeblock_packed, codeblock); - - matcher->rate_match(matched_packed, codeblock_packed, rm_cfg); + matcher->rate_match(matched_packed, rm_buffer, rm_cfg); // Unpack rate matched. srsvec::bit_unpack(matched, matched_packed); @@ -187,15 +206,12 @@ TEST_P(LDPCRateMatchingFixture, LDPCRateMatchingTest) return b.to_hard_bit(); }; std::vector hard(dematched.size()); + rm_buffer = ldpc_encoder_buffer_impl(hard); std::transform(dematched.cbegin(), dematched.cend(), hard.begin(), llrs_to_bit); - // Pack hard bits. - dynamic_bit_buffer hard_packed(dematched.size()); - srsvec::bit_pack(hard_packed, hard); - // Now, apply the rate matcher and compare results. static_bit_buffer matched_packed2(rm_length); - matcher->rate_match(matched_packed2, hard_packed, rm_cfg); + matcher->rate_match(matched_packed2, rm_buffer, rm_cfg); EXPECT_EQ(matched_packed, matched_packed2) << "Wrong rate dematching."; } From 92f1692f62d43c306b5149b4f971d9060b11c698 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 22 Jul 2024 15:06:09 +0200 Subject: [PATCH 056/407] ci: fedora builder support --- .gitlab/ci/builders.yml | 60 ++++++++++++++++++++++++++ .gitlab/ci/builders/fedora/Dockerfile | 33 ++++++++++++++ .gitlab/ci/trx.yml | 13 +++++- docker/scripts/install_dependencies.sh | 11 +++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 .gitlab/ci/builders/fedora/Dockerfile diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index 37532ee6a2..1be5d3580f 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -892,6 +892,66 @@ manifest [rhel, 8]: matrix: - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] +################################################################################ +# Fedora 39 +################################################################################ +image-build-publish [fedora, 39]: + extends: + - .image-build-publish + variables: + OS_FAMILY: fedora + OS_NAME: fedora + OS_VERSION: "39" + PLATFORM: amd64 + needs: + - builder version + parallel: + matrix: + - PLATFORM: [amd64, arm64] + +alternative-tag [fedora, 39, amd64]: + extends: + - .alternative-tag + variables: + OS_NAME: fedora + OS_VERSION: "39" + VERSION: ${DOCKER_BUILDER_VERSION}-amd64 + needs: + - builder version + - job: image-build-publish [fedora, 39] + parallel: + matrix: + - PLATFORM: amd64 + +alternative-tag [fedora, 39, arm64]: + extends: + - .alternative-tag + variables: + OS_NAME: fedora + OS_VERSION: "39" + VERSION: ${DOCKER_BUILDER_VERSION}-arm64 + needs: + - builder version + - job: image-build-publish [fedora, 39] + parallel: + matrix: + - PLATFORM: arm64 + +manifest [fedora, 39]: + extends: .manifest + variables: + OS_NAME: fedora + OS_VERSION: "39" + needs: + - builder version + - job: alternative-tag [fedora, 39, amd64] + optional: false + - job: alternative-tag [fedora, 39, arm64] + optional: false + parallel: + matrix: + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + ################################################################################ # Archlinux ################################################################################ diff --git a/.gitlab/ci/builders/fedora/Dockerfile b/.gitlab/ci/builders/fedora/Dockerfile new file mode 100644 index 0000000000..b9959519fd --- /dev/null +++ b/.gitlab/ci/builders/fedora/Dockerfile @@ -0,0 +1,33 @@ +# +# Copyright 2013-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. +# + +ARG VERSION=39 +ARG OS_NAME=fedora +FROM $OS_NAME:$VERSION + +RUN TZ=Europe/Madrid && \ + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ + echo $TZ > /etc/timezone && \ + dnf update -y && \ + dnf install -y \ + which git git-lfs \ + clang llvm \ + ccache gcovr valgrind \ + python3-devel python3-virtualenv && \ + dnf install -y libstdc++-static && \ + dnf autoremove -y && dnf clean all && rm -rf /var/cache/dnf && \ + git lfs install + +ADD install_dependencies.sh builder.sh changed_tests.py ram_reporter.py /usr/local/bin/ +RUN chmod +x /usr/local/bin/install_dependencies.sh /usr/local/bin/builder.sh /usr/local/bin/changed_tests.py /usr/local/bin/ram_reporter.py && \ + /usr/local/bin/install_dependencies.sh && \ + dnf autoremove -y && dnf clean all && rm -rf /var/cache/dnf && \ + python3 -m venv /usr/local/builder_tools && \ + /usr/local/builder_tools/bin/pip install "pandas<3" "psutil" + +WORKDIR /workdir diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index df7a47e7d9..228041a350 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -58,7 +58,7 @@ build trx driver: rm -Rf build mkdir build cd build - cmake -DENABLE_TRX_DRIVER=True -DTRX_DRIVER_DIR=${CI_PROJECT_DIR}/amarisoft/trx_uhd-linux -DENABLE_EXPORT=True -DENABLE_UHD=False -DENABLE_ZEROMQ=True -DMARCH=x86-64-v3 .. + cmake -DBUILD_TESTS=False -DENABLE_TRX_DRIVER=True -DTRX_DRIVER_DIR=${CI_PROJECT_DIR}/amarisoft/trx_uhd-linux -DENABLE_EXPORT=True -DENABLE_UHD=False -DENABLE_ZEROMQ=True -DMARCH=x86-64-v3 .. make -j${KUBERNETES_CPU_REQUEST} trx_srsran_test } - | @@ -87,3 +87,14 @@ build amariue zmq driver: artifacts: <<: *trx_artifacts expire_in: 3 days + +build uesim zmq driver: + extends: build trx driver + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ + variables: + OS: fedora-39 + AMARISOFT_VERSION: "2024-03-15" + artifacts: + <<: *trx_artifacts + expire_in: 3 days diff --git a/docker/scripts/install_dependencies.sh b/docker/scripts/install_dependencies.sh index 95bf3c534e..a38491754b 100755 --- a/docker/scripts/install_dependencies.sh +++ b/docker/scripts/install_dependencies.sh @@ -69,6 +69,17 @@ main() { dnf -y install cppzmq-devel libusb1-devel boost-devel numactl-devel # dpdk libelf libdwarf fi + elif [[ "$ID" == "fedora" ]]; then + if [[ "$mode" == "all" || "$mode" == "build" ]]; then + dnf -y install cmake fftw-devel lksctp-tools-devel yaml-cpp-devel mbedtls-devel gtest-devel + fi + if [[ "$mode" == "all" || "$mode" == "run" ]]; then + dnf -y install fftw-devel lksctp-tools-devel yaml-cpp-devel mbedtls-devel gtest-devel + fi + if [[ "$mode" == "all" || "$mode" == "extra" ]]; then + dnf -y install cppzmq-devel libusb1-devel boost-devel numactl-devel # dpdk libelf libdwarf + fi + else echo "OS $ID not supported" exit 1 From c93b983339bfa41c9e373861828292f12217db3a Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 31 Jul 2024 12:11:18 +0200 Subject: [PATCH 057/407] ci,e2e: added uesim testbed --- .gitlab/ci/e2e.yml | 25 ++++-- .gitlab/ci/e2e/.env | 4 +- .gitlab/ci/e2e/retina_request_test_mode.yml | 2 - .gitlab/ci/e2e/retina_request_zmq.yml | 6 +- .../ci/e2e/retina_request_zmq_2x2_mimo.yml | 79 ------------------- .../ci/e2e/retina_request_zmq_4x4_mimo.yml | 78 ------------------ .gitlab/ci/e2e/retina_request_zmq_cudu.yml | 6 +- .gitlab/ci/e2e/retina_request_zmq_deb.yml | 6 +- .gitlab/ci/e2e/retina_request_zmq_srsue.yml | 6 +- ...le_ue.yml => retina_request_zmq_uesim.yml} | 30 +++---- tests/e2e/tests/iperf.py | 10 ++- tests/e2e/tests/steps/configuration.py | 6 ++ tests/e2e/tests/test_mode.py | 6 +- tests/e2e/tests/test_mode/config_ru.yml | 4 +- tests/e2e/tests/test_mode/config_ue.yml | 4 +- tests/e2e/tests/viavi.py | 2 + 16 files changed, 75 insertions(+), 199 deletions(-) delete mode 100644 .gitlab/ci/e2e/retina_request_zmq_2x2_mimo.yml delete mode 100644 .gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml rename .gitlab/ci/e2e/{retina_request_zmq_single_ue.yml => retina_request_zmq_uesim.yml} (77%) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 9aa85018e5..31398437e2 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -16,10 +16,8 @@ variables: description: Retina Testbed Description options: - "zmq" + - "zmq_uesim" - "zmq_deb" - - "zmq_single_ue" - - "zmq_2x2_mimo" - - "zmq_4x4_mimo" - "zmq_srsue" - "zmq_cudu" - "rf_b200" @@ -278,7 +276,6 @@ srsue: amari 1UE: extends: .zmq variables: - TESTBED: "zmq_single_ue" MARKERS: "zmq_single_ue" E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" @@ -291,7 +288,6 @@ amari 1UE: amari 1UE 2x2 mimo: extends: .zmq variables: - TESTBED: "zmq_2x2_mimo" MARKERS: "zmq_2x2_mimo" E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" @@ -305,7 +301,6 @@ amari 1UE 2x2 mimo: amari 1UE 4x4 mimo: extends: .zmq variables: - TESTBED: "zmq_4x4_mimo" MARKERS: "zmq_4x4_mimo" E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" @@ -449,6 +444,24 @@ cudu amari 32UE: matrix: - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] +uesim 32UE beta: + stage: zmq + extends: .e2e-run + variables: + GROUP: uesim + TESTBED: zmq_uesim + MARKERS: "zmq and not smoke" + KEYWORDS: ping + E2E_LOG_LEVEL: "info" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + needs: + - job: "basic relwithdeb" + artifacts: true + - job: "build uesim zmq driver" + artifacts: true + - *retina-needs + allow_failure: true + ################################################################################ # TEST MODE ################################################################################ diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 88a1468b94..e1a9b8149d 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.51.15 +RETINA_VERSION=0.52.0 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 @@ -9,6 +9,6 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.3 DPDK_VERSION=23.11 ZMQ_HOSTLABEL_0=kubernetes.io/hostname=k8s-worker-vm2 -ZMQ_HOSTLABEL_1=kubernetes.io/hostname=k8s-worker-vm2 +ZMQ_HOSTLABEL_1=kubernetes.io/hostname=srskit AMARISOFT_TXRX_BINARY_PATH=../../build_trx_srsran/libtrx_srsran.so GNB_BINARY_PATH=../../build/apps/gnb/gnb diff --git a/.gitlab/ci/e2e/retina_request_test_mode.yml b/.gitlab/ci/e2e/retina_request_test_mode.yml index 67f761939a..d12c59a545 100644 --- a/.gitlab/ci/e2e/retina_request_test_mode.yml +++ b/.gitlab/ci/e2e/retina_request_test_mode.yml @@ -23,8 +23,6 @@ limits: "6G" resources: - type: zmq - nof_antennas_dl: 4 - nof_antennas_ul: 4 environment: - PATH: ${PATH}:/builds/softwareradiosystems/srsgnb/build/apps/gnb shared_files: diff --git a/.gitlab/ci/e2e/retina_request_zmq.yml b/.gitlab/ci/e2e/retina_request_zmq.yml index 821ae50498..0130c4ef12 100644 --- a/.gitlab/ci/e2e/retina_request_zmq.yml +++ b/.gitlab/ci/e2e/retina_request_zmq.yml @@ -10,7 +10,7 @@ type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} nof_ports: 32 requirements: arch: amd64 @@ -36,7 +36,7 @@ type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 cpu: @@ -72,4 +72,4 @@ limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_2x2_mimo.yml b/.gitlab/ci/e2e/retina_request_zmq_2x2_mimo.yml deleted file mode 100644 index 7d5eea54f2..0000000000 --- a/.gitlab/ci/e2e/retina_request_zmq_2x2_mimo.yml +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright 2013-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. -# - -- name: amarisoft-ue - type: ue - image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} - nof_ports: 32 - requirements: - arch: amd64 - cpu: - requests: 5 - limits: 5 - memory: - requests: "26G" - limits: "26G" - ephemeral-storage: - requests: "6G" - limits: "6G" - resources: - - type: zmq - nof_antennas_dl: 2 - nof_antennas_ul: 2 - - type: license - model: amarisoft-5g - shared_files: - - local_path: ${AMARISOFT_TXRX_BINARY_PATH} - remote_path: /opt/lteue/trx_srsran.so - is_executable: true - -- name: srs-gnb - type: gnb - image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} - requirements: - arch: amd64 - cpu: - requests: 5 - limits: 5 - memory: - requests: "26G" - limits: "26G" - ephemeral-storage: - requests: "6G" - limits: "6G" - resources: - - type: zmq - nof_antennas_dl: 2 - nof_antennas_ul: 2 - environment: - - PATH: ${PATH}:/builds/softwareradiosystems/srsgnb/build/apps/gnb - shared_files: - - local_path: ${GNB_BINARY_PATH} - remote_path: /usr/local/bin/gnb - is_executable: true - -- name: open5gs - type: 5gc - requirements: - arch: amd64 - cpu: - requests: 1 - limits: 1 - memory: - requests: "8G" - limits: "8G" - ephemeral-storage: - requests: "6G" - limits: "6G" - image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} diff --git a/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml b/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml deleted file mode 100644 index ddd442b725..0000000000 --- a/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml +++ /dev/null @@ -1,78 +0,0 @@ -# -# Copyright 2013-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. -# - -- name: amarisoft-ue - type: ue - image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} - requirements: - arch: amd64 - cpu: - requests: 5 - limits: 5 - memory: - requests: "26G" - limits: "26G" - ephemeral-storage: - requests: "6G" - limits: "6G" - resources: - - type: zmq - nof_antennas_dl: 4 - nof_antennas_ul: 4 - - type: license - model: amarisoft-5g - shared_files: - - local_path: ${AMARISOFT_TXRX_BINARY_PATH} - remote_path: /opt/lteue/trx_srsran.so - is_executable: true - -- name: srs-gnb - type: gnb - image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} - requirements: - arch: amd64 - cpu: - requests: 5 - limits: 5 - memory: - requests: "26G" - limits: "26G" - ephemeral-storage: - requests: "6G" - limits: "6G" - resources: - - type: zmq - nof_antennas_dl: 4 - nof_antennas_ul: 4 - environment: - - PATH: ${PATH}:/builds/softwareradiosystems/srsgnb/build/apps/gnb - shared_files: - - local_path: ${GNB_BINARY_PATH} - remote_path: /usr/local/bin/gnb - is_executable: true - -- name: open5gs - type: 5gc - requirements: - arch: amd64 - cpu: - requests: 1 - limits: 1 - memory: - requests: "8G" - limits: "8G" - ephemeral-storage: - requests: "6G" - limits: "6G" - image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} diff --git a/.gitlab/ci/e2e/retina_request_zmq_cudu.yml b/.gitlab/ci/e2e/retina_request_zmq_cudu.yml index f448bf81f1..e8a292e3ec 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_cudu.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_cudu.yml @@ -10,7 +10,7 @@ type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} nof_ports: 32 requirements: arch: amd64 @@ -36,7 +36,7 @@ type: gnb image: ${RETINA_REGISTRY_PREFIX}/srscudu:${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 cpu: @@ -73,4 +73,4 @@ limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_deb.yml b/.gitlab/ci/e2e/retina_request_zmq_deb.yml index a7bb0b5d11..253f1910c5 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_deb.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_deb.yml @@ -10,7 +10,7 @@ type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} nof_ports: 4 requirements: arch: amd64 @@ -36,7 +36,7 @@ type: gnb image: ${RETINA_REGISTRY_PREFIX}/agent-ubuntu-${UBUNTU_VERSION}:${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 cpu: @@ -70,4 +70,4 @@ limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml index 6e5b272406..94a8badd1b 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml @@ -10,7 +10,7 @@ type: ue image: ${RETINA_REGISTRY_PREFIX}/srsue:${SRSUE_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 cpu: @@ -29,7 +29,7 @@ type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 cpu: @@ -65,4 +65,4 @@ limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_single_ue.yml b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml similarity index 77% rename from .gitlab/ci/e2e/retina_request_zmq_single_ue.yml rename to .gitlab/ci/e2e/retina_request_zmq_uesim.yml index 78b9cb20f2..85edb577cb 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_single_ue.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml @@ -8,24 +8,25 @@ - name: amarisoft-ue type: ue - image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} + image: ${RETINA_REGISTRY_PREFIX}/amarisoftue-remote:${RETINA_VERSION} labels: - ${ZMQ_HOSTLABEL_1} + nof_ports: 32 requirements: arch: amd64 cpu: - requests: 5 - limits: 5 + requests: 2 + limits: 2 memory: - requests: "26G" - limits: "26G" + requests: "4G" + limits: "4G" ephemeral-storage: requests: "6G" limits: "6G" resources: - type: zmq - - type: license - model: amarisoft-5g + - type: emulator + model: uesim shared_files: - local_path: ${AMARISOFT_TXRX_BINARY_PATH} remote_path: /opt/lteue/trx_srsran.so @@ -36,17 +37,18 @@ image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} labels: - ${ZMQ_HOSTLABEL_1} + force_external_ip: true requirements: arch: amd64 cpu: - requests: 5 - limits: 5 + requests: 16 + limits: 16 memory: - requests: "26G" - limits: "26G" + requests: "48G" + limits: "48G" ephemeral-storage: - requests: "6G" - limits: "6G" + requests: "15G" + limits: "15G" resources: - type: zmq environment: @@ -71,4 +73,4 @@ limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} labels: - - ${ZMQ_HOSTLABEL_1} + - ${ZMQ_HOSTLABEL_1} \ No newline at end of file diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index b104554417..04076932d4 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -363,7 +363,7 @@ def test_zmq_2x2_mimo( direction: IPerfDir, ): """ - ZMQ 4x4 mimo IPerfs + ZMQ 2x2 mimo IPerfs """ _iperf( @@ -385,6 +385,8 @@ def test_zmq_2x2_mimo( always_download_artifacts=True, rx_to_tx_latency=2, enable_dddsu=True, + nof_antennas_dl=2, + nof_antennas_ul=2, ) @@ -443,6 +445,8 @@ def test_zmq_4x4_mimo( global_timing_advance=-1, time_alignment_calibration=0, always_download_artifacts=False, + nof_antennas_dl=4, + nof_antennas_ul=4, ) @@ -672,6 +676,8 @@ def _iperf( ue_stop_timeout: int = 0, rx_to_tx_latency: int = -1, enable_dddsu: bool = False, + nof_antennas_dl: int = 1, + nof_antennas_ul: int = 1, ): wait_before_power_off = 5 @@ -690,6 +696,8 @@ def _iperf( prach_config_index=prach_config_index, rx_to_tx_latency=rx_to_tx_latency, enable_dddsu=enable_dddsu, + nof_antennas_dl=nof_antennas_dl, + nof_antennas_ul=nof_antennas_ul, ) configure_artifacts( retina_data=retina_data, diff --git a/tests/e2e/tests/steps/configuration.py b/tests/e2e/tests/steps/configuration.py index ef8b2b17eb..0b8ca7e0a3 100644 --- a/tests/e2e/tests/steps/configuration.py +++ b/tests/e2e/tests/steps/configuration.py @@ -42,6 +42,8 @@ def configure_test_parameters( enable_security_mode: bool = False, rx_to_tx_latency: int = -1, enable_dddsu: bool = False, + nof_antennas_dl: int = 1, + nof_antennas_ul: int = 1, ): """ Configure test parameters @@ -61,6 +63,8 @@ def configure_test_parameters( "num_cells": num_cells, "cell_position_offset": cell_position_offset, "rx_to_tx_latency": rx_to_tx_latency, + "nof_antennas_dl": nof_antennas_dl, + "nof_antennas_ul": nof_antennas_ul, }, }, "gnb": { @@ -77,6 +81,8 @@ def configure_test_parameters( "num_cells": num_cells, "enable_security_mode": enable_security_mode, "enable_dddsu": enable_dddsu, + "nof_antennas_dl": nof_antennas_dl, + "nof_antennas_ul": nof_antennas_ul, }, }, } diff --git a/tests/e2e/tests/test_mode.py b/tests/e2e/tests/test_mode.py index 389d15ae2c..85e854108b 100644 --- a/tests/e2e/tests/test_mode.py +++ b/tests/e2e/tests/test_mode.py @@ -80,6 +80,8 @@ def test_ue( "gnb_id": 1, "log_level": "warning", "pcap": False, + "nof_antennas_dl": nof_ant, + "nof_antennas_ul": nof_ant, }, "templates": { "cu": str(Path(__file__).joinpath("../test_mode/config_ue.yml").resolve()), @@ -116,7 +118,7 @@ def test_ue( timeout=gnb_startup_timeout, post_commands=( "", - f"cell_cfg --nof_antennas_dl {nof_ant} --nof_antennas_ul {nof_ant}" + " " + extra_config, + extra_config, ), ), ) @@ -203,6 +205,8 @@ def _test_ru( "gnb_id": 1, "log_level": "warning", "pcap": False, + "nof_antennas_dl": nof_ant, + "nof_antennas_ul": nof_ant, }, "templates": { "cu": str(Path(__file__).joinpath("../test_mode/config_ru.yml").resolve()), diff --git a/tests/e2e/tests/test_mode/config_ru.yml b/tests/e2e/tests/test_mode/config_ru.yml index c2114475ec..5cad482059 100644 --- a/tests/e2e/tests/test_mode/config_ru.yml +++ b/tests/e2e/tests/test_mode/config_ru.yml @@ -20,8 +20,8 @@ cell_cfg: plmn: "00101" tac: 7 pci: 1 - nof_antennas_dl: 4 - nof_antennas_ul: 4 + nof_antennas_dl: {{nof_antennas_dl}} + nof_antennas_ul: {{nof_antennas_ul}} pdsch: min_ue_mcs: 27 mcs_table: qam256 diff --git a/tests/e2e/tests/test_mode/config_ue.yml b/tests/e2e/tests/test_mode/config_ue.yml index c7f822d2e3..b1fe7108d9 100644 --- a/tests/e2e/tests/test_mode/config_ue.yml +++ b/tests/e2e/tests/test_mode/config_ue.yml @@ -52,8 +52,8 @@ cell_cfg: nof_dl_symbols: 7 nof_dl_slots: 7 nof_ul_slots: 2 - # nof_antennas_dl: 1 - Set in gnb call. Please check it in agent.log - # nof_antennas_ul: 1 - Set in gnb call. Please check it in agent.log + nof_antennas_dl: {{nof_antennas_dl}} + nof_antennas_ul: {{nof_antennas_ul}} test_mode: test_ue: diff --git a/tests/e2e/tests/viavi.py b/tests/e2e/tests/viavi.py index 517e308f27..c2ee08d1df 100644 --- a/tests/e2e/tests/viavi.py +++ b/tests/e2e/tests/viavi.py @@ -333,6 +333,8 @@ def _test_viavi( "max_puschs_per_slot": test_declaration.max_puschs_per_slot, "max_pdschs_per_slot": test_declaration.max_pdschs_per_slot, "enable_qos_viavi": test_declaration.enable_qos_viavi, + "nof_antennas_dl": 4, + "nof_antennas_ul": 1, }, }, } From 0035e9bf80d57f06b884fe091e253cd63e87c3bd Mon Sep 17 00:00:00 2001 From: faluco Date: Thu, 1 Aug 2024 18:09:02 +0200 Subject: [PATCH 058/407] srslog: Implement vectorized context metrics --- include/srsran/srslog/context.h | 14 ++++++++++--- include/srsran/srslog/formatter.h | 9 +++++++++ .../unittests/srslog/json_formatter_test.cpp | 11 +++++++--- .../unittests/srslog/text_formatter_test.cpp | 20 +++++++++++-------- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/srsran/srslog/context.h b/include/srsran/srslog/context.h index 51c11da60b..a65c9160a3 100644 --- a/include/srsran/srslog/context.h +++ b/include/srsran/srslog/context.h @@ -13,6 +13,7 @@ #include "srsran/srslog/detail/support/tmpl_utils.h" #include #include +#include namespace srslog { @@ -127,7 +128,14 @@ struct metric { /// Template specialization that tags metrics with arithmetic values (integers /// and floating point) as numeric. template -struct metric_kind_selector, typename std::enable_if::value>::type> { +struct metric_kind_selector, std::enable_if_t>> { + static const metric_kind kind = metric_kind::numeric; +}; + +/// Template specialization that tags vector metrics with arithmetic values (integers +/// and floating point) as numeric. +template +struct metric_kind_selector, Name, Units>, std::enable_if_t>> { static const metric_kind kind = metric_kind::numeric; }; @@ -160,7 +168,7 @@ namespace detail { /// eg: using my_metric_t = srslog::build_metric_set_type; /// NOTE: Adding duplicated types into the list is not allowed. template -using build_metric_set_type = metric_set::type...>; +using build_metric_set_type = metric_set...>; } // namespace detail @@ -168,7 +176,7 @@ using build_metric_set_type = metric_set::type...> /// eg: using my_context_t = srslog::build_context_type; /// NOTE: Adding duplicated types into the list is not allowed. template -using build_context_type = context::type...>; +using build_context_type = context...>; /// This macro defines a new metric type using the following attributes: /// a) name: encoded as a string. diff --git a/include/srsran/srslog/formatter.h b/include/srsran/srslog/formatter.h index 4682491edf..7ba77f8129 100644 --- a/include/srsran/srslog/formatter.h +++ b/include/srsran/srslog/formatter.h @@ -39,6 +39,15 @@ struct metric_value_formatter> { } }; +template +struct metric_value_formatter, Name, Units>> { + template + void format(const T& v, fmt::memory_buffer& buffer) + { + fmt::format_to(buffer, "[{}]", fmt::join(v.cbegin(), v.cend(), ", ")); + } +}; + /// This is the base class that provides a common framework to format log /// entries to different kinds of formats. User should implement two different /// kinds of formats: diff --git a/tests/unittests/srslog/json_formatter_test.cpp b/tests/unittests/srslog/json_formatter_test.cpp index 82cea06c8f..0ed3e7f55d 100644 --- a/tests/unittests/srslog/json_formatter_test.cpp +++ b/tests/unittests/srslog/json_formatter_test.cpp @@ -72,7 +72,8 @@ DECLARE_METRIC_SET("RF", myset1, snr_t, pwr_t, cfreq_t); DECLARE_METRIC("Throughput", thr_t, float, "MB/s"); DECLARE_METRIC("Address", ip_addr_t, std::string, ""); -DECLARE_METRIC_SET("Network", myset2, thr_t, ip_addr_t); +DECLARE_METRIC("Value_Array", valarray_t, std::vector, ""); +DECLARE_METRIC_SET("Network", myset2, thr_t, ip_addr_t, valarray_t); using basic_ctx_t = srslog::build_context_type; } // namespace @@ -88,6 +89,7 @@ static bool when_log_entry_with_only_basic_context_is_passed_then_context_is_for ctx.get().write(1500); ctx.get().write(150.01); ctx.get().write("192.168.1.0"); + ctx.get().write(std::vector{1, 2, 3, 4}); fmt::memory_buffer buffer; json_formatter{}.format_ctx(ctx, std::move(entry), buffer); @@ -100,7 +102,8 @@ static bool when_log_entry_with_only_basic_context_is_passed_then_context_is_for " },\n" " \"Network\": {\n" " \"Throughput\": 150.01,\n" - " \"Address\": \"192.168.1.0\"\n" + " \"Address\": \"192.168.1.0\",\n" + " \"Value_Array\": [1, 2, 3, 4]\n" " }\n" "}\n"; @@ -120,6 +123,7 @@ static bool when_log_entry_with_message_and_basic_context_is_passed_then_context ctx.get().write(1500); ctx.get().write(150.01); ctx.get().write("192.168.1.0"); + ctx.get().write(std::vector{1, 2, 3, 4}); fmt::memory_buffer buffer; json_formatter{}.format_ctx(ctx, std::move(entry), buffer); @@ -133,7 +137,8 @@ static bool when_log_entry_with_message_and_basic_context_is_passed_then_context " },\n" " \"Network\": {\n" " \"Throughput\": 150.01,\n" - " \"Address\": \"192.168.1.0\"\n" + " \"Address\": \"192.168.1.0\",\n" + " \"Value_Array\": [1, 2, 3, 4]\n" " }\n" "}\n"; diff --git a/tests/unittests/srslog/text_formatter_test.cpp b/tests/unittests/srslog/text_formatter_test.cpp index 55293e97bc..1c6d484369 100644 --- a/tests/unittests/srslog/text_formatter_test.cpp +++ b/tests/unittests/srslog/text_formatter_test.cpp @@ -122,8 +122,9 @@ DECLARE_METRIC_SET("ue_container", ue_set, thr_t, ip_addr_t, antenna_list_t); DECLARE_METRIC("type", entry_type_t, std::string, ""); DECLARE_METRIC("sector_id", sector_id_t, unsigned, ""); +DECLARE_METRIC("Value_Array", valarray_t, std::vector, ""); DECLARE_METRIC_LIST("ue_list", ue_list_t, std::vector); -DECLARE_METRIC_SET("sector_metrics", sector_set, entry_type_t, sector_id_t, ue_list_t); +DECLARE_METRIC_SET("sector_metrics", sector_set, entry_type_t, sector_id_t, valarray_t, ue_list_t); DECLARE_METRIC_LIST("sector_list", sector_list_t, std::vector); @@ -139,6 +140,7 @@ static complex_ctx_t build_complex_context() ctx.get().emplace_back(); ctx.at(0).write("event"); ctx.at(0).write(1); + ctx.at(0).write(std::vector{1, 2, 3, 4}); ctx.at(0).get().emplace_back(); ctx.at(0).at(0).write(1.2); @@ -181,6 +183,7 @@ static bool when_log_entry_with_only_context_is_passed_then_context_is_formatted " > Set: sector_metrics\n" " type: event\n" " sector_id: 1\n" + " Value_Array: [1, 2, 3, 4]\n" " > List: ue_list\n" " > Set: ue_container\n" " Throughput: 1.2 MB/s\n" @@ -216,13 +219,14 @@ static bool when_log_entry_with_context_and_message_is_passed_then_context_is_fo fmt::memory_buffer buffer; text_formatter{}.format_ctx(ctx, std::move(entry), buffer); - std::string result = fmt::to_string(buffer); - std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [Z] [ 99.99] [[sector_metrics_type: event, " - "sector_metrics_sector_id: 1, [ue_container_Throughput: 1.2 MB/s, " - "ue_container_Address: 10.20.30.40, [RF_SNR: 5.1 dB, RF_PWR: -11 " - "dBm][RF_SNR: 10.1 dB, RF_PWR: -20 dBm]][ue_container_Throughput: 10.2 " - "MB/s, ue_container_Address: 10.20.30.41, [RF_SNR: 20.1 dB, RF_PWR: -30 " - "dBm][RF_SNR: 30.1 dB, RF_PWR: -40 dBm]]]]: Text 88\n"; + std::string result = fmt::to_string(buffer); + std::string expected = + "1970-01-01T00:00:00.050000 [ABC ] [Z] [ 99.99] [[sector_metrics_type: event, " + "sector_metrics_sector_id: 1, sector_metrics_Value_Array: [1, 2, 3, 4], [ue_container_Throughput: 1.2 MB/s, " + "ue_container_Address: 10.20.30.40, [RF_SNR: 5.1 dB, RF_PWR: -11 " + "dBm][RF_SNR: 10.1 dB, RF_PWR: -20 dBm]][ue_container_Throughput: 10.2 " + "MB/s, ue_container_Address: 10.20.30.41, [RF_SNR: 20.1 dB, RF_PWR: -30 " + "dBm][RF_SNR: 30.1 dB, RF_PWR: -40 dBm]]]]: Text 88\n"; ASSERT_EQ(result, expected); From 1db2fbc0cda140a2c35998bef6e31f56ed879370 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 29 Jul 2024 15:26:13 +0200 Subject: [PATCH 059/407] ran: add PRACH Format B4 configuration for FR2 ran: minor correction --- .../srsran/ran/prach/prach_configuration.h | 13 +- include/srsran/ran/prach/prach_format_type.h | 5 +- lib/ran/prach/prach_configuration.cpp | 763 ++++++++++++------ .../common_scheduling/prach_scheduler.cpp | 4 +- .../ran/prach/prach_configuration_test.cpp | 168 ++++ .../prach_scheduler_test.cpp | 4 +- 6 files changed, 707 insertions(+), 250 deletions(-) diff --git a/include/srsran/ran/prach/prach_configuration.h b/include/srsran/ran/prach/prach_configuration.h index 8cccfa91d8..725cc4e9fc 100644 --- a/include/srsran/ran/prach/prach_configuration.h +++ b/include/srsran/ran/prach/prach_configuration.h @@ -31,12 +31,16 @@ struct prach_configuration { /// SFN period, \f$x\f$. unsigned x; /// SFN offset \f$y\f$. - unsigned y; + static_vector y; /// Subframes within a frame that contain PRACH occasions. - static_vector subframe; + static_vector subframe; /// Starting OFDM symbol index. uint8_t starting_symbol; - /// Number of PRACH slots within a subframe. Set zero for reserved. + /// \brief Number of PRACH slots. Set zero for reserved. + /// + /// Depending on the frequency range: + /// - FR1: within a subframe (15 kHz slot); or + /// - FR2: within a 60 kHz slot. uint8_t nof_prach_slots_within_subframe; /// Number of time-domain PRACH occasions within a PRACH slot. Set zero for reserved. uint8_t nof_occasions_within_slot; @@ -45,8 +49,7 @@ struct prach_configuration { }; /// Reserved PRACH configuration. Indicates the configuration parameters are invalid. -static const prach_configuration PRACH_CONFIG_RESERVED = - {prach_format_type::invalid, UINT32_MAX, UINT32_MAX, {}, 0, 0, 0, 0}; +static const prach_configuration PRACH_CONFIG_RESERVED = {prach_format_type::invalid, UINT32_MAX, {}, {}, 0, 0, 0, 0}; /// \brief Gets a PRACH configuration. /// diff --git a/include/srsran/ran/prach/prach_format_type.h b/include/srsran/ran/prach/prach_format_type.h index 4bc78f227b..8722112302 100644 --- a/include/srsran/ran/prach/prach_format_type.h +++ b/include/srsran/ran/prach/prach_format_type.h @@ -65,11 +65,10 @@ inline constexpr const char* to_string(prach_format_type format) return "C0"; case prach_format_type::C2: return "C2"; - default: - srsran_assert(0, "Invalid PRACH format={}", format); + case prach_format_type::invalid: break; } - return ""; + return "invalid"; } inline prach_format_type to_prach_format_type(const char* string) diff --git a/lib/ran/prach/prach_configuration.cpp b/lib/ran/prach/prach_configuration.cpp index f00e600c41..88da2780f2 100644 --- a/lib/ran/prach/prach_configuration.cpp +++ b/lib/ran/prach/prach_configuration.cpp @@ -16,114 +16,114 @@ static prach_configuration prach_configuration_get_fr1_paired(uint8_t prach_conf { // TS38.211 Table 6.3.3.2-2. static const std::array table = { - {{prach_format_type::zero, 16, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::zero, 16, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 16, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::zero, 16, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 8, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::zero, 8, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 8, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::zero, 8, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 4, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::zero, 4, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 4, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::zero, 4, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 6}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {2, 7}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {3, 8}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 4, 7}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {2, 5, 8}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {3, 6, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {0, 2, 4, 6, 8}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::one, 16, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::one, 16, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::one, 16, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 16, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::one, 8, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::one, 8, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::one, 8, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 8, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::one, 4, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::one, 4, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::one, 4, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 4, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::one, 2, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::one, 2, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::one, 2, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 2, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {1}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {1, 6}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {2, 7}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {3, 8}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {1, 4, 7}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {2, 5, 8}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {3, 6, 9}, 0, 0, 0, 0}, - {prach_format_type::two, 16, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::two, 8, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::two, 4, 0, {1}, 0, 0, 0, 0}, - {prach_format_type::two, 2, 0, {1}, 0, 0, 0, 0}, - {prach_format_type::two, 2, 0, {5}, 0, 0, 0, 0}, - {prach_format_type::two, 1, 0, {1}, 0, 0, 0, 0}, - {prach_format_type::two, 1, 0, {5}, 0, 0, 0, 0}, - {prach_format_type::three, 16, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::three, 16, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 16, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::three, 16, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 8, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::three, 8, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 8, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::three, 4, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::three, 4, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 4, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::three, 4, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 1, {1}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 6}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {2, 7}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {3, 8}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 4, 7}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {2, 5, 8}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {3, 6, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {0, 2, 4, 6, 8}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::A1, 16, 0, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 16, 1, {4}, 0, 2, 6, 2}, - {prach_format_type::A1, 8, 0, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 8, 1, {4}, 0, 2, 6, 2}, - {prach_format_type::A1, 4, 0, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 4, 1, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 4, 0, {4}, 0, 2, 6, 2}, - {prach_format_type::A1, 2, 0, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 2, 0, {1}, 0, 2, 6, 2}, - {prach_format_type::A1, 2, 0, {4}, 0, 2, 6, 2}, - {prach_format_type::A1, 2, 0, {7}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {4}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {1, 6}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {1}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {7}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {2, 7}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {1, 4, 7}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {0, 2, 4, 6, 8}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {1, 3, 5, 7, 9}, 0, 2, 6, 2}, + {{prach_format_type::zero, 16, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::zero, 16, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 16, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::zero, 16, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 8, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::zero, 8, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 8, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::zero, 8, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 4, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::zero, 4, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 4, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::zero, 4, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 6}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {2, 7}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {3, 8}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 4, 7}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {2, 5, 8}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {3, 6, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {0, 2, 4, 6, 8}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::one, 16, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::one, 16, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::one, 16, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 16, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::one, 8, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::one, 8, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::one, 8, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 8, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::one, 4, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::one, 4, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::one, 4, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 4, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::one, 2, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::one, 2, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::one, 2, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 2, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {1}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {1, 6}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {2, 7}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {3, 8}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {1, 4, 7}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {2, 5, 8}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {3, 6, 9}, 0, 0, 0, 0}, + {prach_format_type::two, 16, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::two, 8, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::two, 4, {0}, {1}, 0, 0, 0, 0}, + {prach_format_type::two, 2, {0}, {1}, 0, 0, 0, 0}, + {prach_format_type::two, 2, {0}, {5}, 0, 0, 0, 0}, + {prach_format_type::two, 1, {0}, {1}, 0, 0, 0, 0}, + {prach_format_type::two, 1, {0}, {5}, 0, 0, 0, 0}, + {prach_format_type::three, 16, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::three, 16, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 16, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::three, 16, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 8, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::three, 8, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 8, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::three, 4, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::three, 4, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 4, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::three, 4, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {1}, {1}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 6}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {2, 7}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {3, 8}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 4, 7}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {2, 5, 8}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {3, 6, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {0, 2, 4, 6, 8}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::A1, 16, {0}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 16, {1}, {4}, 0, 2, 6, 2}, + {prach_format_type::A1, 8, {0}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 8, {1}, {4}, 0, 2, 6, 2}, + {prach_format_type::A1, 4, {0}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 4, {1}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 4, {0}, {4}, 0, 2, 6, 2}, + {prach_format_type::A1, 2, {0}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 2, {0}, {1}, 0, 2, 6, 2}, + {prach_format_type::A1, 2, {0}, {4}, 0, 2, 6, 2}, + {prach_format_type::A1, 2, {0}, {7}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {4}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {1, 6}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {1}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {7}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {2, 7}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {1, 4, 7}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {0, 2, 4, 6, 8}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {1, 3, 5, 7, 9}, 0, 2, 6, 2}, /* A1/B1 */ {PRACH_CONFIG_RESERVED}, /* A1/B1 */ {PRACH_CONFIG_RESERVED}, /* A1/B1 */ {PRACH_CONFIG_RESERVED}, @@ -214,27 +214,27 @@ static prach_configuration prach_configuration_get_fr1_paired(uint8_t prach_conf /* B1 */ {PRACH_CONFIG_RESERVED}, /* B1 */ {PRACH_CONFIG_RESERVED}, /* B1 */ {PRACH_CONFIG_RESERVED}, - {prach_format_type::B4, 16, 0, {4, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 16, 1, {4}, 0, 2, 1, 12}, - {prach_format_type::B4, 8, 0, {4, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 8, 1, {4}, 0, 2, 1, 12}, - {prach_format_type::B4, 4, 0, {4, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 4, 0, {4}, 0, 2, 1, 12}, - {prach_format_type::B4, 4, 1, {4, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 2, 0, {4, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 2, 0, {1}, 0, 2, 1, 12}, - {prach_format_type::B4, 2, 0, {4}, 0, 2, 1, 12}, - {prach_format_type::B4, 2, 0, {7}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {1}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {4}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {7}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {1, 6}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {2, 7}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {4, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {1, 4, 7}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {0, 2, 4, 6, 8}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 2, 1, 12}, - {prach_format_type::B4, 1, 0, {1, 3, 5, 7, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 16, {0}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 16, {1}, {4}, 0, 2, 1, 12}, + {prach_format_type::B4, 8, {0}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 8, {1}, {4}, 0, 2, 1, 12}, + {prach_format_type::B4, 4, {0}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 4, {0}, {4}, 0, 2, 1, 12}, + {prach_format_type::B4, 4, {1}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {0}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {0}, {1}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {0}, {4}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {0}, {7}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {1}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {4}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {7}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {1, 6}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {2, 7}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {1, 4, 7}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {0, 2, 4, 6, 8}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {1, 3, 5, 7, 9}, 0, 2, 1, 12}, /* C0 */ {PRACH_CONFIG_RESERVED}, /* C0 */ {PRACH_CONFIG_RESERVED}, /* C0 */ {PRACH_CONFIG_RESERVED}, @@ -280,93 +280,93 @@ static prach_configuration prach_configuration_get_fr1_unpaired(uint8_t prach_co { // TS38.211 Table 6.3.3.2-3. static const std::array table = { - {{prach_format_type::zero, 16, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 8, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 4, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 0, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 2, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {8}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {6}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {5}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {3}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {2}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 6}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 6}, 7, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {4, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {3, 8}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {2, 7}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {8, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {4, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {3, 4, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {7, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {3, 4, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {6, 7, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 4, 6, 9}, 0, 0, 0, 0}, - {prach_format_type::zero, 1, 0, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, - {prach_format_type::one, 16, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 8, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 4, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 2, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 2, 1, {7}, 0, 0, 0, 0}, - {prach_format_type::one, 1, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::two, 16, 1, {6}, 0, 0, 0, 0}, - {prach_format_type::two, 8, 1, {6}, 0, 0, 0, 0}, - {prach_format_type::two, 4, 1, {6}, 0, 0, 0, 0}, - {prach_format_type::two, 2, 0, {6}, 7, 0, 0, 0}, - {prach_format_type::two, 2, 1, {6}, 7, 0, 0, 0}, - {prach_format_type::two, 1, 0, {6}, 7, 0, 0, 0}, - {prach_format_type::three, 16, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 8, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 4, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 0, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 1, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 2, 1, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {8}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {7}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {6}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {5}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {4}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {3}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {2}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 6}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 6}, 7, 0, 0, 0}, - {prach_format_type::three, 1, 0, {4, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {3, 8}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {2, 7}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {8, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {4, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {3, 4, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {7, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {3, 4, 8, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 4, 6, 9}, 0, 0, 0, 0}, - {prach_format_type::three, 1, 0, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, - {prach_format_type::A1, 16, 1, {9}, 0, 2, 6, 2}, - {prach_format_type::A1, 8, 1, {9}, 0, 2, 6, 2}, - {prach_format_type::A1, 4, 1, {9}, 0, 1, 6, 2}, - {prach_format_type::A1, 2, 1, {9}, 0, 1, 6, 2}, - {prach_format_type::A1, 2, 1, {4, 9}, 7, 1, 3, 2}, - {prach_format_type::A1, 2, 1, {7, 9}, 7, 1, 3, 2}, - {prach_format_type::A1, 2, 1, {7, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 2, 1, {8, 9}, 0, 2, 6, 2}, - {prach_format_type::A1, 2, 1, {4, 9}, 0, 2, 6, 2}, - {prach_format_type::A1, 2, 1, {2, 3, 4, 7, 8, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {9}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {9}, 7, 1, 3, 2}, - {prach_format_type::A1, 1, 0, {9}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {8, 9}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {4, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {7, 9}, 7, 1, 3, 2}, - {prach_format_type::A1, 1, 0, {3, 4, 8, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {3, 4, 8, 9}, 0, 2, 6, 2}, - {prach_format_type::A1, 1, 0, {1, 3, 5, 7, 9}, 0, 1, 6, 2}, - {prach_format_type::A1, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7, 1, 3, 2}, + {{prach_format_type::zero, 16, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 8, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 4, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {0}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 2, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {8}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {6}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {5}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {3}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {2}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 6}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 6}, 7, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {4, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {3, 8}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {2, 7}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {8, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {4, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {3, 4, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {7, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {3, 4, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {6, 7, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 4, 6, 9}, 0, 0, 0, 0}, + {prach_format_type::zero, 1, {0}, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, + {prach_format_type::one, 16, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 8, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 4, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 2, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 2, {1}, {7}, 0, 0, 0, 0}, + {prach_format_type::one, 1, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::two, 16, {1}, {6}, 0, 0, 0, 0}, + {prach_format_type::two, 8, {1}, {6}, 0, 0, 0, 0}, + {prach_format_type::two, 4, {1}, {6}, 0, 0, 0, 0}, + {prach_format_type::two, 2, {0}, {6}, 7, 0, 0, 0}, + {prach_format_type::two, 2, {1}, {6}, 7, 0, 0, 0}, + {prach_format_type::two, 1, {0}, {6}, 7, 0, 0, 0}, + {prach_format_type::three, 16, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 8, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 4, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {0}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {1}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 2, {1}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {8}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {7}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {6}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {5}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {4}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {3}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {2}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 6}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 6}, 7, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {4, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {3, 8}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {2, 7}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {8, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {4, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {3, 4, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {7, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {3, 4, 8, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 4, 6, 9}, 0, 0, 0, 0}, + {prach_format_type::three, 1, {0}, {1, 3, 5, 7, 9}, 0, 0, 0, 0}, + {prach_format_type::A1, 16, {1}, {9}, 0, 2, 6, 2}, + {prach_format_type::A1, 8, {1}, {9}, 0, 2, 6, 2}, + {prach_format_type::A1, 4, {1}, {9}, 0, 1, 6, 2}, + {prach_format_type::A1, 2, {1}, {9}, 0, 1, 6, 2}, + {prach_format_type::A1, 2, {1}, {4, 9}, 7, 1, 3, 2}, + {prach_format_type::A1, 2, {1}, {7, 9}, 7, 1, 3, 2}, + {prach_format_type::A1, 2, {1}, {7, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 2, {1}, {8, 9}, 0, 2, 6, 2}, + {prach_format_type::A1, 2, {1}, {4, 9}, 0, 2, 6, 2}, + {prach_format_type::A1, 2, {1}, {2, 3, 4, 7, 8, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {9}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {9}, 7, 1, 3, 2}, + {prach_format_type::A1, 1, {0}, {9}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {8, 9}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {4, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {7, 9}, 7, 1, 3, 2}, + {prach_format_type::A1, 1, {0}, {3, 4, 8, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {3, 4, 8, 9}, 0, 2, 6, 2}, + {prach_format_type::A1, 1, {0}, {1, 3, 5, 7, 9}, 0, 1, 6, 2}, + {prach_format_type::A1, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7, 1, 3, 2}, /* A2 */ {PRACH_CONFIG_RESERVED}, /* A2 */ {PRACH_CONFIG_RESERVED}, /* A2 */ {PRACH_CONFIG_RESERVED}, @@ -425,30 +425,30 @@ static prach_configuration prach_configuration_get_fr1_unpaired(uint8_t prach_co /* B1 */ {PRACH_CONFIG_RESERVED}, /* B1 */ {PRACH_CONFIG_RESERVED}, /* B1 */ {PRACH_CONFIG_RESERVED}, - /* B4 */ {prach_format_type::B4, 16, 1, {9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 8, 1, {9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 4, 1, {9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {9}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {7, 9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {4, 9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {4, 9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {8, 9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 2, 1, {2, 3, 4, 7, 8, 9}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {1}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {2}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {4}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {7}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {9}, 0, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {4, 9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {7, 9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {8, 9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {3, 4, 8, 9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {1, 3, 5, 7, 9}, 2, 1, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 2, 1, 12}, - /* B4 */ {prach_format_type::B4, 1, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 16, {1}, {9}, 0, 2, 1, 12}, + {prach_format_type::B4, 8, {1}, {9}, 0, 2, 1, 12}, + {prach_format_type::B4, 4, {1}, {9}, 2, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {9}, 0, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {9}, 2, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {7, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {4, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {4, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {1}, {8, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {1}, {2, 3, 4, 7, 8, 9}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {1}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {2}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {4}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {7}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {9}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {9}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {9}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {4, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {7, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {8, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {3, 4, 8, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {1, 3, 5, 7, 9}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 2, 1, 1, 12}, /* C0 */ {PRACH_CONFIG_RESERVED}, /* C0 */ {PRACH_CONFIG_RESERVED}, /* C0 */ {PRACH_CONFIG_RESERVED}, @@ -540,6 +540,285 @@ static prach_configuration prach_configuration_get_fr1_unpaired(uint8_t prach_co return table[prach_config_index]; } +static prach_configuration prach_configuration_get_fr2_unpaired(uint8_t prach_config_index) +{ + // TS38.211 Table 6.3.3.2-4. + static const std::array table = + {{/* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A1 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A2 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* A3 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + /* B1 */ {PRACH_CONFIG_RESERVED}, + {prach_format_type::B4, 16, {1, 2}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 16, {1, 2}, {3, 7, 11, 15, 19, 23, 27, 31, 35, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 8, {1, 2}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 8, {1, 2}, {3, 7, 11, 15, 19, 23, 27, 31, 35, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 8, {1, 2}, {9, 19, 29, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 4, {1}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 4, {1}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 4, {1, 2}, {3, 7, 11, 15, 19, 23, 27, 31, 35, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {7, 15, 23, 31, 39}, 2, 2, 1, 12}, + {prach_format_type::B4, 2, {1}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 2, {1}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 2, {1}, {3, 7, 11, 15, 19, 23, 27, 31, 35, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {19, 39}, 2, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {17, 19, 37, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {24, 29, 34, 39}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {9, 19, 29, 39}, 2, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {9, 19, 29, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {7, 15, 23, 31, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {7, 15, 23, 31, 39}, 0, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {23, 27, 31, 35, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {23, 27, 31, 35, 39}, 2, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {9, 11, 13, 15, 17, 19}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {3, 5, 7, 9, 11, 13}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {4, 9, 14, 19, 24, 29, 34, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {4, 9, 14, 19, 24, 29, 34, 39}, 2, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {13, 14, 15, 29, 30, 31, 37, 38, 39}, 2, 2, 1, 12}, + {prach_format_type::B4, 1, {0}, {3, 7, 11, 15, 19, 23, 27, 31, 35, 39}, 0, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {3, 7, 11, 15, 19, 23, 27, 31, 35, 39}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25}, 2, 1, 1, 12}, + {prach_format_type::B4, 1, {0}, {3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25}, 0, 2, 1, 12}, + {prach_format_type::B4, + 1, + {0}, + {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39}, + 0, + 1, + 1, + 12}, + {prach_format_type::B4, + 1, + {0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, + 2, + 1, + 1, + 12}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C0 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* C2 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A1/B1 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A2/B2 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}, + /* A3/B3 */ {PRACH_CONFIG_RESERVED}}}; + + return table[prach_config_index]; +} + prach_configuration srsran::prach_configuration_get(frequency_range fr, duplex_mode dm, uint8_t prach_config_index) { if ((fr == frequency_range::FR1) && (dm == duplex_mode::FDD || dm == duplex_mode::SUL)) { @@ -550,5 +829,9 @@ prach_configuration srsran::prach_configuration_get(frequency_range fr, duplex_m return prach_configuration_get_fr1_unpaired(prach_config_index); } + if ((fr == frequency_range::FR2) && (dm == duplex_mode::TDD)) { + return prach_configuration_get_fr2_unpaired(prach_config_index); + } + return PRACH_CONFIG_RESERVED; } diff --git a/lib/scheduler/common_scheduling/prach_scheduler.cpp b/lib/scheduler/common_scheduling/prach_scheduler.cpp index 7a8c96ff99..51ffdb1185 100644 --- a/lib/scheduler/common_scheduling/prach_scheduler.cpp +++ b/lib/scheduler/common_scheduling/prach_scheduler.cpp @@ -142,7 +142,9 @@ void prach_scheduler::allocate_slot_prach_pdus(cell_resource_allocator& res_grid } } - if (sl.sfn() % prach_cfg.x != prach_cfg.y) { + bool prach_occasion_sfn = std::any_of( + prach_cfg.y.begin(), prach_cfg.y.end(), [this, sl](uint8_t y) { return sl.sfn() % prach_cfg.x != y; }); + if (prach_occasion_sfn) { // PRACH is not enabled in this SFN. return; } diff --git a/tests/unittests/ran/prach/prach_configuration_test.cpp b/tests/unittests/ran/prach/prach_configuration_test.cpp index 80d7c32d1c..7b9a08fd7a 100644 --- a/tests/unittests/ran/prach/prach_configuration_test.cpp +++ b/tests/unittests/ran/prach/prach_configuration_test.cpp @@ -10,11 +10,30 @@ #include "srsran/adt/span.h" #include "srsran/ran/prach/prach_configuration.h" +#include #include #include using namespace srsran; +namespace srsran { + +std::ostream& operator<<(std::ostream& os, prach_format_type format) +{ + fmt::print(os, "{}", to_string(format)); + return os; +} + +bool operator==(int left, const static_vector right) +{ + if (right.size() == 1) { + return left == right.front(); + } + return false; +} + +} // namespace srsran + TEST(PrachConfiguration, Fr1Paired) { for (unsigned prach_config_index = 0; prach_config_index != UINT8_MAX; ++prach_config_index) { @@ -476,3 +495,152 @@ TEST(PrachConfiguration, Fr1Unpaired) } } } + +TEST(PrachConfiguration, Fr2Unpaired) +{ + for (unsigned prach_config_index = 0; prach_config_index != UINT8_MAX; ++prach_config_index) { + prach_configuration config = prach_configuration_get(frequency_range::FR2, duplex_mode::TDD, prach_config_index); + + // Assert format. + if (prach_config_index < 112) { + ASSERT_EQ(config.format, PRACH_CONFIG_RESERVED.format); + } else if (prach_config_index < 144) { + ASSERT_EQ(config.format, prach_format_type::B4); + } else { + ASSERT_EQ(config.format, PRACH_CONFIG_RESERVED.format); + } + + // Assert x. + if (prach_config_index < 112) { + ASSERT_EQ(PRACH_CONFIG_RESERVED.x, config.x); + } else if (prach_config_index < 114) { + ASSERT_EQ(16, config.x); + } else if (prach_config_index < 117) { + ASSERT_EQ(8, config.x); + } else if (prach_config_index < 120) { + ASSERT_EQ(4, config.x); + } else if (prach_config_index < 124) { + ASSERT_EQ(2, config.x); + } else if (prach_config_index < 144) { + ASSERT_EQ(1, config.x); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.x, config.x); + } + + // Assert y. + static const static_vector value_y_0 = {0}; + static const static_vector value_y_1 = {1}; + static const static_vector value_y_1_2 = {1, 2}; + if (prach_config_index < 112) { + ASSERT_EQ(PRACH_CONFIG_RESERVED.y, config.y); + } else if ((prach_config_index < 117) || (prach_config_index == 119)) { + ASSERT_EQ(value_y_1_2, config.y); + } else if (prach_config_index < 124) { + ASSERT_EQ(value_y_1, config.y); + } else if (prach_config_index < 144) { + ASSERT_EQ(value_y_0, config.y); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.y, config.y); + } + + // Assert subframe number. + static const std::set config_subframe_4_9_etc = {112, 114, 117, 118, 121, 122, 135, 136}; + static const std::set config_subframe_3_7_etc = {113, 115, 119, 123, 138, 139}; + static const std::set config_subframe_9_19_etc = {116, 127, 128}; + static const std::set config_subframe_7_15_etc = {120, 129, 130}; + static const std::set config_subframe_19_39 = {124}; + static const std::set config_subframe_17_19_etc = {125}; + static const std::set config_subframe_24_29_etc = {126}; + static const std::set config_subframe_9_19_etc2 = {127, 128}; + static const std::set config_subframe_7_15_etc2 = {129, 130}; + static const std::set config_subframe_23_27_etc = {131, 132}; + static const std::set config_subframe_9_11_etc = {133}; + static const std::set config_subframe_3_5_etc = {134}; + static const std::set config_subframe_13_14_etc = {137}; + static const std::set config_subframe_3_5_etc2 = {140, 141}; + static const std::set config_subframe_1_3_etc = {142}; + static const std::set config_subframe_0_1_etc = {143}; + if (config_subframe_4_9_etc.count(prach_config_index)) { + ASSERT_EQ(span({4, 9, 14, 19, 24, 29, 34, 39}), span(config.subframe)); + } else if (config_subframe_3_7_etc.count(prach_config_index)) { + ASSERT_EQ(span({3, 7, 11, 15, 19, 23, 27, 31, 35, 39}), span(config.subframe)); + } else if (config_subframe_9_19_etc.count(prach_config_index)) { + ASSERT_EQ(span({9, 19, 29, 39}), span(config.subframe)); + } else if (config_subframe_7_15_etc.count(prach_config_index)) { + ASSERT_EQ(span({7, 15, 23, 31, 39}), span(config.subframe)); + } else if (config_subframe_19_39.count(prach_config_index)) { + ASSERT_EQ(span({19, 39}), span(config.subframe)); + } else if (config_subframe_17_19_etc.count(prach_config_index)) { + ASSERT_EQ(span({17, 19, 37, 39}), span(config.subframe)); + } else if (config_subframe_24_29_etc.count(prach_config_index)) { + ASSERT_EQ(span({24, 29, 34, 39}), span(config.subframe)); + } else if (config_subframe_9_19_etc2.count(prach_config_index)) { + ASSERT_EQ(span({9, 19, 29, 39}), span(config.subframe)); + } else if (config_subframe_7_15_etc2.count(prach_config_index)) { + ASSERT_EQ(span({7, 15, 23, 31, 39}), span(config.subframe)); + } else if (config_subframe_23_27_etc.count(prach_config_index)) { + ASSERT_EQ(span({23, 27, 31, 35, 39}), span(config.subframe)); + } else if (config_subframe_9_11_etc.count(prach_config_index)) { + ASSERT_EQ(span({9, 11, 13, 15, 17, 19}), span(config.subframe)); + } else if (config_subframe_3_5_etc.count(prach_config_index)) { + ASSERT_EQ(span({3, 5, 7, 9, 11, 13}), span(config.subframe)); + } else if (config_subframe_13_14_etc.count(prach_config_index)) { + ASSERT_EQ(span({13, 14, 15, 29, 30, 31, 37, 38, 39}), span(config.subframe)); + } else if (config_subframe_3_5_etc2.count(prach_config_index)) { + ASSERT_EQ(span({3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25}), + span(config.subframe)); + } else if (config_subframe_1_3_etc.count(prach_config_index)) { + ASSERT_EQ(span({1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39}), + span(config.subframe)); + } else if (config_subframe_0_1_etc.count(prach_config_index)) { + ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}), + span(config.subframe)); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.subframe, config.subframe) << "prach_config_index=" << prach_config_index; + } + + // Assert starting symbol. + static const std::set config_starting_symbol_2 = {120, 124, 126, 127, 132, 134, 136, 137, 139, 140, 143}; + if (config_starting_symbol_2.count(prach_config_index)) { + ASSERT_EQ(2, config.starting_symbol); + } else if (prach_config_index < 112) { + ASSERT_EQ(PRACH_CONFIG_RESERVED.starting_symbol, config.starting_symbol); + } else if (prach_config_index < 144) { + ASSERT_EQ(0, config.starting_symbol); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.starting_symbol, config.starting_symbol); + } + + // Assert number of PRACH slots within a 60 kHz slot. + static const std::set config_slots_2 = { + 112, 114, 116, 118, 120, 122, 124, 127, 128, 130, 132, 136, 137, 141}; + if (config_slots_2.count(prach_config_index)) { + ASSERT_EQ(2, config.nof_prach_slots_within_subframe); + } else if (prach_config_index < 112) { + ASSERT_EQ(PRACH_CONFIG_RESERVED.nof_prach_slots_within_subframe, config.nof_prach_slots_within_subframe); + } else if (prach_config_index < 144) { + ASSERT_EQ(1, config.nof_prach_slots_within_subframe); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.nof_prach_slots_within_subframe, config.nof_prach_slots_within_subframe); + } + + // Assert number of time-domain PRACH occasions within a PRACH slot. + if (prach_config_index < 112) { + ASSERT_EQ(PRACH_CONFIG_RESERVED.nof_occasions_within_slot, config.nof_occasions_within_slot); + } else if (prach_config_index < 144) { + ASSERT_EQ(1, config.nof_occasions_within_slot); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.nof_occasions_within_slot, config.nof_occasions_within_slot); + } + + // Assert PRACH duration. + if (prach_config_index < 112) { + ASSERT_EQ(PRACH_CONFIG_RESERVED.duration, config.duration); + } else if (prach_config_index < 144) { + ASSERT_EQ(12, config.duration); + } else { + ASSERT_EQ(PRACH_CONFIG_RESERVED.duration, config.duration); + } + } +} \ No newline at end of file diff --git a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp index cf7c5749f6..901455949f 100644 --- a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp @@ -107,7 +107,9 @@ class prach_tester : public ::testing::TestWithParam bool is_prach_slot() { - if (sl.sfn() % prach_cfg.x != prach_cfg.y) { + bool prach_occasion_sfn = + std::any_of(prach_cfg.y.begin(), prach_cfg.y.end(), [this](uint8_t y) { return sl.sfn() % prach_cfg.x != y; }); + if (prach_occasion_sfn) { return false; } if (std::find(prach_cfg.subframe.begin(), prach_cfg.subframe.end(), sl.subframe_index()) == From aaa52f175f498363423f797f700642f157c010cd Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 1 Aug 2024 09:39:11 +0200 Subject: [PATCH 060/407] ran: review PRACH configuration --- .../srsran/ran/prach/prach_configuration.h | 16 ++++- include/srsran/ran/prach/prach_format_type.h | 1 + .../ran/prach/prach_configuration_test.cpp | 72 +++++++++---------- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/include/srsran/ran/prach/prach_configuration.h b/include/srsran/ran/prach/prach_configuration.h index 725cc4e9fc..713f6dc9dd 100644 --- a/include/srsran/ran/prach/prach_configuration.h +++ b/include/srsran/ran/prach/prach_configuration.h @@ -26,14 +26,24 @@ namespace srsran { /// /// The PRACH transmission occasions are in the system frames \f$n_{SFN}\f$ that satisfy \f$n_{SFN} \bmod x = y\f$. struct prach_configuration { + /// Maximum number of system frame offsets. + static constexpr unsigned max_nof_sfn_offsets = 2; + /// Maximum number of PRACH slots per radio frame assuming a subcarrier spacing of 60kHz. + static constexpr unsigned max_nof_slots_per_frame = + NOF_SUBFRAMES_PER_FRAME * (1U << to_numerology_value(subcarrier_spacing::kHz60)); + /// Preamble format (see [here](\ref preamble_format) for more information). prach_format_type format; /// SFN period, \f$x\f$. unsigned x; /// SFN offset \f$y\f$. - static_vector y; - /// Subframes within a frame that contain PRACH occasions. - static_vector subframe; + static_vector y; + /// \brief Slots within a radio frame that contain PRACH occasions. + /// + /// The slot numbering assumes the subcarrier spacing: + /// - 15kHz for FR1; and + /// - 60kHz for FR2. + static_vector subframe; /// Starting OFDM symbol index. uint8_t starting_symbol; /// \brief Number of PRACH slots. Set zero for reserved. diff --git a/include/srsran/ran/prach/prach_format_type.h b/include/srsran/ran/prach/prach_format_type.h index 8722112302..5948b0f3be 100644 --- a/include/srsran/ran/prach/prach_format_type.h +++ b/include/srsran/ran/prach/prach_format_type.h @@ -66,6 +66,7 @@ inline constexpr const char* to_string(prach_format_type format) case prach_format_type::C2: return "C2"; case prach_format_type::invalid: + default: break; } return "invalid"; diff --git a/tests/unittests/ran/prach/prach_configuration_test.cpp b/tests/unittests/ran/prach/prach_configuration_test.cpp index 7b9a08fd7a..37ac7e576f 100644 --- a/tests/unittests/ran/prach/prach_configuration_test.cpp +++ b/tests/unittests/ran/prach/prach_configuration_test.cpp @@ -24,14 +24,6 @@ std::ostream& operator<<(std::ostream& os, prach_format_type format) return os; } -bool operator==(int left, const static_vector right) -{ - if (right.size() == 1) { - return left == right.front(); - } - return false; -} - } // namespace srsran TEST(PrachConfiguration, Fr1Paired) @@ -100,33 +92,35 @@ TEST(PrachConfiguration, Fr1Paired) } // Assert y. - static const std::set config_B4_y_1 = {199, 201, 204}; + static const std::set config_B4_y_1 = {199, 201, 204}; + static const static_vector value_y_0 = {0}; + static const static_vector value_y_1 = {1}; if (prach_config_index < 16) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 28) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 44) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 53) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 55) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 60) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 75) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 87) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 93) { - ASSERT_EQ((prach_config_index - 87) % 2, config.y); + ASSERT_EQ(((prach_config_index - 1) % 2) ? value_y_1 : value_y_0, config.y); } else if (prach_config_index < 108) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 198) { ASSERT_EQ(PRACH_CONFIG_RESERVED.y, config.y); } else if (config_B4_y_1.count(prach_config_index) > 0) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 219) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else { ASSERT_EQ(PRACH_CONFIG_RESERVED.x, config.x); } @@ -319,36 +313,38 @@ TEST(PrachConfiguration, Fr1Unpaired) } // Assert y. + static const static_vector value_y_0 = {0}; + static const static_vector value_y_1 = {1}; if (prach_config_index < 3) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 7) { - ASSERT_EQ((prach_config_index + 1) % 2, config.y); + ASSERT_EQ(((prach_config_index + 1) % 2) ? value_y_1 : value_y_0, config.y); } else if (prach_config_index < 28) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 31) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 34) { - ASSERT_EQ((prach_config_index - 1) % 2, config.y); + ASSERT_EQ(((prach_config_index - 1) % 2) ? value_y_1 : value_y_0, config.y); } else if (prach_config_index < 36) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 40) { - ASSERT_EQ((prach_config_index + 1) % 2, config.y); + ASSERT_EQ(((prach_config_index + 1) % 2) ? value_y_1 : value_y_0, config.y); } else if (prach_config_index < 42) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 47) { - ASSERT_EQ((prach_config_index + 1) % 2, config.y); + ASSERT_EQ(((prach_config_index + 1) % 2) ? value_y_1 : value_y_0, config.y); } else if (prach_config_index < 67) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 77) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 87) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else if (prach_config_index < 145) { ASSERT_EQ(PRACH_CONFIG_RESERVED.y, config.y); } else if (prach_config_index < 155) { - ASSERT_EQ(1, config.y); + ASSERT_EQ(value_y_1, config.y); } else if (prach_config_index < 169) { - ASSERT_EQ(0, config.y); + ASSERT_EQ(value_y_0, config.y); } else { ASSERT_EQ(PRACH_CONFIG_RESERVED.y, config.y); } @@ -528,9 +524,9 @@ TEST(PrachConfiguration, Fr2Unpaired) } // Assert y. - static const static_vector value_y_0 = {0}; - static const static_vector value_y_1 = {1}; - static const static_vector value_y_1_2 = {1, 2}; + static const static_vector value_y_0 = {0}; + static const static_vector value_y_1 = {1}; + static const static_vector value_y_1_2 = {1, 2}; if (prach_config_index < 112) { ASSERT_EQ(PRACH_CONFIG_RESERVED.y, config.y); } else if ((prach_config_index < 117) || (prach_config_index == 119)) { From e3f76b6adbb4086ef58cbabe24f7d12af3bad3d6 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 1 Aug 2024 15:34:39 +0200 Subject: [PATCH 061/407] ran: review PRACH configuration --- .../srsran/ran/prach/prach_configuration.h | 4 +- lib/ran/prach/prach_helper.cpp | 2 +- .../common_scheduling/prach_scheduler.cpp | 2 +- .../ran/prach/prach_configuration_test.cpp | 137 +++++++++--------- .../prach_scheduler_test.cpp | 3 +- 5 files changed, 73 insertions(+), 75 deletions(-) diff --git a/include/srsran/ran/prach/prach_configuration.h b/include/srsran/ran/prach/prach_configuration.h index 713f6dc9dd..0279de62ee 100644 --- a/include/srsran/ran/prach/prach_configuration.h +++ b/include/srsran/ran/prach/prach_configuration.h @@ -29,7 +29,7 @@ struct prach_configuration { /// Maximum number of system frame offsets. static constexpr unsigned max_nof_sfn_offsets = 2; /// Maximum number of PRACH slots per radio frame assuming a subcarrier spacing of 60kHz. - static constexpr unsigned max_nof_slots_per_frame = + static constexpr unsigned max_nof_slots_60kHz_frame = NOF_SUBFRAMES_PER_FRAME * (1U << to_numerology_value(subcarrier_spacing::kHz60)); /// Preamble format (see [here](\ref preamble_format) for more information). @@ -43,7 +43,7 @@ struct prach_configuration { /// The slot numbering assumes the subcarrier spacing: /// - 15kHz for FR1; and /// - 60kHz for FR2. - static_vector subframe; + static_vector slots; /// Starting OFDM symbol index. uint8_t starting_symbol; /// \brief Number of PRACH slots. Set zero for reserved. diff --git a/lib/ran/prach/prach_helper.cpp b/lib/ran/prach/prach_helper.cpp index e41d74f58b..e2cfd7a00b 100644 --- a/lib/ran/prach/prach_helper.cpp +++ b/lib/ran/prach/prach_helper.cpp @@ -75,7 +75,7 @@ error_type> srsran::prach_helper::prach_fits_in_tdd_pattern(su const prach_symbols_slots_duration dur = get_prach_duration_info(prach_cfg, pusch_scs); // For each subframe with PRACH, check if all slots are UL. - for (uint8_t subframe_index : prach_cfg.subframe) { + for (uint8_t subframe_index : prach_cfg.slots) { // There are configuration for which the PRACH starts in an odd slot within the subframe // (for numerologies > mu(SCS 15kHz)); the addition of start_slot_pusch_scs compensate for this. uint8_t start_slot_index = subframe_index * nof_slots_per_subframe + dur.start_slot_pusch_scs; diff --git a/lib/scheduler/common_scheduling/prach_scheduler.cpp b/lib/scheduler/common_scheduling/prach_scheduler.cpp index 51ffdb1185..53a2392808 100644 --- a/lib/scheduler/common_scheduling/prach_scheduler.cpp +++ b/lib/scheduler/common_scheduling/prach_scheduler.cpp @@ -30,7 +30,7 @@ prach_scheduler::prach_scheduler(const cell_configuration& cfg_) : static const unsigned nof_symbols_per_slot = NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; // Convert list of PRACH subframe occasions to bitmap. - for (const unsigned pos : prach_cfg.subframe) { + for (const unsigned pos : prach_cfg.slots) { prach_subframe_occasion_bitmap.set(pos, true); } diff --git a/tests/unittests/ran/prach/prach_configuration_test.cpp b/tests/unittests/ran/prach/prach_configuration_test.cpp index 37ac7e576f..52dd9c6726 100644 --- a/tests/unittests/ran/prach/prach_configuration_test.cpp +++ b/tests/unittests/ran/prach/prach_configuration_test.cpp @@ -151,61 +151,61 @@ TEST(PrachConfiguration, Fr1Paired) static const std::array, 4> repeat_sequence = {{{1}, {4}, {7}, {9}}}; if (prach_config_index < 19) { ASSERT_EQ(span(repeat_sequence[prach_config_index % repeat_sequence.size()]), - span(config.subframe)); + span(config.slots)); } else if (prach_config_index == 19 || prach_config_index == 47 || prach_config_index == 78) { - ASSERT_EQ(span({1, 6}), span(config.subframe)); + ASSERT_EQ(span({1, 6}), span(config.slots)); } else if (prach_config_index == 20 || prach_config_index == 48 || prach_config_index == 79) { - ASSERT_EQ(span({2, 7}), span(config.subframe)); + ASSERT_EQ(span({2, 7}), span(config.slots)); } else if (prach_config_index == 21 || prach_config_index == 49 || prach_config_index == 80) { - ASSERT_EQ(span({3, 8}), span(config.subframe)); + ASSERT_EQ(span({3, 8}), span(config.slots)); } else if (prach_config_index == 22 || prach_config_index == 50 || prach_config_index == 81) { - ASSERT_EQ(span({1, 4, 7}), span(config.subframe)); + ASSERT_EQ(span({1, 4, 7}), span(config.slots)); } else if (prach_config_index == 23 || prach_config_index == 51 || prach_config_index == 82) { - ASSERT_EQ(span({2, 5, 8}), span(config.subframe)); + ASSERT_EQ(span({2, 5, 8}), span(config.slots)); } else if (prach_config_index == 24 || prach_config_index == 52 || prach_config_index == 83) { - ASSERT_EQ(span({3, 6, 9}), span(config.subframe)); + ASSERT_EQ(span({3, 6, 9}), span(config.slots)); } else if (prach_config_index == 25 || prach_config_index == 84) { - ASSERT_EQ(span({0, 2, 4, 6, 8}), span(config.subframe)); + ASSERT_EQ(span({0, 2, 4, 6, 8}), span(config.slots)); } else if (prach_config_index == 26 || prach_config_index == 85) { - ASSERT_EQ(span({1, 3, 5, 7, 9}), span(config.subframe)); + ASSERT_EQ(span({1, 3, 5, 7, 9}), span(config.slots)); } else if (prach_config_index == 27 || prach_config_index == 86) { - ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), span(config.slots)); } else if (prach_config_index < 47) { ASSERT_EQ(span(repeat_sequence[(prach_config_index - 28) % repeat_sequence.size()]), - span(config.subframe)); + span(config.slots)); } else if (prach_config_index < 56) { - ASSERT_EQ(span({1}), span(config.subframe)); + ASSERT_EQ(span({1}), span(config.slots)); } else if (prach_config_index < 60) { const std::array subframes = {static_cast(4 * ((prach_config_index - 56) % 2) + 1)}; - ASSERT_EQ(span(subframes), span(config.subframe)); + ASSERT_EQ(span(subframes), span(config.slots)); } else if (prach_config_index < 67) { ASSERT_EQ(span(repeat_sequence[(prach_config_index - 60) % repeat_sequence.size()]), - span(config.subframe)); + span(config.slots)); } else if (prach_config_index < 78) { ASSERT_EQ(span(repeat_sequence[(prach_config_index - 67) % repeat_sequence.size()]), - span(config.subframe)); + span(config.slots)); } else if (config_subframe_4_9.count(prach_config_index)) { - ASSERT_EQ(span({4, 9}), span(config.subframe)); + ASSERT_EQ(span({4, 9}), span(config.slots)); } else if (config_subframe_4.count(prach_config_index)) { - ASSERT_EQ(span({4}), span(config.subframe)); + ASSERT_EQ(span({4}), span(config.slots)); } else if (config_subframe_1.count(prach_config_index)) { - ASSERT_EQ(span({1}), span(config.subframe)); + ASSERT_EQ(span({1}), span(config.slots)); } else if (config_subframe_7.count(prach_config_index)) { - ASSERT_EQ(span({7}), span(config.subframe)); + ASSERT_EQ(span({7}), span(config.slots)); } else if (config_subframe_1_6.count(prach_config_index)) { - ASSERT_EQ(span({1, 6}), span(config.subframe)); + ASSERT_EQ(span({1, 6}), span(config.slots)); } else if (config_subframe_2_7.count(prach_config_index)) { - ASSERT_EQ(span({2, 7}), span(config.subframe)); + ASSERT_EQ(span({2, 7}), span(config.slots)); } else if (config_subframe_1_4_7.count(prach_config_index)) { - ASSERT_EQ(span({1, 4, 7}), span(config.subframe)); + ASSERT_EQ(span({1, 4, 7}), span(config.slots)); } else if (config_subframe_even.count(prach_config_index)) { - ASSERT_EQ(span({0, 2, 4, 6, 8}), span(config.subframe)); + ASSERT_EQ(span({0, 2, 4, 6, 8}), span(config.slots)); } else if (config_subframe_odd.count(prach_config_index)) { - ASSERT_EQ(span({1, 3, 5, 7, 9}), span(config.subframe)); + ASSERT_EQ(span({1, 3, 5, 7, 9}), span(config.slots)); } else if (config_subframe_all.count(prach_config_index)) { - ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), span(config.slots)); } else { - ASSERT_EQ(span(PRACH_CONFIG_RESERVED.subframe), span(config.subframe)); + ASSERT_EQ(span(PRACH_CONFIG_RESERVED.slots), span(config.slots)); } // Assert starting symbol. @@ -377,55 +377,55 @@ TEST(PrachConfiguration, Fr1Unpaired) static const std::set config_subframe_all = {86, 167, 168}; if (config_subframe_1.count(prach_config_index)) { - ASSERT_EQ(span({1}), span(config.subframe)); + ASSERT_EQ(span({1}), span(config.slots)); } else if (config_subframe_2.count(prach_config_index)) { - ASSERT_EQ(span({2}), span(config.subframe)); + ASSERT_EQ(span({2}), span(config.slots)); } else if (config_subframe_3.count(prach_config_index)) { - ASSERT_EQ(span({3}), span(config.subframe)); + ASSERT_EQ(span({3}), span(config.slots)); } else if (config_subframe_4.count(prach_config_index)) { - ASSERT_EQ(span({4}), span(config.subframe)); + ASSERT_EQ(span({4}), span(config.slots)); } else if (config_subframe_5.count(prach_config_index)) { - ASSERT_EQ(span({5}), span(config.subframe)); + ASSERT_EQ(span({5}), span(config.slots)); } else if (config_subframe_6.count(prach_config_index)) { - ASSERT_EQ(span({6}), span(config.subframe)); + ASSERT_EQ(span({6}), span(config.slots)); } else if (config_subframe_7.count(prach_config_index)) { - ASSERT_EQ(span({7}), span(config.subframe)); + ASSERT_EQ(span({7}), span(config.slots)); } else if (config_subframe_8.count(prach_config_index)) { - ASSERT_EQ(span({8}), span(config.subframe)); + ASSERT_EQ(span({8}), span(config.slots)); } else if (config_subframe_9.count(prach_config_index)) { - ASSERT_EQ(span({9}), span(config.subframe)); + ASSERT_EQ(span({9}), span(config.slots)); } else if (config_subframe_1_6.count(prach_config_index)) { - ASSERT_EQ(span({1, 6}), span(config.subframe)); + ASSERT_EQ(span({1, 6}), span(config.slots)); } else if (config_subframe_4_9.count(prach_config_index)) { - ASSERT_EQ(span({4, 9}), span(config.subframe)); + ASSERT_EQ(span({4, 9}), span(config.slots)); } else if (config_subframe_3_8.count(prach_config_index)) { - ASSERT_EQ(span({3, 8}), span(config.subframe)); + ASSERT_EQ(span({3, 8}), span(config.slots)); } else if (config_subframe_2_7.count(prach_config_index)) { - ASSERT_EQ(span({2, 7}), span(config.subframe)); + ASSERT_EQ(span({2, 7}), span(config.slots)); } else if (config_subframe_7_9.count(prach_config_index)) { - ASSERT_EQ(span({7, 9}), span(config.subframe)); + ASSERT_EQ(span({7, 9}), span(config.slots)); } else if (config_subframe_8_9.count(prach_config_index)) { - ASSERT_EQ(span({8, 9}), span(config.subframe)); + ASSERT_EQ(span({8, 9}), span(config.slots)); } else if (config_subframe_4_8_9.count(prach_config_index)) { - ASSERT_EQ(span({4, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({4, 8, 9}), span(config.slots)); } else if (config_subframe_3_4_9.count(prach_config_index)) { - ASSERT_EQ(span({3, 4, 9}), span(config.subframe)); + ASSERT_EQ(span({3, 4, 9}), span(config.slots)); } else if (config_subframe_7_8_9.count(prach_config_index)) { - ASSERT_EQ(span({7, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({7, 8, 9}), span(config.slots)); } else if (config_subframe_3_4_8_9.count(prach_config_index)) { - ASSERT_EQ(span({3, 4, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({3, 4, 8, 9}), span(config.slots)); } else if (config_subframe_6_7_8_9.count(prach_config_index)) { - ASSERT_EQ(span({6, 7, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({6, 7, 8, 9}), span(config.slots)); } else if (config_subframe_1_4_6_9.count(prach_config_index)) { - ASSERT_EQ(span({1, 4, 6, 9}), span(config.subframe)); + ASSERT_EQ(span({1, 4, 6, 9}), span(config.slots)); } else if (config_subframe_2_3_4_7_8_9.count(prach_config_index)) { - ASSERT_EQ(span({2, 3, 4, 7, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({2, 3, 4, 7, 8, 9}), span(config.slots)); } else if (config_subframe_odd.count(prach_config_index)) { - ASSERT_EQ(span({1, 3, 5, 7, 9}), span(config.subframe)); + ASSERT_EQ(span({1, 3, 5, 7, 9}), span(config.slots)); } else if (config_subframe_all.count(prach_config_index)) { - ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), span(config.subframe)); + ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), span(config.slots)); } else { - ASSERT_EQ(span({}), span(config.subframe)); + ASSERT_EQ(span({}), span(config.slots)); } // Assert starting symbol. @@ -557,43 +557,42 @@ TEST(PrachConfiguration, Fr2Unpaired) static const std::set config_subframe_1_3_etc = {142}; static const std::set config_subframe_0_1_etc = {143}; if (config_subframe_4_9_etc.count(prach_config_index)) { - ASSERT_EQ(span({4, 9, 14, 19, 24, 29, 34, 39}), span(config.subframe)); + ASSERT_EQ(span({4, 9, 14, 19, 24, 29, 34, 39}), span(config.slots)); } else if (config_subframe_3_7_etc.count(prach_config_index)) { - ASSERT_EQ(span({3, 7, 11, 15, 19, 23, 27, 31, 35, 39}), span(config.subframe)); + ASSERT_EQ(span({3, 7, 11, 15, 19, 23, 27, 31, 35, 39}), span(config.slots)); } else if (config_subframe_9_19_etc.count(prach_config_index)) { - ASSERT_EQ(span({9, 19, 29, 39}), span(config.subframe)); + ASSERT_EQ(span({9, 19, 29, 39}), span(config.slots)); } else if (config_subframe_7_15_etc.count(prach_config_index)) { - ASSERT_EQ(span({7, 15, 23, 31, 39}), span(config.subframe)); + ASSERT_EQ(span({7, 15, 23, 31, 39}), span(config.slots)); } else if (config_subframe_19_39.count(prach_config_index)) { - ASSERT_EQ(span({19, 39}), span(config.subframe)); + ASSERT_EQ(span({19, 39}), span(config.slots)); } else if (config_subframe_17_19_etc.count(prach_config_index)) { - ASSERT_EQ(span({17, 19, 37, 39}), span(config.subframe)); + ASSERT_EQ(span({17, 19, 37, 39}), span(config.slots)); } else if (config_subframe_24_29_etc.count(prach_config_index)) { - ASSERT_EQ(span({24, 29, 34, 39}), span(config.subframe)); + ASSERT_EQ(span({24, 29, 34, 39}), span(config.slots)); } else if (config_subframe_9_19_etc2.count(prach_config_index)) { - ASSERT_EQ(span({9, 19, 29, 39}), span(config.subframe)); + ASSERT_EQ(span({9, 19, 29, 39}), span(config.slots)); } else if (config_subframe_7_15_etc2.count(prach_config_index)) { - ASSERT_EQ(span({7, 15, 23, 31, 39}), span(config.subframe)); + ASSERT_EQ(span({7, 15, 23, 31, 39}), span(config.slots)); } else if (config_subframe_23_27_etc.count(prach_config_index)) { - ASSERT_EQ(span({23, 27, 31, 35, 39}), span(config.subframe)); + ASSERT_EQ(span({23, 27, 31, 35, 39}), span(config.slots)); } else if (config_subframe_9_11_etc.count(prach_config_index)) { - ASSERT_EQ(span({9, 11, 13, 15, 17, 19}), span(config.subframe)); + ASSERT_EQ(span({9, 11, 13, 15, 17, 19}), span(config.slots)); } else if (config_subframe_3_5_etc.count(prach_config_index)) { - ASSERT_EQ(span({3, 5, 7, 9, 11, 13}), span(config.subframe)); + ASSERT_EQ(span({3, 5, 7, 9, 11, 13}), span(config.slots)); } else if (config_subframe_13_14_etc.count(prach_config_index)) { - ASSERT_EQ(span({13, 14, 15, 29, 30, 31, 37, 38, 39}), span(config.subframe)); + ASSERT_EQ(span({13, 14, 15, 29, 30, 31, 37, 38, 39}), span(config.slots)); } else if (config_subframe_3_5_etc2.count(prach_config_index)) { - ASSERT_EQ(span({3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25}), - span(config.subframe)); + ASSERT_EQ(span({3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25}), span(config.slots)); } else if (config_subframe_1_3_etc.count(prach_config_index)) { ASSERT_EQ(span({1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39}), - span(config.subframe)); + span(config.slots)); } else if (config_subframe_0_1_etc.count(prach_config_index)) { ASSERT_EQ(span({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}), - span(config.subframe)); + span(config.slots)); } else { - ASSERT_EQ(PRACH_CONFIG_RESERVED.subframe, config.subframe) << "prach_config_index=" << prach_config_index; + ASSERT_EQ(PRACH_CONFIG_RESERVED.slots, config.slots) << "prach_config_index=" << prach_config_index; } // Assert starting symbol. diff --git a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp index 901455949f..a4f5a48301 100644 --- a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp @@ -112,8 +112,7 @@ class prach_tester : public ::testing::TestWithParam if (prach_occasion_sfn) { return false; } - if (std::find(prach_cfg.subframe.begin(), prach_cfg.subframe.end(), sl.subframe_index()) == - prach_cfg.subframe.end()) { + if (std::find(prach_cfg.slots.begin(), prach_cfg.slots.end(), sl.subframe_index()) == prach_cfg.slots.end()) { return false; } From d7b6dd5f4eff7e55c682e6baa676274fa7d66908 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 2 Aug 2024 08:18:53 +0200 Subject: [PATCH 062/407] ci: deprecate gcc9 avx512 support --- .gitlab/ci/build.yml | 78 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 4a90d971f9..e584c4fac6 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -990,9 +990,9 @@ export on amd64 avx512: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v4 - - OS: ubuntu-20.04 - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" + # - OS: ubuntu-20.04 + # MARCH: x86-64 + # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" # Build + unit tests combinations @@ -1406,13 +1406,13 @@ sanitizers amd64 avx512: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - - OS: ubuntu-20.04 - SANITIZER: asan - COMPILER: [gcc, clang] - ENABLE_ASAN: "True" - TEST_MODE: default - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" + # - OS: ubuntu-20.04 + # SANITIZER: asan + # COMPILER: [gcc, clang] + # ENABLE_ASAN: "True" + # TEST_MODE: default + # MARCH: x86-64 + # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang @@ -1580,20 +1580,20 @@ ubuntu-20.04 amd64 native: - OS: ubuntu-20.04 <<: *basic_combinations -ubuntu-20.04 amd64 avx512: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 90 minutes - interruptible: false - tags: ["${AMD64_AVX512_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" +# ubuntu-20.04 amd64 avx512: +# extends: .build_and_unit +# rules: +# - if: $CI_DESCRIPTION =~ /Weekly/ +# when: delayed +# start_in: 90 minutes +# interruptible: false +# tags: ["${AMD64_AVX512_TAG}"] +# parallel: +# matrix: +# - OS: ubuntu-20.04 +# <<: *basic_combinations +# MARCH: x86-64 +# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" ubuntu-20.04 arm native: extends: .build_and_unit @@ -1701,21 +1701,21 @@ ubuntu-20.04 amd64 avx2 dpdk: MARCH: x86-64 BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" -ubuntu-20.04 amd64 avx512 dpdk: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 210 minutes - interruptible: false - tags: ["${AMD64_AVX512_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations_dpdk - DPDK_VERSION: ["22.11.3", "23.11"] - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" +# ubuntu-20.04 amd64 avx512 dpdk: +# extends: .build_and_unit +# rules: +# - if: $CI_DESCRIPTION =~ /Weekly/ +# when: delayed +# start_in: 210 minutes +# interruptible: false +# tags: ["${AMD64_AVX512_TAG}"] +# parallel: +# matrix: +# - OS: ubuntu-20.04 +# <<: *basic_combinations_dpdk +# DPDK_VERSION: ["22.11.3", "23.11"] +# MARCH: x86-64 +# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" ubuntu-22.04 amd64 avx2 dpdk: extends: .build_and_unit From 5980e5e70b5d3cd332400b1d2cd47973213558f8 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 2 Aug 2024 10:49:42 +0200 Subject: [PATCH 063/407] ci: deprecate gcc9 avx2 support --- .gitlab/ci/build.yml | 98 ++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index e584c4fac6..990dc5bb95 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -979,9 +979,9 @@ export on amd64: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v3 - - OS: ubuntu-20.04 - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" + # - OS: ubuntu-20.04 + # MARCH: x86-64 + # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" export on amd64 avx512: extends: export on amd64 @@ -1066,20 +1066,20 @@ ubuntu-22.04 amd64 avx2: <<: *basic_combinations MARCH: x86-64-v3 -ubuntu-20.04 amd64 avx2: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ - when: delayed - start_in: 210 minutes - interruptible: false - tags: ["${AMD64_AVX2_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" +# ubuntu-20.04 amd64 avx2: +# extends: .build_and_unit +# rules: +# - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ +# when: delayed +# start_in: 210 minutes +# interruptible: false +# tags: ["${AMD64_AVX2_TAG}"] +# parallel: +# matrix: +# - OS: ubuntu-20.04 +# <<: *basic_combinations +# MARCH: x86-64 +# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" rhel-8 amd64 avx2: extends: .build_and_unit @@ -1152,11 +1152,11 @@ ubuntu dpdk: - OS: ubuntu-22.04 COMPILER: [gcc, clang] DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] - - OS: ubuntu-20.04 - COMPILER: [gcc, clang] - DPDK_VERSION: ["22.11.3", "23.11"] - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" + # - OS: ubuntu-20.04 + # COMPILER: [gcc, clang] + # DPDK_VERSION: ["22.11.3", "23.11"] + # MARCH: x86-64 + # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" ################### # Alternative OSs # @@ -1370,13 +1370,13 @@ sanitizers amd64 avx2: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - - OS: ubuntu-20.04 - SANITIZER: asan - COMPILER: [gcc, clang] - ENABLE_ASAN: "True" - TEST_MODE: default - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" + # - OS: ubuntu-20.04 + # SANITIZER: asan + # COMPILER: [gcc, clang] + # ENABLE_ASAN: "True" + # TEST_MODE: default + # MARCH: x86-64 + # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang @@ -1453,11 +1453,11 @@ build uhd alt: - OS: ubuntu-22.04 COMPILER: [gcc, clang] UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] - - OS: ubuntu-20.04 - COMPILER: [gcc, clang] - UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" + # - OS: ubuntu-20.04 + # COMPILER: [gcc, clang] + # UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] + # MARCH: x86-64 + # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" # Build + unit tests combinations @@ -1685,21 +1685,21 @@ rhel-8 arm neon: ENABLE_DPDK: "True" COMPILER: [gcc, clang] -ubuntu-20.04 amd64 avx2 dpdk: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 180 minutes - interruptible: false - tags: ["${AMD64_AVX2_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations_dpdk - DPDK_VERSION: ["22.11.3", "23.11"] - MARCH: x86-64 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" +# ubuntu-20.04 amd64 avx2 dpdk: +# extends: .build_and_unit +# rules: +# - if: $CI_DESCRIPTION =~ /Weekly/ +# when: delayed +# start_in: 180 minutes +# interruptible: false +# tags: ["${AMD64_AVX2_TAG}"] +# parallel: +# matrix: +# - OS: ubuntu-20.04 +# <<: *basic_combinations_dpdk +# DPDK_VERSION: ["22.11.3", "23.11"] +# MARCH: x86-64 +# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" # ubuntu-20.04 amd64 avx512 dpdk: # extends: .build_and_unit From 3bb2ce296cf8549be79f57fae3fbaa14281429d5 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 2 Aug 2024 15:31:08 +0200 Subject: [PATCH 064/407] ci: fix avx512 smoke --- .gitlab/ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 990dc5bb95..d129edf1c6 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -444,7 +444,7 @@ variables: BUILD_TYPE: Release ASSERT_LEVEL: PARANOID TEST_MODE: default - MARCH: x86-64-v3 + MARCH: x86-64-v4 tags: ["${AMD64_AVX512_TAG}"] .smoke arm: From 1bccbee59a0983fe272f535f3c6fb309248238b6 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 2 Aug 2024 08:22:24 +0200 Subject: [PATCH 065/407] ci: fix fedora zmq driver --- .gitlab/ci/trx.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index 228041a350..4a350e6848 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -33,8 +33,14 @@ build trx driver: script: - | download_amarisoft() { - DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends curl apt-transport-https ca-certificates - + . /etc/os-release + + if [[ "$ID" == "debian" || "$ID" == "ubuntu" ]]; then + DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends curl apt-transport-https ca-certificates + elif [[ "$ID" == "fedora" ]]; then + dnf -y install curl + fi + cd ${CI_PROJECT_DIR} http_code=$(curl -w "%{http_code}" --header "PRIVATE-TOKEN: $CODEBOT_TOKEN" "${AMARISOFT_PACKAGE_REGISTRY}/${AMARISOFT_VERSION}/amarisoft.${AMARISOFT_VERSION}.tar.gz" -o amarisoft.tar.gz) if [[ $http_code != "200" ]]; then From ab5106df75c781e1636522d4acc05da5434e13d1 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 2 Aug 2024 10:45:21 +0200 Subject: [PATCH 066/407] ci,e2e: review rerun conditions --- tests/e2e/tests/iperf.py | 1 + tests/e2e/tests/ping.py | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 04076932d4..7c1d4d1d11 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -545,6 +545,7 @@ def test_smoke( "iperf did not achieve the expected data rate", "socket is already closed", "failed to connect to all addresses", + "5GC crashed", ], ) # pylint: disable=too-many-arguments diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index a85d14d102..66727dcaa3 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -157,6 +157,7 @@ def test_android_hp( "Attach timeout reached", "Some packages got lost", "socket is already closed", + "5GC crashed", ], ) # pylint: disable=too-many-arguments From 34b0c8418c8a880693b07ec8d19e2fd37df057b0 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 2 Aug 2024 13:00:35 +0200 Subject: [PATCH 067/407] ci,e2e: fix srsue testbed --- .gitlab/ci/e2e/.env | 2 +- .gitlab/ci/e2e/retina_request_zmq_srsue.yml | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index e1a9b8149d..dc1fd8c2f5 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.0 +RETINA_VERSION=0.52.1 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml index 94a8badd1b..94aef1e028 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml @@ -9,7 +9,7 @@ - name: srs-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/srsue:${SRSUE_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -22,13 +22,15 @@ ephemeral-storage: requests: "6G" limits: "6G" + resources: + - type: zmq environment: - RETINA_AGENT_ARGS: --grpc.max_size_file_artifact 209715200 - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -64,5 +66,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} From 9c7dd180de674595ed1a9a2ff78af4d52c4aca33 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 1 Aug 2024 19:15:27 +0200 Subject: [PATCH 068/407] f1ap-du: handle f1ap drb-to-be-modified in the DU side --- .../f1ap/du/f1ap_du_ue_context_update.h | 30 ++--- .../procedures/ue_configuration_procedure.cpp | 8 +- .../du_ran_resource_manager_impl.cpp | 107 +++++++++++++----- lib/f1ap/du/procedures/CMakeLists.txt | 1 + .../procedures/f1ap_du_ue_context_common.cpp | 93 +++++++++++++++ .../du/procedures/f1ap_du_ue_context_common.h | 85 +------------- ...p_du_ue_context_modification_procedure.cpp | 10 +- .../f1ap_du_ue_context_setup_procedure.cpp | 2 +- .../du_manager/du_manager_test_helpers.cpp | 15 +-- .../du_manager_procedure_test_helpers.cpp | 2 +- .../procedures/ue_configuration_test.cpp | 8 +- .../f1ap_du_ue_context_modification_test.cpp | 6 +- ...1ap_du_ue_context_setup_procedure_test.cpp | 18 +-- 13 files changed, 236 insertions(+), 149 deletions(-) create mode 100644 lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 16b221982c..0eebd5c8da 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -17,6 +17,7 @@ #include "srsran/ran/five_qi.h" #include "srsran/ran/lcid.h" #include "srsran/ran/qos/qos_info.h" +#include "srsran/ran/rnti.h" #include "srsran/ran/s_nssai.h" #include "srsran/ran/up_transport_layer_info.h" @@ -40,15 +41,17 @@ struct f1ap_ue_context_creation_response { rnti_t crnti; }; -/// \brief DRB to be setup in the UE context. -struct f1ap_drb_to_setup { +/// \brief DRB to be setup or modify in the UE context. +struct f1ap_drb_config_request { drb_id_t drb_id; std::optional lcid; - drb_rlc_mode mode; - pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; - five_qi_t five_qi; - uint8_t arp_priority_level; - s_nssai_t s_nssai; + /// \brief RLC mode. If it is a new bearer to setup, this field is present. If it is an existing bearer that needs + /// to be modified, this field is absent. + std::optional mode; + pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; + five_qi_t five_qi; + uint8_t arp_priority_level; + s_nssai_t s_nssai; /// GBR flow information is present only for GBR QoS flows. See TS 38.473, clause 9.3.1.45. std::optional gbr_flow_info; std::vector uluptnl_info_list; @@ -69,12 +72,13 @@ struct f1ap_drb_setup { /// \brief Request from DU F1AP to DU manager to modify existing UE configuration. struct f1ap_ue_context_update_request { - du_ue_index_t ue_index; - std::vector srbs_to_setup; - std::vector drbs_to_setup; - std::vector drbs_to_rem; - std::vector scells_to_setup; - std::vector scells_to_rem; + du_ue_index_t ue_index; + std::vector srbs_to_setup; + /// List of DRBs to either setup or modify. + std::vector drbs_to_setupmod; + std::vector drbs_to_rem; + std::vector scells_to_setup; + std::vector scells_to_rem; /// \brief If true, the gnb-DU shall generate a cell group configuration using full configuration. Otherwise, delta, /// should be used. bool full_config_required; diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 3e7f7fe31c..b3e956c61c 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -36,7 +36,7 @@ void ue_configuration_procedure::operator()(coro_context Create DU UE DRB objects. - for (const f1ap_drb_to_setup& drbtoadd : request.drbs_to_setup) { + for (const f1ap_drb_config_request& drbtoadd : request.drbs_to_setupmod) { if (drbtoadd.uluptnl_info_list.empty()) { proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtoadd.drb_id); continue; @@ -218,7 +218,7 @@ async_task ue_configuration_procedure::update_m mac_ue_reconf_req.bearers_to_rem.push_back(drb->lcid); } - for (const auto& drb : request.drbs_to_setup) { + for (const auto& drb : request.drbs_to_setupmod) { if (ue->bearers.drbs().count(drb.drb_id) == 0) { // The DRB failed to be setup. Carry on with other DRBs. continue; @@ -243,7 +243,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo resp.result = true; // > Handle DRBs that were setup or failed to be setup. - for (const f1ap_drb_to_setup& drb_req : request.drbs_to_setup) { + for (const f1ap_drb_config_request& drb_req : request.drbs_to_setupmod) { if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { resp.drbs_failed_to_setup.push_back(drb_req.drb_id); continue; diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index e1b15fe808..881b1303cb 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -105,6 +105,72 @@ ue_ran_resource_configurator du_ran_resource_manager_impl::create_ue_resource_co return ue_ran_resource_configurator{std::make_unique(&mcg, *this, ue_index)}; } +static bool equals(const drb_rlc_mode& lhs, const rlc_mode& rhs) +{ + return (lhs == drb_rlc_mode::am and rhs == rlc_mode::am) or + (lhs == drb_rlc_mode::um_bidir and rhs == rlc_mode::um_bidir) or + (lhs == drb_rlc_mode::um_unidir_dl and rhs == rlc_mode::um_unidir_dl) or + (lhs == drb_rlc_mode::um_unidir_ul and rhs == rlc_mode::um_unidir_ul); +} + +static expected +validate_drb_config_request(const f1ap_drb_config_request& drb, + span rlc_bearers, + const std::map& qos_config) +{ + // Validate QOS config. + auto qos_it = qos_config.find(drb.five_qi); + if (qos_it == qos_config.end()) { + return make_unexpected(fmt::format("Failed to allocate {}. Cause: No {} 5QI configured", drb.drb_id, drb.five_qi)); + } + const du_qos_config& qos = qos_it->second; + if (drb.mode.has_value() and not equals(qos.rlc.mode, *drb.mode)) { + return make_unexpected( + fmt::format("RLC mode mismatch for {}. QoS config for {} configures {} but CU-CP requested {}", + drb.drb_id, + drb.five_qi, + qos.rlc.mode, + drb.mode)); + } + + // Search for established DRB with matching DRB-Id. + auto prev_drb_it = std::find_if(rlc_bearers.begin(), rlc_bearers.end(), [&drb](const rlc_bearer_config& item) { + return item.drb_id.has_value() and item.drb_id.value() == drb.drb_id; + }); + bool new_drb = prev_drb_it == rlc_bearers.end(); + + if (new_drb) { + if (not drb.mode.has_value()) { + // RLC mode needs to be specified. + return make_unexpected(fmt::format("Failed to allocate {}. Cause: RLC mode not specified", drb.drb_id)); + } + + // CU-assigned LCID. + if (drb.lcid.has_value()) { + if (std::any_of( + rlc_bearers.begin(), rlc_bearers.end(), [&drb](const auto& item) { return *drb.lcid == item.lcid; })) { + return make_unexpected(fmt::format( + "Failed to allocate {}. Cause: Specified lcid={} already exists", drb.drb_id, drb.lcid.value())); + } + } + } else { + // Modified DRB + if (drb.mode.has_value() and not equals(drb.mode.value(), prev_drb_it->rlc_cfg.mode)) { + // RLC mode cannot be changed. + return make_unexpected( + fmt::format("Failed to configure {}. Cause: RLC mode cannot be changed for an existing DRB", drb.drb_id)); + } + + if (drb.lcid.has_value() and drb.lcid.value() != prev_drb_it->lcid) { + // LCID cannot be changed. + return make_unexpected( + fmt::format("Failed to configure {}. Cause: LCID cannot be changed for an existing DRB", drb.drb_id)); + } + } + + return {}; +} + du_ue_resource_update_response du_ran_resource_manager_impl::update_context(du_ue_index_t ue_index, du_cell_index_t pcell_idx, @@ -139,7 +205,7 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t ue_mcg.rlc_bearers.erase(it); } - // > Allocate new or modified bearers. + // > Allocate new SRBs. for (srb_id_t srb_id : upd_req.srbs_to_setup) { // >> New or Modified SRB. lcid_t lcid = srb_id_to_lcid(srb_id); @@ -161,19 +227,25 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t ue_mcg.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(lcid); } } - for (const f1ap_drb_to_setup& drb : upd_req.drbs_to_setup) { + + // > Allocate new or modify existing DRBs. + for (const f1ap_drb_config_request& drb : upd_req.drbs_to_setupmod) { // >> New or Modified DRB. + auto res = validate_drb_config_request(drb, ue_mcg.rlc_bearers, qos_config); + if (not res.has_value()) { + resp.failed_drbs.push_back(drb.drb_id); + continue; + } + bool new_drb = res.value() == nullptr; + if (not new_drb) { + // TODO: Support DRB modification. + continue; + } + lcid_t lcid; if (drb.lcid.has_value()) { // >> CU-assigned LCID. lcid = *drb.lcid; - if (std::any_of(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [&drb](const auto& item) { - return *drb.lcid == item.lcid; - })) { - logger.warning("Failed to allocate {}. Cause: Specified lcid={} already exists", drb.drb_id, lcid); - resp.failed_drbs.push_back(drb.drb_id); - continue; - } } else { // >> Allocate LCID if not specified by F1AP. lcid = find_empty_lcid(ue_mcg.rlc_bearers); @@ -185,24 +257,7 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } // >> Get RLC config from 5QI - if (qos_config.find(drb.five_qi) == qos_config.end()) { - logger.warning("Failed to allocate {}. Cause: No {} configured", drb.drb_id, drb.five_qi); - resp.failed_drbs.push_back(drb.drb_id); - continue; - } - logger.debug("Getting RLC and MAC config for {} from {}", drb.drb_id, drb.five_qi); const du_qos_config& qos = qos_config.at(drb.five_qi); - - if (!equals(qos.rlc.mode, drb.mode)) { - logger.warning("RLC mode mismatch for {}. QoS config for {} configures {} but CU-UP requested {}", - drb.drb_id, - drb.five_qi, - qos.rlc.mode, - drb.mode); - resp.failed_drbs.push_back(drb.drb_id); - continue; - } - ue_mcg.rlc_bearers.emplace_back(); ue_mcg.rlc_bearers.back().lcid = lcid; ue_mcg.rlc_bearers.back().drb_id = drb.drb_id; diff --git a/lib/f1ap/du/procedures/CMakeLists.txt b/lib/f1ap/du/procedures/CMakeLists.txt index a94658a2c2..5b28b5eaa8 100644 --- a/lib/f1ap/du/procedures/CMakeLists.txt +++ b/lib/f1ap/du/procedures/CMakeLists.txt @@ -7,6 +7,7 @@ # set(SOURCES + f1ap_du_ue_context_common.cpp gnb_cu_configuration_update_procedure.cpp f1ap_du_setup_procedure.cpp f1ap_du_removal_procedure.cpp diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp new file mode 100644 index 0000000000..a16188fcf1 --- /dev/null +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -0,0 +1,93 @@ +/* + * + * 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 "f1ap_du_ue_context_common.h" + +using namespace srsran; +using namespace srs_du; + +template +static void fill_common_drb_config_request_fields(f1ap_drb_config_request& drb_obj, const ASN1Type& drb_item) +{ + drb_obj.drb_id = static_cast(drb_item.drb_id); + + drb_obj.uluptnl_info_list.reserve(drb_item.ul_up_tnl_info_to_be_setup_list.size()); + for (const auto& tnl_info : drb_item.ul_up_tnl_info_to_be_setup_list) { + drb_obj.uluptnl_info_list.push_back(asn1_to_up_transport_layer_info(tnl_info.ul_up_tnl_info)); + } + + // TODO: Handle Dynamic 5QI. + const auto& asn1_drbinfo = drb_item.qos_info.choice_ext().value().drb_info(); + drb_obj.five_qi = uint_to_five_qi(asn1_drbinfo.drb_qos.qos_characteristics.non_dyn_5qi().five_qi); + drb_obj.arp_priority_level = asn1_drbinfo.drb_qos.ngra_nalloc_retention_prio.prio_level; + drb_obj.s_nssai.sst = asn1_drbinfo.snssai.sst.to_number(); + if (asn1_drbinfo.snssai.sd_present) { + drb_obj.s_nssai.sd = drb_item.qos_info.choice_ext().value().drb_info().snssai.sd.to_number(); + } + // TODO: Do not populate gbr_flow_info for non-GBR flows. + if (asn1_drbinfo.drb_qos.gbr_qos_flow_info_present) { + drb_obj.gbr_flow_info.emplace(); + auto& gbr = drb_obj.gbr_flow_info.value(); + gbr.max_flow_dl_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; + gbr.max_flow_ul_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; + gbr.guaranteed_flow_dl_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; + gbr.guaranteed_flow_ul_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; + if (asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { + gbr.max_packet_loss_rate_dl.emplace(asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); + } + if (asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present) { + gbr.max_packet_loss_rate_dl.emplace(asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul); + } + } +} + +f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) +{ + f1ap_drb_config_request drb_obj; + fill_common_drb_config_request_fields(drb_obj, drb_item); + + drb_obj.mode = static_cast(static_cast(drb_item.rlc_mode)); + + if (drb_item.ie_exts_present) { + drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); + } + + return drb_obj; +} + +f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) +{ + f1ap_drb_config_request drb_obj; + fill_common_drb_config_request_fields(drb_obj, drb_item); + + drb_obj.mode = static_cast(static_cast(drb_item.rlc_mode)); + + if (drb_item.ie_exts_present) { + if (drb_item.ie_exts.dl_pdcp_sn_len_present) { + drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); + } + } + + return drb_obj; +} + +f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item) +{ + f1ap_drb_config_request drb_obj; + fill_common_drb_config_request_fields(drb_obj, drb_item); + + if (drb_item.ie_exts_present) { + if (drb_item.ie_exts.dl_pdcp_sn_len_present) { + drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); + } + } + + return drb_obj; +} diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h index 85a82c5720..4436c6449a 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h @@ -31,87 +31,14 @@ srb_id_t make_srb_id(const Asn1Type& srb_item) return static_cast(srb_item.srb_id); } -/// \brief Convert extension fields of F1AP ASN.1 drb to be setup item to common type struct. -/// \param[out] drb_to_be_setup_item The drb to be setup item common type struct. -/// \param[in] ie_exts The ASN.1 struct with DRB-specific parameters to be setup. -inline void -f1ap_drbs_to_be_setup_mod_item_ext_ies_to_asn1(f1ap_drb_to_setup& drb_to_be_setup_mod_item, - const asn1::f1ap::drbs_to_be_setup_item_ext_ies_container& ie_exts) -{ - drb_to_be_setup_mod_item.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(ie_exts.dl_pdcp_sn_len); -} +/// Convert 3GPP TS 38.473, DRBs-ToBeSetup-Item ASN.1 type into f1ap_drb_config_request. +f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); -/// \brief Convert extension fields of F1AP ASN.1 drb to be setup mod item to common type struct. -/// \param[out] drb_to_be_setup_mod_item The drb to be setup item common type struct. -/// \param[in] ie_exts The ASN.1 struct with DRB-specific parameters to be setup. -inline void -f1ap_drbs_to_be_setup_mod_item_ext_ies_to_asn1(f1ap_drb_to_setup& drb_to_be_setup_mod_item, - const asn1::f1ap::drbs_to_be_setup_mod_item_ext_ies_container& ie_exts) -{ - if (ie_exts.dl_pdcp_sn_len_present) { - drb_to_be_setup_mod_item.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(ie_exts.dl_pdcp_sn_len); - } -} +/// Convert 3GPP TS 38.473, DRBs-ToBeSetupMod-Item ASN.1 type into f1ap_drb_config_request. +f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); -/// \brief Creates a \c f1ap_drb_to_setup from ASN.1 type. -/// -/// This function is used by the following procedures: -/// - f1ap_du_ue_context_setup_procedure -/// - f1ap_du_ue_context_modification_procedure -/// -/// This is as shared function for \c drbs_to_be_setup_item_s and \c drbs_to_be_setup_item_s, because of identical -/// items. Since the \c ie_exts are different, the reading from these extensions is delegated to respective overloads. -/// -/// \param drb_item ASN.1 item with DRB-specific parameters to be setup. -/// \return f1ap_drb_to_setup object. -template -f1ap_drb_to_setup make_drb_to_setup(const Asn1Type& drb_item) -{ - f1ap_drb_to_setup drb_obj; - - drb_obj.drb_id = static_cast(drb_item.drb_id); - drb_obj.mode = static_cast(static_cast(drb_item.rlc_mode)); - - if (drb_item.ie_exts_present) { - f1ap_drbs_to_be_setup_mod_item_ext_ies_to_asn1(drb_obj, drb_item.ie_exts); - } - - drb_obj.uluptnl_info_list.reserve(drb_item.ul_up_tnl_info_to_be_setup_list.size()); - for (const auto& tnl_info : drb_item.ul_up_tnl_info_to_be_setup_list) { - drb_obj.uluptnl_info_list.push_back(asn1_to_up_transport_layer_info(tnl_info.ul_up_tnl_info)); - } - - // TODO: Handle Dynamic 5QI. - drb_obj.five_qi = uint_to_five_qi( - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.qos_characteristics.non_dyn_5qi().five_qi); - drb_obj.arp_priority_level = - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.ngra_nalloc_retention_prio.prio_level; - drb_obj.s_nssai.sst = drb_item.qos_info.choice_ext().value().drb_info().snssai.sst.to_number(); - if (drb_item.qos_info.choice_ext().value().drb_info().snssai.sd_present) { - drb_obj.s_nssai.sd = drb_item.qos_info.choice_ext().value().drb_info().snssai.sd.to_number(); - } - // TODO: Do not populate gbr_flow_info for non-GBR flows. - if (drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info_present) { - drb_obj.gbr_flow_info.emplace(); - drb_obj.gbr_flow_info.value().max_flow_dl_bitrate = - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; - drb_obj.gbr_flow_info.value().max_flow_ul_bitrate = - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; - drb_obj.gbr_flow_info.value().guaranteed_flow_dl_bitrate = - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; - drb_obj.gbr_flow_info.value().guaranteed_flow_ul_bitrate = - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; - if (drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { - drb_obj.gbr_flow_info.value().max_packet_loss_rate_dl.emplace( - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); - } - if (drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present) { - drb_obj.gbr_flow_info.value().max_packet_loss_rate_dl.emplace( - drb_item.qos_info.choice_ext().value().drb_info().drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul); - } - } - return drb_obj; -} +/// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_config_request. +f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); /// \brief Creates a \c drb_id_t from ASN.1 type. /// diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index b3cedd0fe3..6968a68bd7 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -73,7 +73,13 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 // >> Pass DRBs to setup/modify. for (const auto& drb : msg->drbs_to_be_setup_mod_list) { - du_request.drbs_to_setup.push_back(make_drb_to_setup(drb.value().drbs_to_be_setup_mod_item())); + du_request.drbs_to_setupmod.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_mod_item())); + } + + // >> Pass DRBs to modify. + // Note: This field is used during RRC Reestablishment. + for (const auto& drb : msg->drbs_to_be_modified_list) { + du_request.drbs_to_setupmod.push_back(make_drb_config_request(drb.value().drbs_to_be_modified_item())); } // >> Pass DRBs to remove @@ -100,7 +106,7 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res resp->drbs_setup_mod_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); const f1ap_drb_setup& drb_setup = du_response.drbs_setup[i]; drbs_setup_mod_item_s& asn1_drb = resp->drbs_setup_mod_list[i]->drbs_setup_mod_item(); - asn1_drb.drb_id = drb_id_to_uint(du_request.drbs_to_setup[i].drb_id); + asn1_drb.drb_id = drb_id_to_uint(du_request.drbs_to_setupmod[i].drb_id); asn1_drb.lcid_present = drb_setup.lcid.has_value(); if (asn1_drb.lcid_present) { asn1_drb.lcid = drb_setup.lcid.value(); diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index 16ac0c7c4c..cbb2a46ae1 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -131,7 +131,7 @@ async_task f1ap_du_ue_context_setup_procedure:: // > Pass DRBs to setup. for (const auto& drb : msg->drbs_to_be_setup_list) { - du_request.drbs_to_setup.push_back(make_drb_to_setup(drb.value().drbs_to_be_setup_item())); + du_request.drbs_to_setupmod.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_item())); } if (msg->cu_to_du_rrc_info.ie_exts_present) { diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index 27894716dd..0b719d631e 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -85,13 +85,14 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t } for (drb_id_t drb_id : drbs_to_addmod) { - req.drbs_to_setup.emplace_back(); - req.drbs_to_setup.back().drb_id = drb_id; - req.drbs_to_setup.back().mode = drb_rlc_mode::am; - req.drbs_to_setup.back().five_qi = uint_to_five_qi(9); - req.drbs_to_setup.back().uluptnl_info_list.resize(1); - req.drbs_to_setup.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); - req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); + req.drbs_to_setupmod.emplace_back(); + req.drbs_to_setupmod.back().drb_id = drb_id; + req.drbs_to_setupmod.back().mode = drb_rlc_mode::am; + req.drbs_to_setupmod.back().five_qi = uint_to_five_qi(9); + req.drbs_to_setupmod.back().uluptnl_info_list.resize(1); + req.drbs_to_setupmod.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); + req.drbs_to_setupmod.back().uluptnl_info_list[0].tp_address = + transport_layer_address::create_from_string("127.0.0.1"); } return req; diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 677b3eb73b..b53b43331f 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -82,7 +82,7 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { + for (const f1ap_drb_config_request& drb : req.drbs_to_setupmod) { cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 1dd89128b8..3a3c3d18ef 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -42,7 +42,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test this->cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { + for (const f1ap_drb_config_request& drb : req.drbs_to_setupmod) { this->cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; @@ -78,7 +78,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test } } - ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), req.srbs_to_setup.size() + req.drbs_to_setup.size()); + ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), req.srbs_to_setup.size() + req.drbs_to_setupmod.size()); for (srb_id_t srb_id : req.srbs_to_setup) { auto srb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), @@ -99,7 +99,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test ASSERT_FALSE(srb_it->reestablish_rlc_present); } } - for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { + for (const f1ap_drb_config_request& drb : req.drbs_to_setupmod) { auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), [&drb](const auto& b) { @@ -294,7 +294,7 @@ TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_inc // Start Procedure. f1ap_ue_context_update_request req = create_f1ap_ue_context_update_request(test_ue->ue_index, {srb_id_t::srb2}, {drb_id_t::drb1}); - req.drbs_to_setup[0].uluptnl_info_list.clear(); + req.drbs_to_setupmod[0].uluptnl_info_list.clear(); start_procedure(req); // Check MAC received request to update UE configuration without the DRB that could not be created. diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp index da0948ca8c..64cec138a3 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp @@ -74,9 +74,9 @@ TEST_F(f1ap_du_ue_context_modification_test, when_f1ap_receives_request_then_f1a const f1ap_ue_context_update_request& req = *this->f1ap_du_cfg_handler.last_ue_context_update_req; ASSERT_EQ(req.ue_index, test_ue_index); ASSERT_EQ(req.srbs_to_setup.size(), 0); - ASSERT_EQ(req.drbs_to_setup.size(), 1); - ASSERT_EQ(req.drbs_to_setup[0].drb_id, drb_id_t::drb1); - ASSERT_FALSE(req.drbs_to_setup[0].lcid.has_value()); + ASSERT_EQ(req.drbs_to_setupmod.size(), 1); + ASSERT_EQ(req.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); + ASSERT_FALSE(req.drbs_to_setupmod[0].lcid.has_value()); } TEST_F(f1ap_du_ue_context_modification_test, diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index 947a068d9c..e1690f5399 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -109,11 +109,11 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notif ASSERT_EQ(req.ue_index, test_ue->ue_index); ASSERT_EQ(req.srbs_to_setup.size(), 1); ASSERT_EQ(req.srbs_to_setup[0], srb_id_t::srb2); - ASSERT_EQ(req.drbs_to_setup.size(), 1); - ASSERT_EQ(req.drbs_to_setup[0].drb_id, drb_id_t::drb1); - ASSERT_FALSE(req.drbs_to_setup[0].lcid.has_value()); - ASSERT_EQ(req.drbs_to_setup[0].mode, drb_rlc_mode::am); - ASSERT_EQ(req.drbs_to_setup[0].pdcp_sn_len, pdcp_sn_size::size12bits); + ASSERT_EQ(req.drbs_to_setupmod.size(), 1); + ASSERT_EQ(req.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); + ASSERT_FALSE(req.drbs_to_setupmod[0].lcid.has_value()); + ASSERT_EQ(req.drbs_to_setupmod[0].mode, drb_rlc_mode::am); + ASSERT_EQ(req.drbs_to_setupmod[0].pdcp_sn_len, pdcp_sn_size::size12bits); } TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_responds_back_with_ue_context_setup_response) @@ -204,10 +204,10 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ ASSERT_TRUE(this->f1ap_du_cfg_handler.last_ue_context_update_req.has_value()); auto& request_to_du = *this->f1ap_du_cfg_handler.last_ue_context_update_req; ASSERT_EQ(test_ue->ue_index, request_to_du.ue_index); - ASSERT_EQ(request_to_du.drbs_to_setup.size(), 1); - ASSERT_EQ(request_to_du.drbs_to_setup[0].drb_id, drb_id_t::drb1); - ASSERT_EQ(request_to_du.drbs_to_setup[0].mode, drb_rlc_mode::am); - ASSERT_EQ(request_to_du.drbs_to_setup[0].pdcp_sn_len, pdcp_sn_size::size12bits); + ASSERT_EQ(request_to_du.drbs_to_setupmod.size(), 1); + ASSERT_EQ(request_to_du.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); + ASSERT_EQ(request_to_du.drbs_to_setupmod[0].mode, drb_rlc_mode::am); + ASSERT_EQ(request_to_du.drbs_to_setupmod[0].pdcp_sn_len, pdcp_sn_size::size12bits); } TEST_F( From f40acbaffcc16ac720ee915a765777075b1f2b40 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 2 Aug 2024 10:37:20 +0200 Subject: [PATCH 069/407] f1ap-du: use rlc mode type --- .../f1ap/du/f1ap_du_ue_context_update.h | 14 ++-- include/srsran/rlc/rlc_config.h | 45 +------------ include/srsran/rlc/rlc_mode.h | 66 +++++++++++++++++++ .../du_ran_resource_manager_impl.cpp | 20 +----- .../procedures/f1ap_du_ue_context_common.cpp | 21 +++++- .../du_manager/du_manager_test_helpers.cpp | 2 +- ...1ap_du_ue_context_setup_procedure_test.cpp | 4 +- 7 files changed, 97 insertions(+), 75 deletions(-) create mode 100644 include/srsran/rlc/rlc_mode.h diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 0eebd5c8da..b86d43077e 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -20,13 +20,11 @@ #include "srsran/ran/rnti.h" #include "srsran/ran/s_nssai.h" #include "srsran/ran/up_transport_layer_info.h" +#include "srsran/rlc/rlc_mode.h" namespace srsran { namespace srs_du { -/// \brief Possible modes for an DRB RLC entity. -enum class drb_rlc_mode { am = 0, um_bidir, um_unidir_ul, um_unidir_dl }; - /// \brief F1AP sends this request to the DU to create a new UE context. This happens in the particular case /// of a F1AP UE Context Setup Request received without associated logical F1-connection. struct f1ap_ue_context_creation_request { @@ -47,11 +45,11 @@ struct f1ap_drb_config_request { std::optional lcid; /// \brief RLC mode. If it is a new bearer to setup, this field is present. If it is an existing bearer that needs /// to be modified, this field is absent. - std::optional mode; - pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; - five_qi_t five_qi; - uint8_t arp_priority_level; - s_nssai_t s_nssai; + std::optional mode; + pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; + five_qi_t five_qi; + uint8_t arp_priority_level; + s_nssai_t s_nssai; /// GBR flow information is present only for GBR QoS flows. See TS 38.473, clause 9.3.1.45. std::optional gbr_flow_info; std::vector uluptnl_info_list; diff --git a/include/srsran/rlc/rlc_config.h b/include/srsran/rlc/rlc_config.h index 4c6e20c2c0..b94faad737 100644 --- a/include/srsran/rlc/rlc_config.h +++ b/include/srsran/rlc/rlc_config.h @@ -11,42 +11,15 @@ #pragma once #include "srsran/pdcp/pdcp_sn_size.h" +#include "srsran/rlc/rlc_mode.h" #include "srsran/support/srsran_assert.h" #include "srsran/support/timers.h" -#include "fmt/format.h" #include #include #include namespace srsran { -/// RLC NR modes -enum class rlc_mode { tm, um_bidir, um_unidir_ul, um_unidir_dl, am }; -inline bool from_string(rlc_mode& mode, const std::string& str) -{ - if (str == "am") { - mode = rlc_mode::am; - return true; - } - if (str == "um-bidir") { - mode = rlc_mode::um_bidir; - return true; - } - if (str == "um-unidir-ul") { - mode = rlc_mode::um_unidir_ul; - return true; - } - if (str == "um-unidir-dl") { - mode = rlc_mode::um_unidir_dl; - return true; - } - if (str == "tm") { - mode = rlc_mode::tm; - return true; - } - return false; -} - /// RLC UM NR sequence number field enum class rlc_um_sn_size : uint16_t { size6bits = 6, size12bits = 12 }; constexpr uint16_t to_number(rlc_um_sn_size sn_size) @@ -766,22 +739,6 @@ struct rlc_config { namespace fmt { -template <> -struct formatter { - template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) - { - return ctx.begin(); - } - - template - auto format(srsran::rlc_mode mode, FormatContext& ctx) -> decltype(std::declval().out()) - { - constexpr static const char* options[] = {"TM", "UM Bi-dir", "UM Uni-dir-UL", "UM Uni-dir-DL", "AM"}; - return format_to(ctx.out(), "{}", options[static_cast(mode)]); - } -}; - template <> struct formatter { template diff --git a/include/srsran/rlc/rlc_mode.h b/include/srsran/rlc/rlc_mode.h new file mode 100644 index 0000000000..d93c6c7fe5 --- /dev/null +++ b/include/srsran/rlc/rlc_mode.h @@ -0,0 +1,66 @@ +/* + * + * 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 "fmt/format.h" +#include + +namespace srsran { + +/// RLC NR modes +enum class rlc_mode { tm, um_bidir, um_unidir_ul, um_unidir_dl, am }; + +inline bool from_string(rlc_mode& mode, const std::string& str) +{ + if (str == "am") { + mode = rlc_mode::am; + return true; + } + if (str == "um-bidir") { + mode = rlc_mode::um_bidir; + return true; + } + if (str == "um-unidir-ul") { + mode = rlc_mode::um_unidir_ul; + return true; + } + if (str == "um-unidir-dl") { + mode = rlc_mode::um_unidir_dl; + return true; + } + if (str == "tm") { + mode = rlc_mode::tm; + return true; + } + return false; +} + +} // namespace srsran + +namespace fmt { + +template <> +struct formatter { + template + auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template + auto format(srsran::rlc_mode mode, FormatContext& ctx) + { + constexpr static const char* options[] = {"TM", "UM Bi-dir", "UM Uni-dir-UL", "UM Uni-dir-DL", "AM"}; + return format_to(ctx.out(), "{}", options[static_cast(mode)]); + } +}; + +} // namespace fmt \ No newline at end of file diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index 881b1303cb..d6bfb09191 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -18,14 +18,6 @@ using namespace srsran; using namespace srs_du; -constexpr bool equals(const rlc_mode& lhs, const drb_rlc_mode& rhs) -{ - return (lhs == rlc_mode::am && rhs == drb_rlc_mode::am) || - (lhs == rlc_mode::um_bidir && rhs == drb_rlc_mode::um_bidir) || - (lhs == rlc_mode::um_unidir_dl && rhs == drb_rlc_mode::um_unidir_dl) || - (lhs == rlc_mode::um_unidir_ul && rhs == drb_rlc_mode::um_unidir_ul); -} - /// \brief Finds an unused LCID for DRBs given a list of UE configured RLC bearers. static lcid_t find_empty_lcid(const std::vector& rlc_bearers) { @@ -105,14 +97,6 @@ ue_ran_resource_configurator du_ran_resource_manager_impl::create_ue_resource_co return ue_ran_resource_configurator{std::make_unique(&mcg, *this, ue_index)}; } -static bool equals(const drb_rlc_mode& lhs, const rlc_mode& rhs) -{ - return (lhs == drb_rlc_mode::am and rhs == rlc_mode::am) or - (lhs == drb_rlc_mode::um_bidir and rhs == rlc_mode::um_bidir) or - (lhs == drb_rlc_mode::um_unidir_dl and rhs == rlc_mode::um_unidir_dl) or - (lhs == drb_rlc_mode::um_unidir_ul and rhs == rlc_mode::um_unidir_ul); -} - static expected validate_drb_config_request(const f1ap_drb_config_request& drb, span rlc_bearers, @@ -124,7 +108,7 @@ validate_drb_config_request(const f1ap_drb_config_request& drb, return make_unexpected(fmt::format("Failed to allocate {}. Cause: No {} 5QI configured", drb.drb_id, drb.five_qi)); } const du_qos_config& qos = qos_it->second; - if (drb.mode.has_value() and not equals(qos.rlc.mode, *drb.mode)) { + if (drb.mode.has_value() and qos.rlc.mode != *drb.mode) { return make_unexpected( fmt::format("RLC mode mismatch for {}. QoS config for {} configures {} but CU-CP requested {}", drb.drb_id, @@ -155,7 +139,7 @@ validate_drb_config_request(const f1ap_drb_config_request& drb, } } else { // Modified DRB - if (drb.mode.has_value() and not equals(drb.mode.value(), prev_drb_it->rlc_cfg.mode)) { + if (drb.mode.has_value() and drb.mode.value() != prev_drb_it->rlc_cfg.mode) { // RLC mode cannot be changed. return make_unexpected( fmt::format("Failed to configure {}. Cause: RLC mode cannot be changed for an existing DRB", drb.drb_id)); diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp index a16188fcf1..9f770b6f7f 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -13,6 +13,23 @@ using namespace srsran; using namespace srs_du; +static rlc_mode get_rlc_mode(const asn1::f1ap::rlc_mode_e& asn1type) +{ + switch (asn1type) { + case asn1::f1ap::rlc_mode_opts::rlc_am: + return rlc_mode::am; + case asn1::f1ap::rlc_mode_opts::rlc_um_bidirectional: + return rlc_mode::um_bidir; + case asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_ul: + return rlc_mode::um_unidir_ul; + case asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_dl: + return rlc_mode::um_unidir_dl; + default: + break; + } + report_fatal_error("Invalid RLC mode"); +} + template static void fill_common_drb_config_request_fields(f1ap_drb_config_request& drb_obj, const ASN1Type& drb_item) { @@ -53,7 +70,7 @@ f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap f1ap_drb_config_request drb_obj; fill_common_drb_config_request_fields(drb_obj, drb_item); - drb_obj.mode = static_cast(static_cast(drb_item.rlc_mode)); + drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); if (drb_item.ie_exts_present) { drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); @@ -67,7 +84,7 @@ f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap f1ap_drb_config_request drb_obj; fill_common_drb_config_request_fields(drb_obj, drb_item); - drb_obj.mode = static_cast(static_cast(drb_item.rlc_mode)); + drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); if (drb_item.ie_exts_present) { if (drb_item.ie_exts.dl_pdcp_sn_len_present) { diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index 0b719d631e..ff8fdfc904 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -87,7 +87,7 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t for (drb_id_t drb_id : drbs_to_addmod) { req.drbs_to_setupmod.emplace_back(); req.drbs_to_setupmod.back().drb_id = drb_id; - req.drbs_to_setupmod.back().mode = drb_rlc_mode::am; + req.drbs_to_setupmod.back().mode = rlc_mode::am; req.drbs_to_setupmod.back().five_qi = uint_to_five_qi(9); req.drbs_to_setupmod.back().uluptnl_info_list.resize(1); req.drbs_to_setupmod.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index e1690f5399..e8889536f7 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -112,7 +112,7 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notif ASSERT_EQ(req.drbs_to_setupmod.size(), 1); ASSERT_EQ(req.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); ASSERT_FALSE(req.drbs_to_setupmod[0].lcid.has_value()); - ASSERT_EQ(req.drbs_to_setupmod[0].mode, drb_rlc_mode::am); + ASSERT_EQ(req.drbs_to_setupmod[0].mode, rlc_mode::am); ASSERT_EQ(req.drbs_to_setupmod[0].pdcp_sn_len, pdcp_sn_size::size12bits); } @@ -206,7 +206,7 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ ASSERT_EQ(test_ue->ue_index, request_to_du.ue_index); ASSERT_EQ(request_to_du.drbs_to_setupmod.size(), 1); ASSERT_EQ(request_to_du.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); - ASSERT_EQ(request_to_du.drbs_to_setupmod[0].mode, drb_rlc_mode::am); + ASSERT_EQ(request_to_du.drbs_to_setupmod[0].mode, rlc_mode::am); ASSERT_EQ(request_to_du.drbs_to_setupmod[0].pdcp_sn_len, pdcp_sn_size::size12bits); } From 956669b5e83573657a2db558fb640f6784de71b8 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 2 Aug 2024 11:14:28 +0200 Subject: [PATCH 070/407] f1ap-du: fix response of the ue context modification procedure --- .../f1ap/du/f1ap_du_ue_context_update.h | 12 +- .../procedures/ue_configuration_procedure.cpp | 10 +- ...p_du_ue_context_modification_procedure.cpp | 118 +++++++++++++----- .../f1ap_du_ue_context_setup_procedure.cpp | 14 +-- .../procedures/ue_configuration_test.cpp | 16 +-- .../f1ap_du_ue_context_modification_test.cpp | 10 +- ...1ap_du_ue_context_setup_procedure_test.cpp | 20 +-- 7 files changed, 125 insertions(+), 75 deletions(-) diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index b86d43077e..44fcbd4c78 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -62,7 +62,7 @@ struct f1ap_scell_to_setup { }; /// \brief DRB that was setup successfully in the F1AP UE context. -struct f1ap_drb_setup { +struct f1ap_drb_configured { drb_id_t drb_id; std::optional lcid; std::vector dluptnl_info_list; @@ -90,11 +90,11 @@ struct f1ap_ue_context_update_request { /// \brief Response from DU manager to DU F1AP with the result of the UE context update. struct f1ap_ue_context_update_response { - bool result; - std::vector drbs_setup; - std::vector drbs_failed_to_setup; - byte_buffer du_to_cu_rrc_container; - bool full_config_present = false; + bool result; + std::vector drbs_configured; + std::vector failed_drbs; + byte_buffer du_to_cu_rrc_container; + bool full_config_present = false; }; /// \brief Handled causes for RLF. diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index b3e956c61c..82b24793e7 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -245,15 +245,15 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo // > Handle DRBs that were setup or failed to be setup. for (const f1ap_drb_config_request& drb_req : request.drbs_to_setupmod) { if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { - resp.drbs_failed_to_setup.push_back(drb_req.drb_id); + resp.failed_drbs.push_back(drb_req.drb_id); continue; } du_ue_drb& drb_added = *ue->bearers.drbs().at(drb_req.drb_id); - resp.drbs_setup.emplace_back(); - f1ap_drb_setup& drb_setup = resp.drbs_setup.back(); - drb_setup.drb_id = drb_added.drb_id; - drb_setup.dluptnl_info_list = drb_added.dluptnl_info_list; + resp.drbs_configured.emplace_back(); + f1ap_drb_configured& drb_setup = resp.drbs_configured.back(); + drb_setup.drb_id = drb_added.drb_id; + drb_setup.dluptnl_info_list = drb_added.dluptnl_info_list; } // > Calculate ASN.1 CellGroupConfig to be sent in DU-to-CU container. diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index 6968a68bd7..850393f363 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -88,6 +88,22 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 } } +// helper function to fill asn1 DRBs-SetupMod and DRBs-Modified types. +template +static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_configured& drb) +{ + asn1obj.drb_id = drb_id_to_uint(drb.drb_id); + asn1obj.lcid_present = drb.lcid.has_value(); + if (asn1obj.lcid_present) { + asn1obj.lcid = drb.lcid.value(); + } + asn1obj.dl_up_tnl_info_to_be_setup_list.resize(drb.dluptnl_info_list.size()); + for (unsigned j = 0; j != drb.dluptnl_info_list.size(); ++j) { + up_transport_layer_info_to_asn1(asn1obj.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, + drb.dluptnl_info_list[j]); + } +} + void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_response() { f1ap_message f1ap_msg; @@ -99,42 +115,75 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res resp->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue.context.gnb_cu_ue_f1ap_id); resp->res_coordination_transfer_container_present = false; - // > DRBs-SetupMod-List. - resp->drbs_setup_mod_list_present = not du_response.drbs_setup.empty(); - resp->drbs_setup_mod_list.resize(du_response.drbs_setup.size()); - for (unsigned i = 0; i != du_response.drbs_setup.size(); ++i) { - resp->drbs_setup_mod_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); - const f1ap_drb_setup& drb_setup = du_response.drbs_setup[i]; - drbs_setup_mod_item_s& asn1_drb = resp->drbs_setup_mod_list[i]->drbs_setup_mod_item(); - asn1_drb.drb_id = drb_id_to_uint(du_request.drbs_to_setupmod[i].drb_id); - asn1_drb.lcid_present = drb_setup.lcid.has_value(); - if (asn1_drb.lcid_present) { - asn1_drb.lcid = drb_setup.lcid.value(); + // DRBs-SetupMod-List + DRBs-FailedToBeSetupMod-List. + for (const auto& req_drb : req->drbs_to_be_setup_mod_list) { + drb_id_t drb_id = uint_to_drb_id(req_drb.value().drbs_to_be_setup_mod_item().drb_id); + auto drb_it = std::find_if(du_response.drbs_configured.begin(), + du_response.drbs_configured.end(), + [drb_id](const f1ap_drb_configured& drb) { return drb.drb_id == drb_id; }); + if (drb_it != du_response.drbs_configured.end()) { + // > DRBs-SetupMod-List. + const f1ap_drb_configured& drb_setup = *drb_it; + resp->drbs_setup_mod_list_present = true; + resp->drbs_setup_mod_list.push_back({}); + resp->drbs_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); + drbs_setup_mod_item_s& asn1_drb = resp->drbs_setup_mod_list.back().value().drbs_setup_mod_item(); + fill_drb_setup_mod_common(asn1_drb, drb_setup); + continue; } - asn1_drb.dl_up_tnl_info_to_be_setup_list.resize(drb_setup.dluptnl_info_list.size()); - for (unsigned j = 0; j != drb_setup.dluptnl_info_list.size(); ++j) { - up_transport_layer_info_to_asn1(asn1_drb.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, - drb_setup.dluptnl_info_list[j]); + + // > DRBs-FailedToBeSetupMod-List. + if (std::count(du_response.failed_drbs.begin(), du_response.failed_drbs.end(), drb_id) == 0) { + logger.warning("DRB{} was not found in the list of configured DRBs by the DU.", drb_id); + continue; } - } - resp->drbs_modified_list_present = false; - resp->srbs_failed_to_be_setup_mod_list_present = false; - // > DRBs-FailedToBeSetupMod-List. - resp->drbs_failed_to_be_setup_mod_list_present = not du_response.drbs_failed_to_setup.empty(); - resp->drbs_failed_to_be_setup_mod_list.resize(du_response.drbs_failed_to_setup.size()); - for (unsigned i = 0; i != du_response.drbs_failed_to_setup.size(); ++i) { - resp->drbs_failed_to_be_setup_mod_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); + resp->drbs_failed_to_be_setup_mod_list_present = true; + resp->drbs_failed_to_be_setup_mod_list.push_back({}); + resp->drbs_failed_to_be_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); drbs_failed_to_be_setup_mod_item_s& asn1_drb = - resp->drbs_failed_to_be_setup_mod_list[i]->drbs_failed_to_be_setup_mod_item(); - asn1_drb.drb_id = drb_id_to_uint(du_response.drbs_failed_to_setup[i]); - asn1_drb.cause.set_transport().value = cause_transport_opts::transport_res_unavailable; + resp->drbs_failed_to_be_setup_mod_list.back()->drbs_failed_to_be_setup_mod_item(); + asn1_drb.drb_id = drb_id_to_uint(drb_id); + asn1_drb.cause_present = true; + asn1_drb.cause.set_radio_network().value = cause_radio_network_opts::no_radio_res_available; } - resp->scell_failedto_setup_mod_list_present = false; - resp->drbs_failed_to_be_modified_list_present = false; - resp->inactivity_monitoring_resp_present = false; - resp->crit_diagnostics_present = false; - resp->c_rnti_present = false; - resp->associated_scell_list_present = false; + + // DRBs-Modified-List + DRBs-FailedToBeModified-List. + for (const auto& req_drb : req->drbs_to_be_modified_list) { + drb_id_t drb_id = uint_to_drb_id(req_drb.value().drbs_to_be_modified_item().drb_id); + auto drb_it = std::find_if(du_response.drbs_configured.begin(), + du_response.drbs_configured.end(), + [drb_id](const f1ap_drb_configured& drb) { return drb.drb_id == drb_id; }); + if (drb_it != du_response.drbs_configured.end()) { + // > DRBs-Modified-List. + const f1ap_drb_configured& drb_mod = *drb_it; + resp->drbs_modified_list_present = true; + resp->drbs_modified_list.push_back({}); + resp->drbs_modified_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); + drbs_modified_item_s& asn1_drb = resp->drbs_modified_list.back().value().drbs_modified_item(); + fill_drb_setup_mod_common(asn1_drb, drb_mod); + continue; + } + + // > DRBs-FailedToBeModified-List. + if (std::count(du_response.failed_drbs.begin(), du_response.failed_drbs.end(), drb_id) == 0) { + logger.warning("DRB{} was not found in the list of configured DRBs by the DU.", drb_id); + continue; + } + resp->drbs_failed_to_be_modified_list_present = true; + resp->drbs_failed_to_be_modified_list.push_back({}); + resp->drbs_failed_to_be_modified_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_MODIFIED_ITEM); + drbs_failed_to_be_modified_item_s& asn1_drb = + resp->drbs_failed_to_be_modified_list.back()->drbs_failed_to_be_modified_item(); + asn1_drb.drb_id = drb_id_to_uint(drb_id); + asn1_drb.cause_present = true; + asn1_drb.cause.set_radio_network().value = cause_radio_network_opts::no_radio_res_available; + } + + resp->scell_failedto_setup_mod_list_present = false; + resp->inactivity_monitoring_resp_present = false; + resp->crit_diagnostics_present = false; + resp->c_rnti_present = false; + resp->associated_scell_list_present = false; // > SRBs-SetupMod-List. resp->srbs_setup_mod_list_present = not du_request.srbs_to_setup.empty(); @@ -145,8 +194,9 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res srb.srb_id = srb_id_to_uint(du_request.srbs_to_setup[i]); srb.lcid = srb_id_to_lcid(du_request.srbs_to_setup[i]); } - resp->srbs_modified_list_present = false; - resp->full_cfg_present = false; + resp->srbs_failed_to_be_setup_mod_list_present = false; + resp->srbs_modified_list_present = false; + resp->full_cfg_present = false; // > DU-to-CU RRC Container. if (not du_response.du_to_cu_rrc_container.empty()) { diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index cbb2a46ae1..fad9d5a775 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -192,13 +192,13 @@ void f1ap_du_ue_context_setup_procedure::send_ue_context_setup_response() } // > DRBs setup List. - resp->drbs_setup_list_present = not du_ue_cfg_response.drbs_setup.empty(); + resp->drbs_setup_list_present = not du_ue_cfg_response.drbs_configured.empty(); if (resp->drbs_setup_list_present) { - resp->drbs_setup_list.resize(du_ue_cfg_response.drbs_setup.size()); + resp->drbs_setup_list.resize(du_ue_cfg_response.drbs_configured.size()); for (unsigned i = 0; i != resp->drbs_setup_list.size(); ++i) { resp->drbs_setup_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_ITEM); drbs_setup_item_s& asn1_drb = resp->drbs_setup_list[i].value().drbs_setup_item(); - auto& drb_resp = du_ue_cfg_response.drbs_setup[i]; + auto& drb_resp = du_ue_cfg_response.drbs_configured[i]; asn1_drb.drb_id = drb_id_to_uint(drb_resp.drb_id); asn1_drb.lcid_present = drb_resp.lcid.has_value(); if (asn1_drb.lcid_present) { @@ -213,13 +213,13 @@ void f1ap_du_ue_context_setup_procedure::send_ue_context_setup_response() } // > DRBs-FailedToBeSetupMod-List. - resp->drbs_failed_to_be_setup_list_present = not du_ue_cfg_response.drbs_failed_to_setup.empty(); + resp->drbs_failed_to_be_setup_list_present = not du_ue_cfg_response.failed_drbs.empty(); if (resp->drbs_failed_to_be_setup_list_present) { - resp->drbs_failed_to_be_setup_list.resize(du_ue_cfg_response.drbs_failed_to_setup.size()); - for (unsigned i = 0; i != du_ue_cfg_response.drbs_failed_to_setup.size(); ++i) { + resp->drbs_failed_to_be_setup_list.resize(du_ue_cfg_response.failed_drbs.size()); + for (unsigned i = 0; i != du_ue_cfg_response.failed_drbs.size(); ++i) { resp->drbs_failed_to_be_setup_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); drbs_failed_to_be_setup_item_s& asn1_drb = resp->drbs_failed_to_be_setup_list[i]->drbs_failed_to_be_setup_item(); - asn1_drb.drb_id = drb_id_to_uint(du_ue_cfg_response.drbs_failed_to_setup[i]); + asn1_drb.drb_id = drb_id_to_uint(du_ue_cfg_response.failed_drbs[i]); asn1_drb.cause.set_transport().value = cause_transport_opts::transport_res_unavailable; } } diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 3a3c3d18ef..2f7640720e 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -284,9 +284,9 @@ TEST_F(ue_config_tester, when_f1u_gw_fails_to_create_bearer_then_drb_is_included ASSERT_TRUE(proc.ready()); f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); - ASSERT_EQ(resp.drbs_setup.size(), 0); - ASSERT_EQ(resp.drbs_failed_to_setup.size(), 1); - ASSERT_EQ(resp.drbs_failed_to_setup[0], drb_id_t::drb1); + ASSERT_EQ(resp.drbs_configured.size(), 0); + ASSERT_EQ(resp.failed_drbs.size(), 1); + ASSERT_EQ(resp.failed_drbs[0], drb_id_t::drb1); } TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_included_in_failed_list) @@ -317,9 +317,9 @@ TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_inc ASSERT_TRUE(proc.ready()); f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); - ASSERT_EQ(resp.drbs_setup.size(), 0); - ASSERT_EQ(resp.drbs_failed_to_setup.size(), 1); - ASSERT_EQ(resp.drbs_failed_to_setup[0], drb_id_t::drb1); + ASSERT_EQ(resp.drbs_configured.size(), 0); + ASSERT_EQ(resp.failed_drbs.size(), 1); + ASSERT_EQ(resp.failed_drbs[0], drb_id_t::drb1); } TEST_F(ue_config_tester, when_config_is_empty_then_procedure_avoids_configuring_other_layers_and_returns_success) @@ -337,8 +337,8 @@ TEST_F(ue_config_tester, when_config_is_empty_then_procedure_avoids_configuring_ f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); ASSERT_FALSE(resp.du_to_cu_rrc_container.empty()); - ASSERT_TRUE(resp.drbs_setup.empty()); - ASSERT_TRUE(resp.drbs_failed_to_setup.empty()); + ASSERT_TRUE(resp.drbs_configured.empty()); + ASSERT_TRUE(resp.failed_drbs.empty()); } TEST_F(ue_config_tester, when_drbs_are_released_then_they_are_added_in_rrc_container) diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp index 64cec138a3..490d49fe9d 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp @@ -35,8 +35,8 @@ class f1ap_du_ue_context_modification_test : public f1ap_du_test // Prepare DU manager response to F1AP. this->f1ap_du_cfg_handler.next_ue_context_update_response.result = true; for (drb_id_t drb_id : drbs) { - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup.emplace_back(); - auto& drb = this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup.back(); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured.emplace_back(); + auto& drb = this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured.back(); drb.drb_id = drb_id; drb.dluptnl_info_list.resize(1); drb.dluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(test_rgen::uniform_int()); @@ -100,10 +100,10 @@ TEST_F(f1ap_du_ue_context_modification_test, ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list.size(), 1); ASSERT_EQ( int_to_gtpu_teid(drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().gtp_teid.to_number()), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list[0].gtp_teid); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list[0].gtp_teid); ASSERT_EQ( drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().transport_layer_address.to_string(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0] + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0] .dluptnl_info_list[0] .tp_address.to_bitstring()); ASSERT_EQ(resp->du_to_cu_rrc_info.cell_group_cfg, @@ -115,7 +115,7 @@ TEST_F(f1ap_du_ue_context_modification_test, { // Prepare DU manager response to F1AP with failed DRB. this->f1ap_du_cfg_handler.next_ue_context_update_response.result = true; - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_failed_to_setup.push_back(drb_id_t::drb1); + this->f1ap_du_cfg_handler.next_ue_context_update_response.failed_drbs.push_back(drb_id_t::drb1); this->f1ap_du_cfg_handler.next_ue_context_update_response.du_to_cu_rrc_container = byte_buffer::create({0x1, 0x2, 0x3}).value(); diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index e8889536f7..64a8f45cb1 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -67,13 +67,13 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test du_to_f1_resp.result = true; du_to_f1_resp.du_to_cu_rrc_container = byte_buffer::create({0x1, 0x2, 0x3}).value(); if (ue_ctx_setup.drbs_to_be_setup_list_present) { - du_to_f1_resp.drbs_setup.resize(ue_ctx_setup.drbs_to_be_setup_list.size()); + du_to_f1_resp.drbs_configured.resize(ue_ctx_setup.drbs_to_be_setup_list.size()); for (size_t i = 0; i < ue_ctx_setup.drbs_to_be_setup_list.size(); ++i) { - uint8_t drb_id = ue_ctx_setup.drbs_to_be_setup_list[i]->drbs_to_be_setup_item().drb_id; - du_to_f1_resp.drbs_setup[i].drb_id = uint_to_drb_id(drb_id); - du_to_f1_resp.drbs_setup[i].lcid = uint_to_lcid((uint8_t)LCID_MIN_DRB + drb_id); - du_to_f1_resp.drbs_setup[i].dluptnl_info_list.resize(1); - du_to_f1_resp.drbs_setup[i].dluptnl_info_list[0] = + uint8_t drb_id = ue_ctx_setup.drbs_to_be_setup_list[i]->drbs_to_be_setup_item().drb_id; + du_to_f1_resp.drbs_configured[i].drb_id = uint_to_drb_id(drb_id); + du_to_f1_resp.drbs_configured[i].lcid = uint_to_lcid((uint8_t)LCID_MIN_DRB + drb_id); + du_to_f1_resp.drbs_configured[i].dluptnl_info_list.resize(1); + du_to_f1_resp.drbs_configured[i].dluptnl_info_list[0] = up_transport_layer_info{transport_layer_address::create_from_string("127.0.0.1"), int_to_gtpu_teid(1)}; } } @@ -144,9 +144,9 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_respo ASSERT_EQ(drb_setup.drb_id, 1); ASSERT_TRUE(drb_setup.lcid_present); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list.size(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list.size()); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list.size()); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().gtp_teid.to_number(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list[0].gtp_teid); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list[0].gtp_teid); ASSERT_EQ(resp->du_to_cu_rrc_info.cell_group_cfg, this->f1ap_du_cfg_handler.next_ue_context_update_response.du_to_cu_rrc_container); } @@ -235,9 +235,9 @@ TEST_F( ASSERT_EQ(drb_setup.drb_id, 1); ASSERT_TRUE(drb_setup.lcid_present); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list.size(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list.size()); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list.size()); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().gtp_teid.to_number(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list[0].gtp_teid); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list[0].gtp_teid); } TEST_F(f1ap_du_test, f1ap_handles_precanned_ue_context_setup_request_correctly) From f613de8112c69592711c1928cc4e66b6cc0a7f67 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 2 Aug 2024 11:28:32 +0200 Subject: [PATCH 071/407] f1ap-du: reuse helper methods for ue context setup and modification --- .../procedures/f1ap_du_ue_context_common.cpp | 37 +++++++++++++++++++ .../du/procedures/f1ap_du_ue_context_common.h | 4 ++ ...p_du_ue_context_modification_procedure.cpp | 22 +---------- .../f1ap_du_ue_context_setup_procedure.cpp | 16 ++------ 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp index 9f770b6f7f..6f35eb45e9 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -108,3 +108,40 @@ f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap return drb_obj; } + +// helper function to fill asn1 DRBs-SetupMod and DRBs-Modified types. +template +static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_configured& drb) +{ + asn1obj.drb_id = drb_id_to_uint(drb.drb_id); + asn1obj.lcid_present = drb.lcid.has_value(); + if (asn1obj.lcid_present) { + asn1obj.lcid = drb.lcid.value(); + } + asn1obj.dl_up_tnl_info_to_be_setup_list.resize(drb.dluptnl_info_list.size()); + for (unsigned j = 0; j != drb.dluptnl_info_list.size(); ++j) { + up_transport_layer_info_to_asn1(asn1obj.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, + drb.dluptnl_info_list[j]); + } +} + +asn1::f1ap::drbs_setup_item_s srsran::srs_du::make_drbs_setup_item(const f1ap_drb_configured& drb_obj) +{ + asn1::f1ap::drbs_setup_item_s asn1_drb; + fill_drb_setup_mod_common(asn1_drb, drb_obj); + return asn1_drb; +} + +asn1::f1ap::drbs_setup_mod_item_s srsran::srs_du::make_drbs_setup_mod_item(const f1ap_drb_configured& drb_obj) +{ + asn1::f1ap::drbs_setup_mod_item_s asn1_drb; + fill_drb_setup_mod_common(asn1_drb, drb_obj); + return asn1_drb; +} + +asn1::f1ap::drbs_modified_item_s srsran::srs_du::make_drbs_modified_item(const f1ap_drb_configured& drb_obj) +{ + asn1::f1ap::drbs_modified_item_s asn1_drb; + fill_drb_setup_mod_common(asn1_drb, drb_obj); + return asn1_drb; +} diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h index 4436c6449a..780266042d 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h @@ -40,6 +40,10 @@ f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_set /// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_config_request. f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); +asn1::f1ap::drbs_setup_item_s make_drbs_setup_item(const f1ap_drb_configured& drb_obj); +asn1::f1ap::drbs_setup_mod_item_s make_drbs_setup_mod_item(const f1ap_drb_configured& drb_obj); +asn1::f1ap::drbs_modified_item_s make_drbs_modified_item(const f1ap_drb_configured& drb_obj); + /// \brief Creates a \c drb_id_t from ASN.1 type. /// /// This function is used by the following procedures: diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index 850393f363..bf90ca786d 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -88,22 +88,6 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 } } -// helper function to fill asn1 DRBs-SetupMod and DRBs-Modified types. -template -static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_configured& drb) -{ - asn1obj.drb_id = drb_id_to_uint(drb.drb_id); - asn1obj.lcid_present = drb.lcid.has_value(); - if (asn1obj.lcid_present) { - asn1obj.lcid = drb.lcid.value(); - } - asn1obj.dl_up_tnl_info_to_be_setup_list.resize(drb.dluptnl_info_list.size()); - for (unsigned j = 0; j != drb.dluptnl_info_list.size(); ++j) { - up_transport_layer_info_to_asn1(asn1obj.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, - drb.dluptnl_info_list[j]); - } -} - void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_response() { f1ap_message f1ap_msg; @@ -127,8 +111,7 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res resp->drbs_setup_mod_list_present = true; resp->drbs_setup_mod_list.push_back({}); resp->drbs_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); - drbs_setup_mod_item_s& asn1_drb = resp->drbs_setup_mod_list.back().value().drbs_setup_mod_item(); - fill_drb_setup_mod_common(asn1_drb, drb_setup); + resp->drbs_setup_mod_list.back().value().drbs_setup_mod_item() = make_drbs_setup_mod_item(drb_setup); continue; } @@ -159,8 +142,7 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res resp->drbs_modified_list_present = true; resp->drbs_modified_list.push_back({}); resp->drbs_modified_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); - drbs_modified_item_s& asn1_drb = resp->drbs_modified_list.back().value().drbs_modified_item(); - fill_drb_setup_mod_common(asn1_drb, drb_mod); + resp->drbs_modified_list.back().value().drbs_modified_item() = make_drbs_modified_item(drb_mod); continue; } diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index fad9d5a775..109a5fcb32 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -197,18 +197,7 @@ void f1ap_du_ue_context_setup_procedure::send_ue_context_setup_response() resp->drbs_setup_list.resize(du_ue_cfg_response.drbs_configured.size()); for (unsigned i = 0; i != resp->drbs_setup_list.size(); ++i) { resp->drbs_setup_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_ITEM); - drbs_setup_item_s& asn1_drb = resp->drbs_setup_list[i].value().drbs_setup_item(); - auto& drb_resp = du_ue_cfg_response.drbs_configured[i]; - asn1_drb.drb_id = drb_id_to_uint(drb_resp.drb_id); - asn1_drb.lcid_present = drb_resp.lcid.has_value(); - if (asn1_drb.lcid_present) { - asn1_drb.lcid = drb_resp.lcid.value(); - } - asn1_drb.dl_up_tnl_info_to_be_setup_list.resize(drb_resp.dluptnl_info_list.size()); - for (unsigned j = 0; j != drb_resp.dluptnl_info_list.size(); ++j) { - up_transport_layer_info_to_asn1(asn1_drb.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, - drb_resp.dluptnl_info_list[j]); - } + resp->drbs_setup_list[i].value().drbs_setup_item() = make_drbs_setup_item(du_ue_cfg_response.drbs_configured[i]); } } @@ -220,7 +209,8 @@ void f1ap_du_ue_context_setup_procedure::send_ue_context_setup_response() resp->drbs_failed_to_be_setup_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); drbs_failed_to_be_setup_item_s& asn1_drb = resp->drbs_failed_to_be_setup_list[i]->drbs_failed_to_be_setup_item(); asn1_drb.drb_id = drb_id_to_uint(du_ue_cfg_response.failed_drbs[i]); - asn1_drb.cause.set_transport().value = cause_transport_opts::transport_res_unavailable; + asn1_drb.cause_present = true; + asn1_drb.cause.set_radio_network().value = cause_radio_network_opts::no_radio_res_available; } } From 0bd0743f55e9ec5b5d41073d48299b4335303384 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Fri, 2 Aug 2024 20:15:37 +0000 Subject: [PATCH 072/407] Revert "srsvec,compression: improve simd in bf16 conversion, optimize AVX implementations of decompressors" --- include/srsran/srsvec/prod.h | 1 - include/srsran/srsvec/sc_prod.h | 1 - .../compression/iq_compression_bfp_avx2.cpp | 32 ++++++--------- .../compression/iq_compression_bfp_avx512.cpp | 32 ++++++--------- .../compression/iq_compression_bfp_neon.cpp | 1 - .../compression/iq_compression_none_avx2.cpp | 24 ++++++------ .../iq_compression_none_avx512.cpp | 23 ++++++----- .../compression/iq_compression_none_neon.cpp | 17 ++++---- lib/srsvec/conversion.cpp | 33 +--------------- lib/srsvec/prod.cpp | 39 ------------------- lib/srsvec/sc_prod.cpp | 37 ------------------ lib/srsvec/simd.h | 34 +++------------- 12 files changed, 58 insertions(+), 216 deletions(-) diff --git a/include/srsran/srsvec/prod.h b/include/srsran/srsvec/prod.h index 15691be6bd..1f69b2b7d8 100644 --- a/include/srsran/srsvec/prod.h +++ b/include/srsran/srsvec/prod.h @@ -19,7 +19,6 @@ void prod(span x, span y, span z); void prod(span x, span y, span z); void prod(span x, span y, span z); void prod(span x, span y, span z); -void prod(span x, span y, span z); void prod_conj(span x, span y, span z); diff --git a/include/srsran/srsvec/sc_prod.h b/include/srsran/srsvec/sc_prod.h index 18c675d0db..4c0f26dd19 100644 --- a/include/srsran/srsvec/sc_prod.h +++ b/include/srsran/srsvec/sc_prod.h @@ -19,7 +19,6 @@ void sc_prod(span x, cf_t h, span z); void sc_prod(span x, cf_t h, span z); void sc_prod(span x, float h, span z); void sc_prod(span x, float h, span z); -void sc_prod(span x, int16_t h, span z); } // namespace srsvec } // namespace srsran diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.cpp b/lib/ofh/compression/iq_compression_bfp_avx2.cpp index 56bfb3b3a8..de4a2de91d 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx2.cpp @@ -12,7 +12,6 @@ #include "avx2_helpers.h" #include "packing_utils_avx2.h" #include "quantizer.h" -#include "srsran/srsvec/prod.h" using namespace srsran; using namespace ofh; @@ -94,33 +93,24 @@ void iq_compression_bfp_avx2::decompress(span output, quantizer q_out(Q_BIT_WIDTH); - // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. - constexpr size_t avx2_size_iqs = 16; - constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; - - alignas(64) std::array unpacked_iq_data; - alignas(64) std::array unpacked_iq_scaling; - - unsigned idx = 0; + unsigned out_idx = 0; for (const auto& c_prb : input) { // Compute scaling factor. uint8_t exponent = c_prb.get_compression_param(); int16_t scaler = 1 << exponent; + // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. + constexpr size_t avx2_size_iqs = 16; + constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; + alignas(64) std::array unpacked_iq_data; // Unpack resource block. - span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); - mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - // Save scaling factor. - std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); - idx += (NOF_SUBCARRIERS_PER_RB * 2); + // Convert to complex samples. + q_out.to_brain_float(output_span, unpacked_span, scaler); + out_idx += NOF_SUBCARRIERS_PER_RB; } - - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); - // Scale unpacked IQ samples using saved exponents. - srsvec::prod(unpacked_iq_int16_span, unpacked_iq_scaling_span, unpacked_iq_int16_span); - // Convert to complex samples. - q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.cpp b/lib/ofh/compression/iq_compression_bfp_avx512.cpp index f2760557fe..98b4ed782d 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx512.cpp @@ -12,7 +12,6 @@ #include "avx512_helpers.h" #include "packing_utils_avx512.h" #include "quantizer.h" -#include "srsran/srsvec/prod.h" using namespace srsran; using namespace ofh; @@ -136,33 +135,24 @@ void iq_compression_bfp_avx512::decompress(span output, quantizer q_out(Q_BIT_WIDTH); - // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. - constexpr size_t avx512_size_iqs = 32; - constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx512_size_iqs) * avx512_size_iqs; - - alignas(64) std::array unpacked_iq_data; - alignas(64) std::array unpacked_iq_scaling; - - unsigned idx = 0; + unsigned out_idx = 0; for (const auto& c_prb : input) { // Compute scaling factor. uint8_t exponent = c_prb.get_compression_param(); int16_t scaler = 1 << exponent; + // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. + constexpr size_t avx512_size_iqs = 32; + constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx512_size_iqs) * avx512_size_iqs; + alignas(64) std::array unpacked_iq_data; // Unpack resource block. - span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); - mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - // Save scaling factor. - std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); - idx += (NOF_SUBCARRIERS_PER_RB * 2); + // Convert to complex samples. + q_out.to_brain_float(output_span, unpacked_span, scaler); + out_idx += NOF_SUBCARRIERS_PER_RB; } - - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); - // Scale unpacked IQ samples using saved exponents. - srsvec::prod(unpacked_iq_int16_span, unpacked_iq_scaling_span, unpacked_iq_int16_span); - // Convert to complex samples. - q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_bfp_neon.cpp b/lib/ofh/compression/iq_compression_bfp_neon.cpp index 35533c9a33..004ae68a17 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.cpp +++ b/lib/ofh/compression/iq_compression_bfp_neon.cpp @@ -209,7 +209,6 @@ void iq_compression_bfp_neon::decompress(span output, constexpr size_t neon_size_iqs = 8; constexpr size_t arr_size = divide_ceil(NOF_SAMPLES_PER_PRB, neon_size_iqs) * neon_size_iqs; alignas(64) std::array unpacked_iq_data; - // Unpack resource block. neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); diff --git a/lib/ofh/compression/iq_compression_none_avx2.cpp b/lib/ofh/compression/iq_compression_none_avx2.cpp index f818d6685b..8abec79574 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.cpp +++ b/lib/ofh/compression/iq_compression_none_avx2.cpp @@ -86,20 +86,20 @@ void iq_compression_none_avx2::decompress(span output, // Quantizer object. quantizer q(params.data_width); - constexpr size_t avx2_size_iqs = 16; - constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; - alignas(64) std::array unpacked_iq_data; - - unsigned idx = 0; + unsigned out_idx = 0; for (const auto& c_prb : input) { + constexpr size_t avx2_size_iqs = 16; + constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; + alignas(64) std::array unpacked_iq_data; + // Unpack resource block. - span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); - mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - idx += (NOF_SUBCARRIERS_PER_RB * 2); - } + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - // Convert to complex brain float samples. - q.to_brain_float(output, unpacked_iq_int16_span, 1); + // Convert to complex samples. + q.to_brain_float(output_span, unpacked_span, 1); + out_idx += NOF_SUBCARRIERS_PER_RB; + } } diff --git a/lib/ofh/compression/iq_compression_none_avx512.cpp b/lib/ofh/compression/iq_compression_none_avx512.cpp index dac64caa52..00bdd83246 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.cpp +++ b/lib/ofh/compression/iq_compression_none_avx512.cpp @@ -70,20 +70,19 @@ void iq_compression_none_avx512::decompress(span output, } // Quantizer object. - quantizer q_out(params.data_width); - - std::array unpacked_iq_data; + quantizer q(params.data_width); - unsigned idx = 0; - for (const compressed_prb& c_prb : input) { + unsigned out_idx = 0; + for (const auto& c_prb : input) { + std::array unpacked_iq_data; // Unpack resource block. - span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); - mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - idx += (NOF_SUBCARRIERS_PER_RB * 2); - } + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - // Convert to complex brain float samples. - q_out.to_brain_float(output, unpacked_iq_int16_span, 1); + // Convert to complex samples. + q.to_brain_float(output_span, unpacked_span, 1); + out_idx += NOF_SUBCARRIERS_PER_RB; + } } diff --git a/lib/ofh/compression/iq_compression_none_neon.cpp b/lib/ofh/compression/iq_compression_none_neon.cpp index 38182270c1..d2925ab929 100644 --- a/lib/ofh/compression/iq_compression_none_neon.cpp +++ b/lib/ofh/compression/iq_compression_none_neon.cpp @@ -107,18 +107,15 @@ void iq_compression_none_neon::decompress(span output, quantizer q_out(params.data_width); - std::array unpacked_iq_data; - - unsigned idx = 0; + unsigned out_idx = 0; for (const compressed_prb& c_prb : input) { // Unpack resource block. - span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); - neon::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + std::array unpacked_iq_data; + neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - idx += (NOF_SUBCARRIERS_PER_RB * 2); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + // Convert to complex samples. + q_out.to_brain_float(output_span, unpacked_iq_data, 1); + out_idx += NOF_SUBCARRIERS_PER_RB; } - - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - // Convert to complex brain float samples. - q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index d59378b171..d1897e8493 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -107,7 +107,7 @@ static void convert_if_simd(float* z, const int16_t* x, float scale, unsigned le __m256 float_vec = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(input_vec)); float_vec = _mm256_mul_ps(float_vec, scale256); - // Store the result back to memory. + // Store the result back to memory _mm256_storeu_ps(z + i, float_vec); } #endif // defined(__AVX__) && defined(__AVX2__) @@ -136,17 +136,6 @@ static void convert_bf16_to_f_simd(float* out, const bf16_t* in, unsigned len) { unsigned i = 0; -#if defined(__ARM_NEON) && defined(__ARM_FEATURE_BF16_VECTOR_ARITHMETIC) - for (unsigned i_end = (len / 4) * 4; i != i_end; i += 4) { - // Load 4 bf16 elements into a 64-bit vector register. - bfloat16x4_t input_vec = vld1_bf16(reinterpret_cast(in + i)); - // Convert bf16 to single-precision floating point. - float32x4_t output_vec = vcvt_f32_bf16(input_vec); - // Store the result back to memory. - srsran_simd_f_storeu(out + i, output_vec); - } -#else // __ARM_FEATURE_BF16 - #if SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE for (unsigned end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != end; i += SRSRAN_SIMD_S_SIZE) { simd_f_t even, odd; @@ -156,7 +145,6 @@ static void convert_bf16_to_f_simd(float* out, const bf16_t* in, unsigned len) srsran_simd_f_storeu_interleaved(out + i, even, odd); } #endif // SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE -#endif // __ARM_FEATURE_BF16 for (; i != len; ++i) { out[i] = to_float(in[i]); @@ -315,25 +303,6 @@ static void convert_int16_to_bf16_simd(bf16_t* out, const int16_t* in, float sca #endif // defined(__AVX__) && defined(__AVX2__) #endif // defined(__AVX__) && defined(__AVX512F__) -#if defined(__ARM_NEON) - // Load the scale factor into a vector register. - float32x4_t scale_f32 = vdupq_n_f32(gain); - - // Process 8 elements at a time (128 bits / 16 bits per brain float = 8 floats). - for (unsigned i_end = (len / 8) * 8; i != i_end; i += 8) { - // Load 8 int16_t elements into a 128-bit vector register. - int16x8_t input_vec = vld1q_s16(in + i); - - // Convert the int16_t elements to float and scale them. - float32x4_t float_vec_1 = vcvtq_f32_s32(vmovl_s16(vget_low_s16(input_vec))); - float32x4_t float_vec_2 = vcvtq_f32_s32(vmovl_high_s16(input_vec)); - float_vec_1 = vmulq_f32(float_vec_1, scale_f32); - float_vec_2 = vmulq_f32(float_vec_2, scale_f32); - - // Convert float to brain float and store the result back to memory. - srsran_simd_bf16_storeu(out + i, float_vec_1, float_vec_2); - } -#endif // defined(__ARM_NEON) for (; i != len; ++i) { out[i] = to_bf16(static_cast(in[i]) * gain); } diff --git a/lib/srsvec/prod.cpp b/lib/srsvec/prod.cpp index b3527552b6..54ac141cb8 100644 --- a/lib/srsvec/prod.cpp +++ b/lib/srsvec/prod.cpp @@ -46,37 +46,6 @@ static void prod_fff_simd(const float* x, const float* y, float* z, std::size_t } } -static void prod_sss_simd(const int16_t* x, const int16_t* y, int16_t* z, std::size_t len) -{ - std::size_t i = 0; - -#if SRSRAN_SIMD_S_SIZE - if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { - for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { - simd_s_t a = srsran_simd_s_load(x + i); - simd_s_t b = srsran_simd_s_load(y + i); - - simd_s_t r = srsran_simd_s_mul(a, b); - - srsran_simd_s_store(z + i, r); - } - } else { - for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { - simd_s_t a = srsran_simd_s_loadu(x + i); - simd_s_t b = srsran_simd_s_loadu(y + i); - - simd_s_t r = srsran_simd_s_mul(a, b); - - srsran_simd_s_storeu(z + i, r); - } - } -#endif - - for (; i != len; ++i) { - z[i] = x[i] * y[i]; - } -} - static void prod_ccc_simd(const cf_t* x, const cf_t* y, cf_t* z, std::size_t len) { std::size_t i = 0; @@ -155,14 +124,6 @@ void srsran::srsvec::prod(span x, span y, span prod_fff_simd(x.data(), y.data(), z.data(), x.size()); } -void srsran::srsvec::prod(span x, span y, span z) -{ - srsran_srsvec_assert_size(x, y); - srsran_srsvec_assert_size(x, z); - - prod_sss_simd(x.data(), y.data(), z.data(), x.size()); -} - void srsran::srsvec::prod_conj(span x, span y, span z) { srsran_srsvec_assert_size(x, y); diff --git a/lib/srsvec/sc_prod.cpp b/lib/srsvec/sc_prod.cpp index 44ed3f72a4..1f0f40b50d 100644 --- a/lib/srsvec/sc_prod.cpp +++ b/lib/srsvec/sc_prod.cpp @@ -94,36 +94,6 @@ static void sc_prod_ccc_simd(const cbf16_t* x, cf_t h, cbf16_t* z, std::size_t l } } -static void sc_prod_sss_simd(const int16_t* x, int16_t h, int16_t* z, std::size_t len) -{ - std::size_t i = 0; - -#if SRSRAN_SIMD_S_SIZE - simd_s_t b = srsran_simd_s_set1(h); - if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(z)) { - for (unsigned i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { - simd_s_t a = srsran_simd_s_load(x + i); - - simd_s_t r = srsran_simd_s_mul(a, b); - - srsran_simd_s_store(z + i, r); - } - } else { - for (unsigned i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { - simd_s_t a = srsran_simd_s_loadu(x + i); - - simd_s_t r = srsran_simd_s_mul(a, b); - - srsran_simd_s_storeu(z + i, r); - } - } -#endif - - for (; i != len; ++i) { - z[i] = x[i] * h; - } -} - void srsran::srsvec::sc_prod(span x, cf_t h, span z) { srsran_srsvec_assert_size(x, z); @@ -151,10 +121,3 @@ void srsran::srsvec::sc_prod(span x, cf_t h, span z) sc_prod_ccc_simd(x.data(), h, z.data(), x.size()); } - -void srsran::srsvec::sc_prod(span x, int16_t h, span z) -{ - srsran_srsvec_assert_size(x, z); - - sc_prod_sss_simd(x.data(), h, z.data(), x.size()); -} diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index afbe05f9ab..600137901e 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -1803,25 +1803,6 @@ inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) #endif /* __AVX512F__ */ } -inline simd_s_t srsran_simd_s_set1(int16_t x) -{ -#ifdef __AVX512F__ - return _mm512_set1_epi16(x); -#else /* __AVX512F__ */ -#ifdef __AVX2__ - return _mm256_set1_epi16(x); -#else /* __AVX2__ */ -#ifdef __SSE4_1__ - return _mm_set1_epi16(x); -#else /* __SSE4_1__ */ -#ifdef __ARM_NEON - return vdupq_n_s16(x); -#endif /* __ARM_NEON */ -#endif /* __SSE4_1__ */ -#endif /* __AVX2__ */ -#endif /* __AVX512F__ */ -} - #endif /* SRSRAN_SIMD_S_SIZE */ #if SRSRAN_SIMD_C16_SIZE @@ -2226,7 +2207,7 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) 0x3b0039, 0x3f003d), b_i32); -#else // __AVX512BW__ +#else // __AVX512BW__ const __m512i mask = _mm512_set1_epi32(0xffff0000); // Input: a0 xx | a1 xx | a2 xx | a3 xx | a4 xx | a5 xx | a6 xx | a7 xx | ... | a15 xx | // Transformations: @@ -2263,8 +2244,9 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) a_packed, _mm512_setr_epi32(0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e), b_packed); -#endif // __AVX512BW__ -#else /* __AVX512F__ */ +#endif + +#else /* __AVX512F__ */ #ifdef __AVX2__ const __m256i bias = _mm256_set1_epi32(0x7fff); const __m256i one = _mm256_set1_epi32(0x1); @@ -2329,11 +2311,6 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) ret = _mm_blend_epi16(a_packed, b_packed, 0xf0); #else /* __ARM_NEON */ #ifdef __ARM_NEON -#ifdef __ARM_FEATURE_BF16_VECTOR_ARITHMETIC - bfloat16x4_t tmp1 = vcvt_bf16_f32(a); - bfloat16x4_t tmp2 = vcvt_bf16_f32(b); - ret = vreinterpretq_s16_bf16(vcombine_bf16(tmp1, tmp2)); -#else // __ARM_FEATURE_BF16_VECTOR_ARITHMETIC const uint32x4_t bias = vdupq_n_u32(0x7fff); const uint32x4_t one = vdupq_n_u32(0x1); @@ -2353,8 +2330,7 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) uint16x8_t tmp_b_2 = vextq_u16(tmp_b_1, tmp_b_1, 1); uint32x4_t b_packed = vreinterpretq_u32_u16(vorrq_u16(tmp_b_1, tmp_b_2)); - ret = vreinterpretq_s16_u32(vuzpq_u32(a_packed, b_packed).val[0]); -#endif /* __ARM_FEATURE_BF16_VECTOR_ARITHMETIC */ + ret = vreinterpretq_s16_u32(vuzpq_u32(a_packed, b_packed).val[0]); #endif /* __ARM_NEON */ #endif /* __SSE4_1__ */ #endif /* __AVX2__ */ From 04472f5f01d2f832da1f5aef57f51fd8decf48cc Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 19 Feb 2024 17:56:31 +0100 Subject: [PATCH 073/407] docs: remove math_macros File math_macros cannot have comments, not even copyright ones. Therefore, we make cmake generate it. --- docs/CMakeGenerateTeXMacros.txt | 25 +++++++++++++++++++++++++ docs/CMakeLists.txt | 2 ++ docs/math_macros.tex | 21 --------------------- 3 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 docs/CMakeGenerateTeXMacros.txt delete mode 100644 docs/math_macros.tex diff --git a/docs/CMakeGenerateTeXMacros.txt b/docs/CMakeGenerateTeXMacros.txt new file mode 100644 index 0000000000..d1a886d975 --- /dev/null +++ b/docs/CMakeGenerateTeXMacros.txt @@ -0,0 +1,25 @@ +# +# 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. +# + +file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/math_macros.tex + "\\renewcommand{\\Re}{\\mathbb{R}\\mathrm{e}}\n" + "\\renewcommand{\\Im}{\\mathbb{I}\\mathrm{m}}\n" + "\n" + "\\newcommand{\\ls}{\\mathrm{LS}}\n" + "\\newcommand{\\mj}{\\mathrm{j}}\n" + "\\newcommand{\\me}{\\mathrm{e}}\n" + "\\newcommand{\\sign}{\\mathrm{sign}}\n" + "\n" + "\\newcommand{\\abs}[1]{\\lvert #1 \\rvert}\n" + "\\newcommand{\\norm}[1]{\\lVert #1 \\rVert}\n" + "\\newcommand{\\conj}[1]{\\overline{#1}}\n" + "\n" + "\\newcommand{\\EV}{\\mathbb{E}}\n" + "\n" + "\\newcommand{\\textup}[1]{\\text{#1}}\n" +) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 845875f757..30b8900a1b 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -10,6 +10,8 @@ find_package(Doxygen OPTIONAL_COMPONENTS dot) if (DOXYGEN_FOUND) + include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeGenerateTeXMacros.txt) + # Configure doxygen set(DOXYGEN_PROJECT_NAME "srsRAN Project") set(DOXYGEN_PROJECT_NUMBER ${VERSION}) diff --git a/docs/math_macros.tex b/docs/math_macros.tex deleted file mode 100644 index a717dff6f5..0000000000 --- a/docs/math_macros.tex +++ /dev/null @@ -1,21 +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. - -\renewcommand{\Re}{\mathbb{R}\mathrm{e}} -\renewcommand{\Im}{\mathbb{I}\mathrm{m}} - -\newcommand{\ls}{\mathrm{LS}} -\newcommand{\mj}{\mathrm{j}} -\newcommand{\me}{\mathrm{e}} -\newcommand{\sign}{\mathrm{sign}} - -\newcommand{\abs}[1]{\lvert #1 \rvert} -\newcommand{\norm}[1]{\lVert #1 \rVert} -\newcommand{\conj}[1]{\overline{#1}} - -\newcommand{\EV}{\mathbb{E}} - -\newcommand{\textup}[1]{\text{#1}} From 9edc0b8c8b37f095e8667fe739f8ba2396fb91d5 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 20 Feb 2024 15:25:06 +0100 Subject: [PATCH 074/407] add missing copyright header --- lib/phy/generic_functions/dft_processor_generic_impl.cpp | 9 +++++++++ lib/phy/generic_functions/dft_processor_generic_impl.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/phy/generic_functions/dft_processor_generic_impl.cpp b/lib/phy/generic_functions/dft_processor_generic_impl.cpp index 23ab07cec0..9f22564fba 100644 --- a/lib/phy/generic_functions/dft_processor_generic_impl.cpp +++ b/lib/phy/generic_functions/dft_processor_generic_impl.cpp @@ -1,3 +1,12 @@ +/* + * + * 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 "dft_processor_generic_impl.h" #include "../../srsvec/simd.h" diff --git a/lib/phy/generic_functions/dft_processor_generic_impl.h b/lib/phy/generic_functions/dft_processor_generic_impl.h index 3d7a9332af..c67a82012a 100644 --- a/lib/phy/generic_functions/dft_processor_generic_impl.h +++ b/lib/phy/generic_functions/dft_processor_generic_impl.h @@ -1,3 +1,12 @@ +/* + * + * 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 From af7e8c13f3df2b5c4c0a46572bb1b5622f9d90b1 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Thu, 20 Jun 2024 19:01:57 +0200 Subject: [PATCH 075/407] channel_coding: improve documentation --- .../phy/upper/channel_coding/crc_calculator.h | 1 + .../channel_coding/ldpc/ldpc_rate_dematcher.h | 2 + .../channel_coding/polar/polar_allocator.h | 10 +++ .../channel_coding/polar/polar_deallocator.h | 10 +++ .../channel_coding/polar/polar_encoder.h | 19 ++--- .../channel_coding/polar/polar_interleaver.h | 21 +++--- .../polar/polar_rate_dematcher.h | 4 +- .../channel_coding/polar/polar_rate_matcher.h | 19 +++-- .../channel_coding/ldpc/ldpc_decoder_impl.h | 2 +- .../ldpc/ldpc_rate_dematcher_neon_impl.h | 8 +++ .../polar/polar_allocator_impl.h | 7 +- .../polar/polar_deallocator_impl.h | 6 +- .../channel_coding/polar/polar_decoder_impl.h | 5 +- .../channel_coding/polar/polar_encoder_impl.h | 3 + .../polar/polar_interleaver_impl.h | 6 ++ .../polar/polar_rate_matcher_impl.h | 6 ++ .../channel_coding/polar/polar_chain_test.cpp | 72 +++++++++---------- .../short/short_block_detector_test.cpp | 2 +- 18 files changed, 126 insertions(+), 77 deletions(-) diff --git a/include/srsran/phy/upper/channel_coding/crc_calculator.h b/include/srsran/phy/upper/channel_coding/crc_calculator.h index 9207b3514d..7a7d0489ba 100644 --- a/include/srsran/phy/upper/channel_coding/crc_calculator.h +++ b/include/srsran/phy/upper/channel_coding/crc_calculator.h @@ -26,6 +26,7 @@ enum class crc_generator_poly { // etc... }; +/// Returns the CRC size from its identifier. inline constexpr unsigned get_crc_size(crc_generator_poly poly) { switch (poly) { diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher.h index 09ecb0ae64..61b0d7ad67 100644 --- a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher.h +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher.h @@ -35,6 +35,8 @@ class ldpc_rate_dematcher /// be determined from the input are set to zero. /// \param[in,out] output Full-length codeblock (log-likelihood ratios). /// \param[in] input Rate-matched codeblock (log-likelihood ratios). + /// \param[in] new_data Boolean flag that indicates whether the input corresponds to a new codeblock (if + /// true) or to a retransmission of an old one (if false). /// \param[in] cfg Configuration parameters. /// \remark The sizes of \c input and \c output determine the behavior of the rate recovering algorithm. virtual void rate_dematch(span output, diff --git a/include/srsran/phy/upper/channel_coding/polar/polar_allocator.h b/include/srsran/phy/upper/channel_coding/polar/polar_allocator.h index 1f71faffc1..d32947b7ca 100644 --- a/include/srsran/phy/upper/channel_coding/polar/polar_allocator.h +++ b/include/srsran/phy/upper/channel_coding/polar/polar_allocator.h @@ -8,17 +8,27 @@ * */ +/// \file +/// \brief Polar allocator interface. + #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_code.h" namespace srsran { +/// Polar allocator interface. class polar_allocator { public: + /// Default destructor. virtual ~polar_allocator() = default; + /// \brief Allocates the message bits into the encoder input. + /// + /// \param[out] input_encoder Sequence of allocated bits to be fed to the polar encoder. + /// \param[in] message Information bits to be allocated. + /// \param[in] code Polar code description. virtual void allocate(span input_encoder, span message, const polar_code& code) = 0; }; diff --git a/include/srsran/phy/upper/channel_coding/polar/polar_deallocator.h b/include/srsran/phy/upper/channel_coding/polar/polar_deallocator.h index 04080206fb..ecb7eef1ed 100644 --- a/include/srsran/phy/upper/channel_coding/polar/polar_deallocator.h +++ b/include/srsran/phy/upper/channel_coding/polar/polar_deallocator.h @@ -8,17 +8,27 @@ * */ +/// \file +/// \brief Polar deallocator - Interface. + #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_code.h" namespace srsran { +/// Polar deallocator interface. class polar_deallocator { public: + /// Default destructor. virtual ~polar_deallocator() = default; + /// \brief Extracts the information bits from the polar decoder output. + /// + /// \param[out] message Information bits. + /// \param[in] output_decoder Output bits of the polar decoder. + /// \param[in] code Polar code description. virtual void deallocate(span message, span output_decoder, const polar_code& code) = 0; }; diff --git a/include/srsran/phy/upper/channel_coding/polar/polar_encoder.h b/include/srsran/phy/upper/channel_coding/polar/polar_encoder.h index 0408cab522..79f48d94c5 100644 --- a/include/srsran/phy/upper/channel_coding/polar/polar_encoder.h +++ b/include/srsran/phy/upper/channel_coding/polar/polar_encoder.h @@ -8,6 +8,9 @@ * */ +/// \file +/// \brief Polar encoder interface. + #pragma once #include "srsran/adt/span.h" @@ -15,19 +18,19 @@ namespace srsran { +/// Polar encoder interface. class polar_encoder { public: + /// Default destructor. virtual ~polar_encoder() = default; - /*! - * Encodes the input vector into a codeword with the specified polar encoder. - * \param[in] input The encoder input vector. - * \param[in] code_size_log The \f$ log_2\f$ of the number of bits of the encoder input/output vector. - * It cannot be larger than the maximum code_size_log specified in q.code_size_log of - * the srsran_polar_encoder_t structure. - * \param[out] output The encoder output vector. - */ + /// \brief Encodes the input vector into a codeword with the specified polar encoder. + /// \param[out] output The encoder output vector. + /// \param[in] input The encoder input vector. + /// \param[in] code_size_log The \f$ log_2\f$ of the number of bits of the encoder input/output vector. + /// It cannot be larger than the maximum \c code_size_log specified in \c q.code_size_log of + /// the \c srsran_polar_encoder_t structure. virtual void encode(span output, span input, unsigned code_size_log) = 0; }; diff --git a/include/srsran/phy/upper/channel_coding/polar/polar_interleaver.h b/include/srsran/phy/upper/channel_coding/polar/polar_interleaver.h index e684329a66..1ed4f3c4c3 100644 --- a/include/srsran/phy/upper/channel_coding/polar/polar_interleaver.h +++ b/include/srsran/phy/upper/channel_coding/polar/polar_interleaver.h @@ -8,6 +8,9 @@ * */ +/// \file +/// \brief Polar interleaver interface. + #pragma once #include "srsran/adt/span.h" @@ -15,22 +18,22 @@ namespace srsran { +/// Identifiers for Tx and Rx interleavers. enum class polar_interleaver_direction { tx, rx }; +/// Polar interleaver interface. class polar_interleaver { public: virtual ~polar_interleaver() = default; - /** - * @brief Implements Polar code interleaver as described in TS 38.212 V15.9.0 Section 5.3.1.1 - * - * @attention The input and output data cannot be the same. - * - * @param[in] in bit Input data - * @param[out] out bit Output data - * @param[in] dir Set to TX or RX for encoder or decoder - */ + /// \brief Implements Polar code interleaver as described in TS 38.212 V15.9.0 Section 5.3.1.1 + /// + /// \attention The input and output data cannot be the same. + /// + /// \param[out] out Output data. + /// \param[in] in Input data. + /// \param[in] direction Set to TX or RX for encoder or decoder, respectively. virtual void interleave(span out, span in, polar_interleaver_direction direction) = 0; }; diff --git a/include/srsran/phy/upper/channel_coding/polar/polar_rate_dematcher.h b/include/srsran/phy/upper/channel_coding/polar/polar_rate_dematcher.h index ee1dda4a7c..d5fd4e895f 100644 --- a/include/srsran/phy/upper/channel_coding/polar/polar_rate_dematcher.h +++ b/include/srsran/phy/upper/channel_coding/polar/polar_rate_dematcher.h @@ -32,9 +32,7 @@ class polar_rate_dematcher /// operation. /// \param[in] input The LLRs obtained from the channel samples that correspond to /// the codeword to be, first, rate-dematched and, second, decoded. - /// \param[in] E Rate-matched codeword length. - /// \param[in] n \f$log_2\f$ of the codeword length. - /// \param[in] K Message size (including CRC). + /// \param[in] code Polar code description. virtual void rate_dematch(span output, span input, const polar_code& code) = 0; }; diff --git a/include/srsran/phy/upper/channel_coding/polar/polar_rate_matcher.h b/include/srsran/phy/upper/channel_coding/polar/polar_rate_matcher.h index e4fc69fb1a..9df0511bb0 100644 --- a/include/srsran/phy/upper/channel_coding/polar/polar_rate_matcher.h +++ b/include/srsran/phy/upper/channel_coding/polar/polar_rate_matcher.h @@ -8,6 +8,9 @@ * */ +/// \file +/// \brief Polar rate matcher interface. + #pragma once #include "srsran/adt/span.h" @@ -16,21 +19,17 @@ namespace srsran { +/// Polar rate matcher interface. class polar_rate_matcher { public: + /// Default destructor. virtual ~polar_rate_matcher() = default; - /*! - * Carries out the actual rate-matching. - * \param[in] input The codeword obtained from the polar encoder. - * \param[out] output The rate-matched codeword resulting from the rate-matching - * operation. - * \param[in] n \f$log_2\f$ of the codeword length. - * \param[in] E Rate-matched codeword length. - * \param[in] K Message size (including CRC). - * \return An integer: 0 if the function executes correctly, -1 otherwise. - */ + /// \brief Carries out the actual rate-matching. + /// \param[out] output The rate-matched codeword resulting from the rate-matching operation. + /// \param[in] input The codeword obtained from the polar encoder. + /// \param[in] code The polar code description. virtual void rate_match(span output, span input, const polar_code& code) = 0; }; diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h index 5f70b651ce..9511bdb1a9 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h @@ -158,7 +158,7 @@ class ldpc_decoder_impl : public ldpc_decoder /// \param[out] this_var_to_check Buffer to store the updated variable-to-check messages. /// \param[in] this_soft_bits Current soft bits. /// \param[in] this_check_to_var Current check-to-variable messages. - /// \remard An exception is raised if the size of the three spans is not the same. + /// \remark An exception is raised if the size of the three spans is not the same. virtual void compute_var_to_check_msgs(span this_var_to_check, span this_soft_bits, span this_check_to_var) = 0; diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher_neon_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher_neon_impl.h index 8641693243..84fc335182 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher_neon_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_rate_dematcher_neon_impl.h @@ -14,19 +14,27 @@ namespace srsran { +/// \brief LDPC Rate dematcher specialized with NEON instruction set. +/// +/// It implements \ref ldpc_rate_dematcher interface. It relies on NEON instruction sets. class ldpc_rate_dematcher_neon_impl : public ldpc_rate_dematcher_impl { protected: + // See interface for documentation. void combine_softbits(span out, span in0, span in1) const override; + // See interface for documentation. void deinterleave_qpsk(span out, span in) const override; + // See interface for documentation. void deinterleave_qam16(span out, span in) const override; + // See interface for documentation. void deinterleave_qam64(span out, span in) const override; + // See interface for documentation. void deinterleave_qam256(span out, span in) const override; }; diff --git a/lib/phy/upper/channel_coding/polar/polar_allocator_impl.h b/lib/phy/upper/channel_coding/polar/polar_allocator_impl.h index 6ad670fc8c..32aaef8e21 100644 --- a/lib/phy/upper/channel_coding/polar/polar_allocator_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_allocator_impl.h @@ -8,17 +8,20 @@ * */ +/// \file +/// \brief Polar allocator - Declaration of implementation class. + #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_allocator.h" namespace srsran { +/// Polar allocator implementation. class polar_allocator_impl : public polar_allocator { public: - polar_allocator_impl() = default; - ~polar_allocator_impl() = default; + // See interface for the documentation. void allocate(span input_encoder, span message, const polar_code& code) override; }; diff --git a/lib/phy/upper/channel_coding/polar/polar_deallocator_impl.h b/lib/phy/upper/channel_coding/polar/polar_deallocator_impl.h index 6eb8371e7f..f62805d1be 100644 --- a/lib/phy/upper/channel_coding/polar/polar_deallocator_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_deallocator_impl.h @@ -8,17 +8,19 @@ * */ +/// \file +/// \brief Polar deallocator implementation - Declaration. #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_deallocator.h" namespace srsran { +/// Polar deallocator implementation. class polar_deallocator_impl : public polar_deallocator { public: - polar_deallocator_impl() = default; - ~polar_deallocator_impl() = default; + // See interface for the documentation. void deallocate(span message, span output_decoder, const polar_code& code) override; }; diff --git a/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h b/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h index e2977a650b..1b1f5454e0 100644 --- a/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h @@ -142,9 +142,8 @@ class polar_decoder_impl : public polar_decoder /// Initializes all the polar decoder variables according to the Simplified Successive /// Cancellation (SSC) decoder algorithm and the maximum given code size. /// - /// \param[in] enc A polar encoder. - /// \param[in] code_size_log The \f$ log_2\f$ of the number of bits of the decoder input/output vector. - /// \return A unique pointer to the initialized SSC polar decoder. + /// \param[in] enc_ A polar encoder. + /// \param[in] nMax \f$log_2\f$ of the maximum number of bits in the codeword. polar_decoder_impl(std::unique_ptr enc_, uint8_t nMax); // See interface for the documentation. diff --git a/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h b/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h index 7dcab0d215..de61663341 100644 --- a/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h @@ -8,6 +8,8 @@ * */ +/// \file +/// \brief Polar encoder - Declaration of implementation class. #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_encoder.h" @@ -15,6 +17,7 @@ namespace srsran { +/// Polar encoder implementation. class polar_encoder_impl : public polar_encoder { public: diff --git a/lib/phy/upper/channel_coding/polar/polar_interleaver_impl.h b/lib/phy/upper/channel_coding/polar/polar_interleaver_impl.h index e44a5e7a4a..3679822112 100644 --- a/lib/phy/upper/channel_coding/polar/polar_interleaver_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_interleaver_impl.h @@ -8,11 +8,16 @@ * */ +/// \file +/// \brief Polar interleaver - Declaration of implementation class. + #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_interleaver.h" namespace srsran { + +/// Polar interleaver implementation. class polar_interleaver_impl : public polar_interleaver { private: @@ -21,6 +26,7 @@ class polar_interleaver_impl : public polar_interleaver public: ~polar_interleaver_impl() override = default; + // See interface for the documentation. void interleave(span out, span in, polar_interleaver_direction direction) override; }; } // namespace srsran diff --git a/lib/phy/upper/channel_coding/polar/polar_rate_matcher_impl.h b/lib/phy/upper/channel_coding/polar/polar_rate_matcher_impl.h index 1d0b0a1c7b..abe75c12dc 100644 --- a/lib/phy/upper/channel_coding/polar/polar_rate_matcher_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_rate_matcher_impl.h @@ -8,12 +8,17 @@ * */ +/// \file +/// \brief Polar rate-matcher - Declaration of implementation class. + #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_code.h" #include "srsran/phy/upper/channel_coding/polar/polar_rate_matcher.h" namespace srsran { + +/// Polar rate-matcher implementation. class polar_rate_matcher_impl : public polar_rate_matcher { private: @@ -23,6 +28,7 @@ class polar_rate_matcher_impl : public polar_rate_matcher polar_rate_matcher_impl() = default; ~polar_rate_matcher_impl() override = default; + // See interface for the documentation. void rate_match(span output, span input, const polar_code& code) override; }; } // namespace srsran diff --git a/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp b/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp index 4c5c7c8b04..749e9df4a2 100644 --- a/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp +++ b/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp @@ -16,44 +16,40 @@ using namespace srsran; -/*! - * \file polar_chain_test.c - * \brief Ent-to-end test for the Polar coding chain including: subchannel allocator, encoder, rate-matcher, - rate-dematcher, decoder and subchannel deallocation. - * - * A batch of example messages is randomly generated, frozen bits are added, encoded, rate-matched, 2-PAM modulated, - * sent over an AWGN channel, rate-dematched, and, finally, decoded by all three types of - * decoder. Transmitted and received messages are compared to estimate the WER. - * Multiple batches are simulated if the number of errors is not significant - * enough. - * - * Synopsis: **polar_chain_test [options]** - * - * Options: - * - * - -n \ nMax, [Default 9] -- Use 9 for downlink, and 10 for uplink configuration. - * - -k \ Message size (K), [Default 128]. K includes the CRC bits if applicable. - * If nMax = 9, K must satisfy 165 > K > 35. If nMax = 10, K must satisfy K > 17 and K <1024, excluding 31 > K > 25. - * - -e \ Rate matching size (E), [Default 256]. If 17 < K < 26, E must satisfy K +3 < E < 8193. - * If K > 30, E must satisfy K < E < 8193. - * - -i \ Enable bit interleaver (bil), [Default 0] -- Set bil = 0 to disable the - * bit interleaver at rate matching. Choose 0 for downlink and 1 for uplink configuration. - * - -s \ SNR [dB, Default 3.00 dB] -- Use 100 for scan, and 101 for noiseless. - * - -o \ Print output results [Default 0] -- Use 0 for detailed, Use 1 for 1 line, Use 2 for vector - * form. - * - * Example 1: BCH - ./polar_chain_test -n9 -k56 -e864 -i0 -s101 -o1 - * - * Example 2: DCI - ./polar_chain_test -n9 -k40 -e100 -i0 -s101 -o1 - * - * Example 3: UCI - PC bits - ./polar_chain_test -n10 -k20 -e256 -i1 -s101 -o1 - * - * Example 4: UCI - puncturing 19 first bits - ./polar_chain_test -n10 -k18 -e45 -i1 -s101 -o1 - * - * Example 5: UCI - shortening 26 last bits - ./polar_chain_test -n10 -k18 -e38 -i1 -s101 -o1 - * - * - */ +/// \file +/// \brief Ent-to-end test for the Polar coding chain including: subchannel allocator, encoder, rate-matcher, +/// rate-dematcher, decoder and subchannel deallocation. +/// +/// A batch of example messages is randomly generated, frozen bits are added, encoded, rate-matched, 2-PAM modulated, +/// sent over an AWGN channel, rate-dematched, and, finally, decoded by all three types of +/// decoder. Transmitted and received messages are compared to estimate the WER. +/// Multiple batches are simulated if the number of errors is not significant +/// enough. +/// +/// Synopsis: **polar_chain_test [options]** +/// +/// Options: +/// +/// - -n \ nMax, [Default 9] -- Use 9 for downlink, and 10 for uplink configuration. +/// - -k \ Message size (K), [Default 128]. K includes the CRC bits if applicable. +/// If nMax = 9, K must satisfy 165 > K > 35. If nMax = 10, K must satisfy K > 17 and K <1024, excluding 31 > K > 25. +/// - -e \ Rate matching size (E), [Default 256]. If 17 < K < 26, E must satisfy K +3 < E < 8193. +/// If K > 30, E must satisfy K < E < 8193. +/// - -i \ Enable bit interleaver (bil), [Default 0] -- Set bil = 0 to disable the +/// bit interleaver at rate matching. Choose 0 for downlink and 1 for uplink configuration. +/// - -s \ SNR [dB, Default 3.00 dB] -- Use 100 for scan, and 101 for noiseless. +/// - -o \ Print output results [Default 0] -- Use 0 for detailed, Use 1 for 1 line, Use 2 for vector +/// form. +/// +/// Example 1: BCH - ./polar_chain_test -n9 -k56 -e864 -i0 -s101 -o1 +/// +/// Example 2: DCI - ./polar_chain_test -n9 -k40 -e100 -i0 -s101 -o1 +/// +/// Example 3: UCI - PC bits - ./polar_chain_test -n10 -k20 -e256 -i1 -s101 -o1 +/// +/// Example 4: UCI - puncturing 19 first bits - ./polar_chain_test -n10 -k18 -e45 -i1 -s101 -o1 +/// +/// Example 5: UCI - shortening 26 last bits - ./polar_chain_test -n10 -k18 -e38 -i1 -s101 -o1 // default values static uint16_t K = 56; /*!< \brief Number of message bits (data and CRC). */ diff --git a/tests/unittests/phy/upper/channel_coding/short/short_block_detector_test.cpp b/tests/unittests/phy/upper/channel_coding/short/short_block_detector_test.cpp index 2bddc2d7f7..b689d6a9a7 100644 --- a/tests/unittests/phy/upper/channel_coding/short/short_block_detector_test.cpp +++ b/tests/unittests/phy/upper/channel_coding/short/short_block_detector_test.cpp @@ -118,4 +118,4 @@ INSTANTIATE_TEST_SUITE_P(ShortBlockDetectorTest, } // end namespace -/// \encond \ No newline at end of file +/// \endcond From 49c6814dc6d5815efc1597ce4ff06b3921a2d93f Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Fri, 5 Jul 2024 17:00:08 +0200 Subject: [PATCH 076/407] generic_functions: improve documentation --- lib/phy/generic_functions/dft_processor_generic_impl.h | 3 ++- lib/phy/generic_functions/precoding/channel_precoder_impl.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/phy/generic_functions/dft_processor_generic_impl.h b/lib/phy/generic_functions/dft_processor_generic_impl.h index c67a82012a..5568247439 100644 --- a/lib/phy/generic_functions/dft_processor_generic_impl.h +++ b/lib/phy/generic_functions/dft_processor_generic_impl.h @@ -19,7 +19,8 @@ namespace srsran { class generic_dft_N { public: - virtual ~generic_dft_N() = default; + virtual ~generic_dft_N() = default; + /// Computes the N-point of \c in and writes the result in \c out. virtual void run(cf_t* out, const cf_t* in) const = 0; }; diff --git a/lib/phy/generic_functions/precoding/channel_precoder_impl.h b/lib/phy/generic_functions/precoding/channel_precoder_impl.h index d7b1f5b13c..8e53e1e9d2 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_impl.h +++ b/lib/phy/generic_functions/precoding/channel_precoder_impl.h @@ -32,9 +32,9 @@ class channel_precoder_impl : public channel_precoder protected: /// \brief Applies precoding to the RE belonging to a single antenna port. /// - /// \param[out] port_re View over the RE of a single antenna port. - /// \param[in] input Input symbols, indexed by RE and transmit layer. - /// \param[in] precoding Precoding coefficients, indexed by layer. + /// \param[out] port_re View over the RE of a single antenna port. + /// \param[in] input_re Input symbols, indexed by RE and transmit layer. + /// \param[in] port_weights Layer weights for the current port. virtual void apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const = 0; From b3bb67602ff447ed0f5b72d59d0835ab77e2909a Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 9 Jul 2024 18:40:09 +0200 Subject: [PATCH 077/407] channel_processors: improve documentation --- .../upper/channel_processors/pbch_encoder.h | 2 +- .../upper/channel_processors/pbch_modulator.h | 2 +- .../upper/channel_processors/prach_detector.h | 2 +- .../channel_processors/pucch_processor.h | 20 +++++++++---------- .../channel_processors/pusch/pusch_decoder.h | 2 +- .../channel_processors/uci/uci_decoder.h | 1 + .../channel_processors/pbch_encoder_impl.h | 1 + .../channel_processors/pbch_modulator_impl.h | 1 + .../channel_processors/pdcch_modulator_impl.h | 1 + .../pdsch_encoder_hw_impl.h | 5 ++--- .../pdsch_processor_concurrent_impl.h | 9 ++++----- .../channel_processors/pdsch_processor_impl.h | 1 - .../pdsch_processor_lite_impl.h | 2 +- .../prach_detector_generic_impl.h | 4 ++-- .../prach_detector_generic_thresholds.h | 13 +++++++++--- .../channel_processors/prach_generator_impl.h | 6 ------ .../pusch/pusch_decoder_empty_impl.h | 4 ++-- .../pusch/pusch_decoder_hw_impl.h | 9 +++++---- .../pusch/pusch_decoder_impl.h | 4 ++-- .../pusch/ulsch_demultiplex_impl.h | 1 + .../channel_processors/ssb_processor_impl.h | 1 + 21 files changed, 48 insertions(+), 43 deletions(-) diff --git a/include/srsran/phy/upper/channel_processors/pbch_encoder.h b/include/srsran/phy/upper/channel_processors/pbch_encoder.h index de2b3fc844..3d0b3b1ca0 100644 --- a/include/srsran/phy/upper/channel_processors/pbch_encoder.h +++ b/include/srsran/phy/upper/channel_processors/pbch_encoder.h @@ -18,7 +18,7 @@ namespace srsran { -/// Describes the PBCH encoder interface +/// PBCH encoder interface. class pbch_encoder { public: diff --git a/include/srsran/phy/upper/channel_processors/pbch_modulator.h b/include/srsran/phy/upper/channel_processors/pbch_modulator.h index 3788402bd6..43aac04535 100644 --- a/include/srsran/phy/upper/channel_processors/pbch_modulator.h +++ b/include/srsran/phy/upper/channel_processors/pbch_modulator.h @@ -20,7 +20,7 @@ namespace srsran { class resource_grid_writer; -/// Describes a PBCH modulator interface +/// PBCH modulator interface. class pbch_modulator { public: diff --git a/include/srsran/phy/upper/channel_processors/prach_detector.h b/include/srsran/phy/upper/channel_processors/prach_detector.h index 9a5c529d1c..cc8bcaabc4 100644 --- a/include/srsran/phy/upper/channel_processors/prach_detector.h +++ b/include/srsran/phy/upper/channel_processors/prach_detector.h @@ -59,7 +59,7 @@ class prach_detector /// /// An assertion is triggered if the sum of start preamble index and number of preambles exceeds 64. /// - /// \param[in] signal Baseband signal buffer. + /// \param[in] input Baseband signal buffer. /// \param[in] config PRACH configuration for the slot. /// \return The detection result. virtual prach_detection_result detect(const prach_buffer& input, const configuration& config) = 0; diff --git a/include/srsran/phy/upper/channel_processors/pucch_processor.h b/include/srsran/phy/upper/channel_processors/pucch_processor.h index 71aa0ed2c0..da5ff61318 100644 --- a/include/srsran/phy/upper/channel_processors/pucch_processor.h +++ b/include/srsran/phy/upper/channel_processors/pucch_processor.h @@ -194,32 +194,32 @@ class pucch_processor virtual ~pucch_processor() = default; /// \brief Processes a PUCCH Format 0 message. - /// \param[out] grid Resource grid. - /// \param[in] config PUCCH Format 0 configuration. + /// \param[in] grid Resource grid. + /// \param[in] config PUCCH Format 0 configuration. /// \return The PUCCH process result. virtual pucch_processor_result process(const resource_grid_reader& grid, const format0_configuration& config) = 0; /// \brief Processes a PUCCH Format 1 message. - /// \param[out] grid Resource grid. - /// \param[in] config PUCCH Format 1 configuration. + /// \param[in] grid Resource grid. + /// \param[in] config PUCCH Format 1 configuration. /// \return The PUCCH process result. virtual pucch_processor_result process(const resource_grid_reader& grid, const format1_configuration& config) = 0; /// \brief Processes a PUCCH Format 2 message. - /// \param[out] grid Resource grid. - /// \param[in] config PUCCH Format 2 configuration. + /// \param[in] grid Resource grid. + /// \param[in] config PUCCH Format 2 configuration. /// \return The PUCCH process result. virtual pucch_processor_result process(const resource_grid_reader& grid, const format2_configuration& config) = 0; /// \brief Processes a PUCCH Format 3 message. - /// \param[out] grid Resource grid. - /// \param[in] config PUCCH Format 3 configuration. + /// \param[in] grid Resource grid. + /// \param[in] config PUCCH Format 3 configuration. /// \return The PUCCH process result. virtual pucch_processor_result process(const resource_grid_reader& grid, const format3_configuration& config) = 0; /// \brief Processes a PUCCH Format 4 message. - /// \param[out] indication PUCCH process result. - /// \param[in] config PUCCH Format 4 configuration. + /// \param[in] grid Resource grid. + /// \param[in] config PUCCH Format 4 configuration. /// \return The PUCCH process result. virtual pucch_processor_result process(const resource_grid_reader& grid, const format4_configuration& config) = 0; }; diff --git a/include/srsran/phy/upper/channel_processors/pusch/pusch_decoder.h b/include/srsran/phy/upper/channel_processors/pusch/pusch_decoder.h index f0f6cf3f22..461e33b4a9 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/pusch_decoder.h +++ b/include/srsran/phy/upper/channel_processors/pusch/pusch_decoder.h @@ -38,7 +38,7 @@ struct pusch_decoder_result; /// which is used to write softbits into the decoder. /// /// The decoder could potentially start the code block processing if a codeword length is provided (see -/// \ref set_codeword_length) prior \ref pusch_decoder_buffer::on_end_softbits. +/// \ref set_nof_softbits) prior \ref pusch_decoder_buffer::on_end_softbits. class pusch_decoder { public: diff --git a/include/srsran/phy/upper/channel_processors/uci/uci_decoder.h b/include/srsran/phy/upper/channel_processors/uci/uci_decoder.h index 69af741023..bc0a6f00a8 100644 --- a/include/srsran/phy/upper/channel_processors/uci/uci_decoder.h +++ b/include/srsran/phy/upper/channel_processors/uci/uci_decoder.h @@ -41,6 +41,7 @@ class uci_decoder /// \brief Decodes Uplink Control Information carried in either PUCCH or PUSCH. /// \param[out] message View of the decoded message. /// \param[in] llr The received soft bits, as a sequence of log-likelihood ratios. + /// \param[in] config The UCI decoder configuration. /// \return The decoding status. virtual uci_status decode(span message, span llr, const configuration& config) = 0; diff --git a/lib/phy/upper/channel_processors/pbch_encoder_impl.h b/lib/phy/upper/channel_processors/pbch_encoder_impl.h index 4296429ed3..ae0d0f17ee 100644 --- a/lib/phy/upper/channel_processors/pbch_encoder_impl.h +++ b/lib/phy/upper/channel_processors/pbch_encoder_impl.h @@ -22,6 +22,7 @@ namespace srsran { +/// PBCH encoder implementation. class pbch_encoder_impl : public pbch_encoder { private: diff --git a/lib/phy/upper/channel_processors/pbch_modulator_impl.h b/lib/phy/upper/channel_processors/pbch_modulator_impl.h index a7faa424ec..019349c806 100644 --- a/lib/phy/upper/channel_processors/pbch_modulator_impl.h +++ b/lib/phy/upper/channel_processors/pbch_modulator_impl.h @@ -16,6 +16,7 @@ namespace srsran { +/// PBCH modulator implementation. class pbch_modulator_impl : public pbch_modulator { private: diff --git a/lib/phy/upper/channel_processors/pdcch_modulator_impl.h b/lib/phy/upper/channel_processors/pdcch_modulator_impl.h index 47f9de802b..89f5d7d9a5 100644 --- a/lib/phy/upper/channel_processors/pdcch_modulator_impl.h +++ b/lib/phy/upper/channel_processors/pdcch_modulator_impl.h @@ -19,6 +19,7 @@ namespace srsran { class resource_grid_mapper; +/// PDCCH modulator implementation. class pdcch_modulator_impl : public pdcch_modulator { private: diff --git a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h index b5232381cd..81ffc29516 100644 --- a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.h @@ -42,10 +42,9 @@ class pdsch_encoder_hw_impl : public pdsch_encoder /// /// Sets up the internal components, namely LDPC segmenter, all the CRC calculators and the hardware accelerator. /// + /// \param[in] c Structure with pointers to three CRC calculator objects, with generator polynomials of type + /// \c CRC16, \c CRC24A and \c CRC24B. /// \param[in] seg Unique pointer to an LDPC segmenter. - /// \param[in] crcs Structure with pointers to three CRC calculator objects, with generator polynomials of type - /// \c - /// CRC16, \c CRC24A and \c CRC24B. /// \param[in] hw Unique pointer to a hardware-accelerator. pdsch_encoder_hw_impl(sch_crc& c, std::unique_ptr seg, diff --git a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h index 004aab7ed7..4ededdca58 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.h @@ -31,11 +31,10 @@ class pdsch_processor_concurrent_impl : public pdsch_processor using pdsch_dmrs_generator_pool = concurrent_thread_local_object_pool; /// \brief Creates a concurrent PDSCH processor with all the dependencies. - /// \param[in] segmenter_ LDPC transmitter segmenter. - /// \param[in] cb_processor_pool_ Codeblock processor pool. - /// \param[in] scrambler_ Scrambling pseudo-random generator. - /// \param[in] dmrs_ DM-RS for PDSCH generator. - /// \param[in] executor_ Asynchronous task executor. + /// \param[in] cb_processor_pool_ Codeblock processor pool. + /// \param[in] scrambler_ Scrambling pseudo-random generator. + /// \param[in] dmrs_generator_pool_ DM-RS for PDSCH generator. + /// \param[in] executor_ Asynchronous task executor. pdsch_processor_concurrent_impl(std::shared_ptr cb_processor_pool_, std::unique_ptr scrambler_, std::shared_ptr dmrs_generator_pool_, diff --git a/lib/phy/upper/channel_processors/pdsch_processor_impl.h b/lib/phy/upper/channel_processors/pdsch_processor_impl.h index 2c16ff663b..2b5e5351dd 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_processor_impl.h @@ -22,7 +22,6 @@ class pdsch_processor_impl : public pdsch_processor { public: /// \brief Creates a generic PDSCH processor. - /// \param[in] config Provides the necessary configuration. pdsch_processor_impl(std::unique_ptr encoder_, std::unique_ptr modulator_, std::unique_ptr dmrs_) : diff --git a/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h b/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h index 7535dd46d6..d75fa5e66f 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h +++ b/lib/phy/upper/channel_processors/pdsch_processor_lite_impl.h @@ -81,7 +81,7 @@ class pdsch_block_processor : public resource_grid_mapper::symbol_buffer /// Current view of the codeblock modulated symbols. span codeblock_symbols; - /// Processes a new codeblock and writes the new data in \ref encoded_bit_buffer. + /// Processes a new codeblock and writes the new data in \ref temp_codeblock_symbols. void new_codeblock(); }; diff --git a/lib/phy/upper/channel_processors/prach_detector_generic_impl.h b/lib/phy/upper/channel_processors/prach_detector_generic_impl.h index 6b96eb7cb7..b35414c2fb 100644 --- a/lib/phy/upper/channel_processors/prach_detector_generic_impl.h +++ b/lib/phy/upper/channel_processors/prach_detector_generic_impl.h @@ -17,7 +17,7 @@ namespace srsran { -/// Implements a parameter validator for \ref prach_detector_simple_impl. +/// Implements a parameter validator for the PRACH detector. class prach_detector_validator_impl : public prach_detector_validator { public: @@ -38,7 +38,7 @@ class prach_detector_generic_impl : public prach_detector /// \param[in] generator_ PRACH frequency-domain sequence generator. /// \param[in] combine_symbols_ Set to true for combining PRACH symbols for each port. /// \remark Assertions are triggered if the IDFT sizes are smaller than their sequences or greater than \ref - /// MAX_DFT_SIZE. + /// MAX_IDFT_SIZE. prach_detector_generic_impl(std::unique_ptr idft_long_, std::unique_ptr idft_short_, std::unique_ptr generator_, diff --git a/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h b/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h index a69dca9b14..d1d9b4765d 100644 --- a/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h +++ b/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h @@ -121,10 +121,14 @@ class threshold_and_margin_finder using threshold_and_margin_type = std::pair; + /// Mapping between PRACH configuration and threshold value. struct threshold_entry { - threshold_params configuration; + /// Subset of PRACH configuration parameters affecting the threshold value. + threshold_params configuration; + /// Threshold value and search margin. threshold_and_margin_type threshold_and_margin; - threshold_flag flag; + /// Threshold quality flag. + threshold_flag flag; }; /// Constructor: receives the list of pairings and ensures it is sorted. @@ -156,6 +160,7 @@ class threshold_and_margin_finder return {/* threshold */ 0.3F, /* margin */ 12}; } + /// Checks the quality flag of the threshold for the given configurations. threshold_flag check_flag(const threshold_params& params) const { auto it = @@ -171,10 +176,12 @@ class threshold_and_margin_finder } private: + /// Sorted list of thresholds. std::vector sorted_thresholds_and_margins; }; -using th_flag = threshold_and_margin_finder::threshold_flag; +using th_flag = threshold_and_margin_finder::threshold_flag; +/// Unsorted list of thresholds. static const auto all_threshold_and_margins = to_array({ // clang-format off {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.147F, 5}, th_flag::orange}, diff --git a/lib/phy/upper/channel_processors/prach_generator_impl.h b/lib/phy/upper/channel_processors/prach_generator_impl.h index e7c8fadb30..b7904e3ffb 100644 --- a/lib/phy/upper/channel_processors/prach_generator_impl.h +++ b/lib/phy/upper/channel_processors/prach_generator_impl.h @@ -54,12 +54,6 @@ class prach_generator_impl : public prach_generator span generate_y_u_v_short(unsigned u, unsigned C_v); public: - /// \brief Constructor - Acquires ownership of the internal components. - /// - /// The PRACH generator depends on the DFT to generate the frequency-domain signals. - /// - /// \param dft_long_ DFT processor for generating long sequences. - /// \param dft_short_ DFT processor for generating short sequences. prach_generator_impl() : sequence(LONG) { // Do nothing. diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.h index dae6faddea..99a4052942 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.h @@ -59,7 +59,7 @@ class pusch_decoder_empty_impl : public pusch_decoder const configuration& cfg); // See interface for documentation. - span get_next_block_view(unsigned int block_size) override; + span get_next_block_view(unsigned block_size) override; // See interface for documentation. void on_new_softbits(span softbits) override; @@ -89,4 +89,4 @@ class pusch_decoder_empty_impl : public pusch_decoder decoder_buffer_impl decoder_buffer; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h index 24e4458139..d4b2c7eea9 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h @@ -28,10 +28,12 @@ namespace srsran { -// Maximum accepted transport block size. +/// Maximum accepted transport block size. static constexpr unsigned MAX_TBS = 1277992; -// Number of bits in the long CRC. A CRC of this length is used either for TB CRCs, when the TB is longer than +/// \brief Number of bits in the long CRC. +/// +/// A CRC of this length is used either for TB CRCs, when the TB is longer than // MAX_BITS_CRC16, or as a codeblock CRC, when the TB consists of multiple codeblocks. static constexpr unsigned LONG_CRC_LENGTH = 24; @@ -150,7 +152,7 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer /// /// \param[in,out] cb_crcs Set of CRC flags. /// \param[in,out] decoder Hardware decoder used to process the codeblocks. - /// \param[in] cb_index Index of the CB (within the TB). + /// \param[in] cb_id Index of the CB (within the TB). /// \param[in] crc_type Type of the CB CRC. /// \param[in] data Decoded data. /// \return Results of the decoding operation (CRC and number of LDPC decoder iterations). @@ -167,7 +169,6 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer /// \brief Sets the segmentation and decoding parameters required by the hardware-accelerated PUSCH decoder function. /// \param[in,out] decoder Selected hardware decoder to configure. - /// \param[in] cfg PUSCH configuration parameters. /// \param[in] nof_segments Number of segments in the transport block. /// \param[in] rm_length Length of the rate-matched codeblock in bits. /// \param[in] lifting_size Length of the circular buffer in bits, as described in TS38.212 Section 5.4.2.1. diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_decoder_impl.h index aed5f84010..42e033131c 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_impl.h @@ -22,10 +22,10 @@ namespace srsran { -// Number of bits in one byte. +/// Number of bits in one byte. static constexpr unsigned BITS_PER_BYTE = 8; -// Maximum TBS that implies a 16-bit CRC. +/// Maximum TBS that implies a 16-bit CRC. constexpr unsigned MAX_BITS_CRC16 = 3824; /// Implementation of the PUSCH decoder. diff --git a/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h b/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h index 3c5e3a0e8d..c19dd554a8 100644 --- a/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h +++ b/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h @@ -16,6 +16,7 @@ namespace srsran { +/// Uplink Shared Channel demultiplexer implementation. class ulsch_demultiplex_impl : public ulsch_demultiplex, private pusch_codeword_buffer { public: diff --git a/lib/phy/upper/channel_processors/ssb_processor_impl.h b/lib/phy/upper/channel_processors/ssb_processor_impl.h index 22a9d86079..3225590242 100644 --- a/lib/phy/upper/channel_processors/ssb_processor_impl.h +++ b/lib/phy/upper/channel_processors/ssb_processor_impl.h @@ -35,6 +35,7 @@ class ssb_processor_validator_impl : public ssb_pdu_validator bool is_valid(const ssb_processor::pdu_t& pdu) const override { return true; } }; +/// SSB processor implementation. class ssb_processor_impl : public ssb_processor { private: From d751f033201a7983675d562457a9383fcd59c52f Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 15 Jul 2024 13:14:35 +0200 Subject: [PATCH 078/407] ran: improve documentation --- lib/ran/ssb_freq_position_generator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ran/ssb_freq_position_generator.h b/lib/ran/ssb_freq_position_generator.h index cb1c85c714..bf0d515945 100644 --- a/lib/ran/ssb_freq_position_generator.h +++ b/lib/ran/ssb_freq_position_generator.h @@ -23,7 +23,7 @@ const unsigned NOF_SSB_SUBCARRIERS = NOF_SSB_PRBS * NOF_SUBCARRIERS_PER_RB; struct ssb_freq_location { /// Tells whether the set of parameters represent a valid configuration. bool is_valid; - /// offsetToPointA<\em>, as per Section 4.4.4.2, TS 38.211. + /// \em offsetToPointA, as per Section 4.4.4.2, TS 38.211. ssb_offset_to_pointA offset_to_point_A; /// \f$k_{SSB}\f$, as per Section 7.4.3.1, TS 38.211. ssb_subcarrier_offset k_ssb; From ce6b93667ef78d355ae1db97fb147ab976bdc616 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 29 Jul 2024 19:30:32 +0200 Subject: [PATCH 079/407] radio: improve documentation --- include/srsran/radio/radio_factory.h | 6 +++--- lib/radio/zmq/radio_zmq_rx_channel.h | 1 + lib/radio/zmq/radio_zmq_rx_channel_fsm.h | 1 + lib/radio/zmq/radio_zmq_timer.h | 3 ++- lib/radio/zmq/radio_zmq_tx_channel.h | 1 + lib/radio/zmq/radio_zmq_tx_channel_fsm.h | 1 + 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/srsran/radio/radio_factory.h b/include/srsran/radio/radio_factory.h index ccd2ef49fb..0b3e167391 100644 --- a/include/srsran/radio/radio_factory.h +++ b/include/srsran/radio/radio_factory.h @@ -25,9 +25,9 @@ class radio_factory : public radio_base virtual const radio_configuration::validator& get_configuration_validator() = 0; /// \brief Creates a new radio session with the given configuration parameters. - /// \param[in] config Provides the configuration parameters. - /// \param[in] task_executor Provides a task executor for executing asynchronous tasks. - /// \param[in] notifier Provides radio event notifier interface. + /// \param[in] config Provides the configuration parameters. + /// \param[in] async_task_executor Provides a task executor for executing asynchronous tasks. + /// \param[in] notifier Provides radio event notifier interface. /// \return The ownership to a radio session if the session was successfully created. virtual std::unique_ptr create(const radio_configuration::radio& config, task_executor& async_task_executor, diff --git a/lib/radio/zmq/radio_zmq_rx_channel.h b/lib/radio/zmq/radio_zmq_rx_channel.h index a051436518..24aefb30ff 100644 --- a/lib/radio/zmq/radio_zmq_rx_channel.h +++ b/lib/radio/zmq/radio_zmq_rx_channel.h @@ -23,6 +23,7 @@ namespace srsran { +/// Radio receive channel over ZeroMQ socket. class radio_zmq_rx_channel { private: diff --git a/lib/radio/zmq/radio_zmq_rx_channel_fsm.h b/lib/radio/zmq/radio_zmq_rx_channel_fsm.h index 728a644618..59f034e9ef 100644 --- a/lib/radio/zmq/radio_zmq_rx_channel_fsm.h +++ b/lib/radio/zmq/radio_zmq_rx_channel_fsm.h @@ -15,6 +15,7 @@ #include namespace srsran { +/// Finite state machine for the ZeroMQ-based radio receive channel. class radio_zmq_rx_channel_fsm { private: diff --git a/lib/radio/zmq/radio_zmq_timer.h b/lib/radio/zmq/radio_zmq_timer.h index 031eff7fc6..0544aea2e6 100644 --- a/lib/radio/zmq/radio_zmq_timer.h +++ b/lib/radio/zmq/radio_zmq_timer.h @@ -13,6 +13,7 @@ namespace srsran { +/// Timer for the ZeroMQ-based radio channel. class radio_zmq_timer { public: @@ -61,4 +62,4 @@ class radio_zmq_timer std::chrono::time_point wait_expire_time = no_time; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/radio/zmq/radio_zmq_tx_channel.h b/lib/radio/zmq/radio_zmq_tx_channel.h index 62bc8aa85f..7675bfa64e 100644 --- a/lib/radio/zmq/radio_zmq_tx_channel.h +++ b/lib/radio/zmq/radio_zmq_tx_channel.h @@ -23,6 +23,7 @@ namespace srsran { +/// Radio transmit channel over ZeroMQ socket. class radio_zmq_tx_channel { private: diff --git a/lib/radio/zmq/radio_zmq_tx_channel_fsm.h b/lib/radio/zmq/radio_zmq_tx_channel_fsm.h index 0ad6f69fe8..16af9f1c2f 100644 --- a/lib/radio/zmq/radio_zmq_tx_channel_fsm.h +++ b/lib/radio/zmq/radio_zmq_tx_channel_fsm.h @@ -16,6 +16,7 @@ #include namespace srsran { +/// Finite state machine for the ZeroMQ-based radio transmit channel. class radio_zmq_tx_channel_fsm { private: From 7d824d75df399aab8193b1541b90df6e967d9f76 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 29 Jul 2024 19:41:23 +0200 Subject: [PATCH 080/407] equalization: improve documentation --- lib/phy/upper/equalization/equalize_zf_1xn.h | 4 ++-- lib/phy/upper/equalization/equalize_zf_2xn.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/phy/upper/equalization/equalize_zf_1xn.h b/lib/phy/upper/equalization/equalize_zf_1xn.h index d6f96d4be2..cbb798e3c7 100644 --- a/lib/phy/upper/equalization/equalize_zf_1xn.h +++ b/lib/phy/upper/equalization/equalize_zf_1xn.h @@ -22,8 +22,8 @@ namespace srsran { /// \brief Implementation of a Zero Forcing equalizer for a SIMO 1 X \c RX_PORTS channel. /// \tparam RX_PORTS Number of receive antenna ports. -/// \param[out] eq_symbols Resultant equalized symbols. -/// \param[out] noise_vars Noise variances after equalization. +/// \param[out] symbols_out Resultant equalized symbols. +/// \param[out] nvars_out Noise variances after equalization. /// \param[in] ch_symbols Channel symbols, i.e., complex samples from the receive ports. /// \param[in] ch_estimates Channel estimation coefficients. /// \param[in] noise_var_est Estimated noise variance for each port. diff --git a/lib/phy/upper/equalization/equalize_zf_2xn.h b/lib/phy/upper/equalization/equalize_zf_2xn.h index adea17b4d2..cb6875292e 100644 --- a/lib/phy/upper/equalization/equalize_zf_2xn.h +++ b/lib/phy/upper/equalization/equalize_zf_2xn.h @@ -25,7 +25,7 @@ namespace srsran { /// \param[out] eq_symbols Equalized channel symbols. /// \param[out] noise_vars Noise variances after equalization. /// \param[in] ch_symbols Channel symbols, i.e., complex samples from the receive ports. -/// \param[in] ch_estimates Estimated channel coefficients. +/// \param[in] ch_estimates_ Estimated channel coefficients. /// \param[in] noise_var_est Estimated noise variance. It is assumed to be the same for all receive ports. /// \param[in] tx_scaling Transmission gain scaling factor. template From c62d2d7a747c5bffa18b37349238186443632447 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 30 Jul 2024 07:45:40 +0200 Subject: [PATCH 081/407] phy lower processors: improve documentation --- include/srsran/phy/lower/lower_phy_request_handler.h | 2 +- .../processors/uplink/prach/prach_processor_baseband.h | 6 +++--- .../processors/uplink/puxch/puxch_processor_notifier.h | 4 ++-- .../phy/lower/processors/uplink/uplink_processor_notifier.h | 6 +++--- .../processors/downlink/downlink_processor_baseband_impl.h | 2 +- .../lower/processors/uplink/puxch/puxch_processor_impl.h | 3 ++- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/srsran/phy/lower/lower_phy_request_handler.h b/include/srsran/phy/lower/lower_phy_request_handler.h index 22bd76e6d6..e5ed9bf7a3 100644 --- a/include/srsran/phy/lower/lower_phy_request_handler.h +++ b/include/srsran/phy/lower/lower_phy_request_handler.h @@ -43,7 +43,7 @@ class lower_phy_request_handler /// The notification contains the exact context and grid. /// /// \param[in] context Resource grid context. - /// \param[in] buffer Resource grid to store the processed slot. + /// \param[in] grid Resource grid to store the processed slot. virtual void request_uplink_slot(const resource_grid_context& context, resource_grid& grid) = 0; }; diff --git a/include/srsran/phy/lower/processors/uplink/prach/prach_processor_baseband.h b/include/srsran/phy/lower/processors/uplink/prach/prach_processor_baseband.h index 796bc0ef1b..84e1180211 100644 --- a/include/srsran/phy/lower/processors/uplink/prach/prach_processor_baseband.h +++ b/include/srsran/phy/lower/processors/uplink/prach/prach_processor_baseband.h @@ -29,11 +29,11 @@ class prach_processor_baseband /// Collects the parameters that describe a symbol context. struct symbol_context { - // Current slot. + /// Current slot. slot_point slot; - // Current symbol index within the slot. + /// Current symbol index within the slot. unsigned symbol; - // Sector identifier. + /// Sector identifier. unsigned sector; }; diff --git a/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h b/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h index 85c9c68f60..49a711c909 100644 --- a/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h +++ b/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h @@ -28,7 +28,7 @@ class puxch_processor_notifier /// \brief Notifies a PUxCH request outside the slot window. /// - /// See \ref lower_phy_error_notifier::on_pdxch_request_late for more information. + /// See \ref lower_phy_error_notifier::on_puxch_request_late for more information. /// \param[in] context PUxCH context. virtual void on_puxch_request_late(const resource_grid_context& context) = 0; @@ -40,4 +40,4 @@ class puxch_processor_notifier virtual void on_rx_symbol(const resource_grid_reader& grid, const lower_phy_rx_symbol_context& context) = 0; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/phy/lower/processors/uplink/uplink_processor_notifier.h b/include/srsran/phy/lower/processors/uplink/uplink_processor_notifier.h index 451589337a..03e0b995cc 100644 --- a/include/srsran/phy/lower/processors/uplink/uplink_processor_notifier.h +++ b/include/srsran/phy/lower/processors/uplink/uplink_processor_notifier.h @@ -26,13 +26,13 @@ class uplink_processor_notifier /// \brief Notifies that an uplink half slot has been received and processed by the lower PHY. /// - /// See \ref lower_phy_timing_notifier::on_half_slot for more information. + /// See \ref lower_phy_timing_notifier::on_ul_half_slot_boundary for more information. /// \param[in] context Timing context. virtual void on_half_slot(const lower_phy_timing_context& context) = 0; /// \brief Notifies that an uplink full slot has been received and processed by the lower PHY. /// - /// See \ref lower_phy_timing_notifier::on_full_slot for more information. + /// See \ref lower_phy_timing_notifier::on_ul_full_slot_boundary for more information. /// \param[in] context Timing context. virtual void on_full_slot(const lower_phy_timing_context& context) = 0; @@ -40,4 +40,4 @@ class uplink_processor_notifier virtual void on_new_metrics(const lower_phy_baseband_metrics& metrics) = 0; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/phy/lower/processors/downlink/downlink_processor_baseband_impl.h b/lib/phy/lower/processors/downlink/downlink_processor_baseband_impl.h index 314710d6b1..399fbe2885 100644 --- a/lib/phy/lower/processors/downlink/downlink_processor_baseband_impl.h +++ b/lib/phy/lower/processors/downlink/downlink_processor_baseband_impl.h @@ -61,7 +61,7 @@ class baseband_symbol_buffer /// \brief Reads samples from the buffer, starting at an initial timestamp. /// - /// Copies the samples starting at the sample indicated by \c timestamp until \out is filled or until all samples + /// Copies the samples starting at the sample indicated by \c timestamp until \c out is filled or until all samples /// have been read. /// /// \param[out] out Destination buffer. diff --git a/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h b/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h index 0cff8a2c65..91ee53aeae 100644 --- a/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h +++ b/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h @@ -21,6 +21,7 @@ namespace srsran { +/// Implements PUxCH baseband processor. class puxch_processor_impl : public puxch_processor, private puxch_processor_baseband, private puxch_processor_request_handler @@ -66,4 +67,4 @@ class puxch_processor_impl : public puxch_processor, resource_grid_request_pool requests; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran From a4838101dca9aac8613f7ceadfebc906b738899e Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 30 Jul 2024 16:20:16 +0200 Subject: [PATCH 082/407] sequence_generators: improve documentation --- .../upper/sequence_generators/low_papr_sequence_generator_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h b/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h index 817f75f2c4..e741a29d2a 100644 --- a/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h +++ b/lib/phy/upper/sequence_generators/low_papr_sequence_generator_impl.h @@ -58,6 +58,7 @@ class low_papr_sequence_generator_impl : public low_papr_sequence_generator /// /// \param[in] u Sequence group index {0, 29}. /// \param[in] v Sequence base index {0, 1}. + /// \param[in] M_zc Sequence length, parameter \f$M_{ZC}\f$. span r_uv_arg_mprb(unsigned u, unsigned v, unsigned M_zc); /// \brief Generates argument for the sequence \f$r^{(\alpha, \beta)}_{u,v}(n)\f$. From d6e27d375495ffa493cc8e44114440875c2d5348 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 30 Jul 2024 17:53:08 +0200 Subject: [PATCH 083/407] radio uhd: improve documentation --- lib/radio/uhd/radio_uhd_impl.h | 1 + lib/radio/uhd/radio_uhd_tx_stream_fsm.h | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/radio/uhd/radio_uhd_impl.h b/lib/radio/uhd/radio_uhd_impl.h index a6c4e8d96c..514f2726ee 100644 --- a/lib/radio/uhd/radio_uhd_impl.h +++ b/lib/radio/uhd/radio_uhd_impl.h @@ -129,6 +129,7 @@ class radio_session_uhd_impl : public radio_session, private radio_management_pl bool set_rx_gain(unsigned port_idx, double gain_dB) override { return set_rx_gain_unprotected(port_idx, gain_dB); } }; +/// Factory for UHD radio session. class radio_factory_uhd_impl : public radio_factory { public: diff --git a/lib/radio/uhd/radio_uhd_tx_stream_fsm.h b/lib/radio/uhd/radio_uhd_tx_stream_fsm.h index 17d2b8c44e..8701db42bc 100644 --- a/lib/radio/uhd/radio_uhd_tx_stream_fsm.h +++ b/lib/radio/uhd/radio_uhd_tx_stream_fsm.h @@ -25,6 +25,7 @@ namespace srsran { +/// Radio UHD transmit stream finite state machine. class radio_uhd_tx_stream_fsm { private: From 6eaa61a06ecd188b08d1b6f458f4759267e01803 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 30 Jul 2024 18:21:40 +0200 Subject: [PATCH 084/407] phy support: improve documentation --- include/srsran/phy/support/precoding_configuration.h | 8 ++++---- include/srsran/phy/support/re_pattern_formatters.h | 2 +- lib/phy/support/resource_grid_pool_asynchronous_impl.h | 2 +- .../time_alignment_estimator_dft_impl.h | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/srsran/phy/support/precoding_configuration.h b/include/srsran/phy/support/precoding_configuration.h index 72231bbf62..121119574c 100644 --- a/include/srsran/phy/support/precoding_configuration.h +++ b/include/srsran/phy/support/precoding_configuration.h @@ -35,10 +35,10 @@ class precoding_configuration precoding_configuration() = default; /// \brief Constructs a precoding configuration with the desired number of layers, ports and PRGs. - /// \param[in] nof_layers Number of layers. - /// \param[in] nof_ports Number of ports. - /// \param[in] nof_prg Number of PRGs. - /// \param[in] prg_size_ Number of PRB that comprise a PRG. + /// \param[in] nof_layers_ Number of layers. + /// \param[in] nof_ports_ Number of ports. + /// \param[in] nof_prg_ Number of PRGs. + /// \param[in] prg_size_ Number of PRB that comprise a PRG. /// \remark An assertion is triggered if the number of layers exceeds \ref precoding_constants::MAX_NOF_LAYERS. /// \remark An assertion is triggered if the number of ports exceeds \ref precoding_constants::MAX_NOF_PORTS. /// \remark An assertion is triggered if the number of PRGs exceeds \ref precoding_constants::MAX_NOF_PRG. diff --git a/include/srsran/phy/support/re_pattern_formatters.h b/include/srsran/phy/support/re_pattern_formatters.h index 25bdb4bd28..a01d8760cd 100644 --- a/include/srsran/phy/support/re_pattern_formatters.h +++ b/include/srsran/phy/support/re_pattern_formatters.h @@ -15,7 +15,7 @@ namespace fmt { -// \brief Custom formatter for \c re_pattern. +/// \brief Custom formatter for \c re_pattern. template <> struct formatter { /// Helper used to parse formatting options and format fields. diff --git a/lib/phy/support/resource_grid_pool_asynchronous_impl.h b/lib/phy/support/resource_grid_pool_asynchronous_impl.h index 36ebe44b99..a66d983f66 100644 --- a/lib/phy/support/resource_grid_pool_asynchronous_impl.h +++ b/lib/phy/support/resource_grid_pool_asynchronous_impl.h @@ -33,7 +33,7 @@ class resource_grid_pool_asynchronous_impl : public resource_grid_pool /// \brief Constructs a resource grid pool. /// \param expire_timeout_slots_ Resource grid timeout expiration in slots. /// \param async_executor_ Asynchronous housekeeping executor. - /// \param grids_ Resource grids. + /// \param grids Resource grids. resource_grid_pool_asynchronous_impl(unsigned expire_timeout_slots_, task_executor& async_executor_, std::vector> grids); diff --git a/lib/phy/support/time_alignment_estimator/time_alignment_estimator_dft_impl.h b/lib/phy/support/time_alignment_estimator/time_alignment_estimator_dft_impl.h index b611940118..728383d872 100644 --- a/lib/phy/support/time_alignment_estimator/time_alignment_estimator_dft_impl.h +++ b/lib/phy/support/time_alignment_estimator/time_alignment_estimator_dft_impl.h @@ -16,6 +16,7 @@ namespace srsran { +/// DFT-based implementation of the time alignment estimator. class time_alignment_estimator_dft_impl : public time_alignment_estimator { public: From 3958f2a6c5dd6ab5f2e6e101c251f913e9e1df8a Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 31 Jul 2024 12:32:14 +0200 Subject: [PATCH 085/407] srsvec: improve documentation --- include/srsran/srsvec/circ_shift.h | 6 +++--- include/srsran/srsvec/compare.h | 2 +- include/srsran/srsvec/convolution.h | 11 ++++++++++- lib/srsvec/unwrap.cpp | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/srsran/srsvec/circ_shift.h b/include/srsran/srsvec/circ_shift.h index 623acdd5df..2b24954423 100644 --- a/include/srsran/srsvec/circ_shift.h +++ b/include/srsran/srsvec/circ_shift.h @@ -21,7 +21,7 @@ namespace srsvec { /// \brief Circularly shifts a sequence in the forward direction. /// -/// The element at position \c i is moved to position i + shift<\tt>. Elements that fall beyond the end of the +/// The element at position \c i is moved to position i + shift. Elements that fall beyond the end of the /// sequence are reintroduced at its start. /// \param[out] out Shifted output sequence. /// \param[in] in Original input sequence. @@ -43,7 +43,7 @@ void circ_shift_forward(T&& out, const U& in, unsigned shift) /// \brief Circularly shifts a sequence in the backward direction. /// -/// The element at position \c i is moved to position i - shift<\tt>. Elements that fall beyond the beginning of the +/// The element at position \c i is moved to position i - shift. Elements that fall beyond the beginning of the /// sequence are reintroduced at its end. /// \param[out] out Shifted output sequence. /// \param[in] in Original input sequence. @@ -64,4 +64,4 @@ void circ_shift_backward(T&& out, const U& in, unsigned shift) } } // namespace srsvec -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/srsvec/compare.h b/include/srsran/srsvec/compare.h index 6aae7eeaac..1ba59d6010 100644 --- a/include/srsran/srsvec/compare.h +++ b/include/srsran/srsvec/compare.h @@ -30,7 +30,7 @@ bool equal(const T1& s1, const T2& s2) return std::equal(s1.begin(), s1.end(), s2.begin(), s2.end()); } -/// \brief Finds the first value in \input that is equal to \c value. +/// \brief Finds the first value in \c input that is equal to \c value. /// /// The implementation is equivalent to: /// \code diff --git a/include/srsran/srsvec/convolution.h b/include/srsran/srsvec/convolution.h index 5e8794fa6f..d6eb6ed442 100644 --- a/include/srsran/srsvec/convolution.h +++ b/include/srsran/srsvec/convolution.h @@ -37,9 +37,18 @@ bool check_different(const T& in1, const T& in2) return (in1.data() != in2.data()); } +/// \name No padding convolution. +/// Convolution between two sequences without zero-padding the edges (MATLAB calls this the \e valid section of the +/// convolution). +///@{ + +/// Real sequences. void multiply_and_accumulate(span out, span x, span y); +/// One real and one complex sequence. void multiply_and_accumulate(span out, span x, span y); +/// Complex sequences. void multiply_and_accumulate(span out, span x, span y); +///@} } // namespace detail @@ -109,4 +118,4 @@ void convolution_same(V&& out, const T& x_v, const U& y_v) } } // namespace srsvec -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/srsvec/unwrap.cpp b/lib/srsvec/unwrap.cpp index 6114b39846..58916fd5a3 100644 --- a/lib/srsvec/unwrap.cpp +++ b/lib/srsvec/unwrap.cpp @@ -17,7 +17,7 @@ using namespace srsran; -/// \brif Unwraps a list of floats. +/// \brief Unwraps a list of floats. /// /// The inputs are assumed to take values in the range \f$[-\alpha, \alpha)\f$. Whenever the jump between two /// consecutive values is larger than \f$\alpha\f$, the second value is shifted by \f$\pm 2 \alpha\f$, depending on the From 758c41996bae0f913120be9fe3d4f9aacb3c6eef Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 31 Jul 2024 12:53:19 +0200 Subject: [PATCH 086/407] phy upper: improve documentation --- include/srsran/phy/upper/upper_phy_factories.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/srsran/phy/upper/upper_phy_factories.h b/include/srsran/phy/upper/upper_phy_factories.h index e41d5270ce..c3ba41e4d9 100644 --- a/include/srsran/phy/upper/upper_phy_factories.h +++ b/include/srsran/phy/upper/upper_phy_factories.h @@ -122,7 +122,7 @@ struct pdsch_processor_generic_configuration { struct pdsch_processor_concurrent_configuration { /// \brief Number of threads for processing PDSCH codeblocks concurrently. /// - /// Only used when \ref pdsch_processor_type is set to \c concurrent. Ignored otherwise. + /// Only used when \ref pdsch_processor is set to \c concurrent. Ignored otherwise. /// /// \remark An assertion is triggered if it is not greater than 1. unsigned nof_pdsch_codeblock_threads = 0; @@ -130,7 +130,7 @@ struct pdsch_processor_concurrent_configuration { /// /// Sets the maximum number of PDSCH processor instances that can be used simultaneously. unsigned max_nof_simultaneous_pdsch = 0; - /// PDSCH codeblock task executor. Set to \c nullptr if \ref nof_pdsch_threads is less than 2. + /// PDSCH codeblock task executor. Set to \c nullptr if \ref nof_pdsch_codeblock_threads is less than 2. task_executor* pdsch_codeblock_task_executor = nullptr; }; From ffee2239a9dd0b7c26f0d1155766bc36b3072d48 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 31 Jul 2024 14:48:00 +0200 Subject: [PATCH 087/407] radio notification handler: improved documentation --- include/srsran/radio/radio_notification_handler.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/srsran/radio/radio_notification_handler.h b/include/srsran/radio/radio_notification_handler.h index a57ec362b0..78809ac700 100644 --- a/include/srsran/radio/radio_notification_handler.h +++ b/include/srsran/radio/radio_notification_handler.h @@ -28,6 +28,7 @@ class radio_notification_handler : public radio_base class event_source { public: + /// Radio event sources. enum sources { /// Default event value meaning it is not set. UNDEFINED = 0, @@ -71,6 +72,7 @@ class radio_notification_handler : public radio_base class event_type { public: + /// Radio event types. enum types { /// Default event value meaning it is not set. UNDEFINED = 0, From e2cdb0f65a64ccefdf89797ab1a7f486c941a579 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 31 Jul 2024 14:52:32 +0200 Subject: [PATCH 088/407] dmrs_mapping: improve documentation --- include/srsran/phy/upper/dmrs_mapping.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/srsran/phy/upper/dmrs_mapping.h b/include/srsran/phy/upper/dmrs_mapping.h index 7f72773d2f..3547533579 100644 --- a/include/srsran/phy/upper/dmrs_mapping.h +++ b/include/srsran/phy/upper/dmrs_mapping.h @@ -110,6 +110,7 @@ class dmrs_type return dmrs_pattern; } + /// Returns a string with the DM-RS type. const char* to_string() const { switch (value) { From 34defd800ed0fed4f1dc8ce610ef91c7b3acd4f8 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 31 Jul 2024 15:09:47 +0200 Subject: [PATCH 089/407] upper_phy: improve documentation --- include/srsran/phy/upper/uplink_slot_pdu_repository.h | 2 +- include/srsran/phy/upper/upper_phy_rx_results_notifier.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/srsran/phy/upper/uplink_slot_pdu_repository.h b/include/srsran/phy/upper/uplink_slot_pdu_repository.h index e36469d018..8b16a3f4eb 100644 --- a/include/srsran/phy/upper/uplink_slot_pdu_repository.h +++ b/include/srsran/phy/upper/uplink_slot_pdu_repository.h @@ -37,7 +37,7 @@ class uplink_slot_pdu_repository public: /// \brief Constructs an uplink slot pdu repository that supports the given number of slots. /// - /// \param nof_slots_[in] Number of slots supported by the repository. + /// \param[in] nof_slots_ Number of slots supported by the repository. explicit uplink_slot_pdu_repository(unsigned nof_slots_) : nof_slots(nof_slots_), repository(nof_slots_) {} /// Adds the given PUSCH PDU to the repository at the given slot. diff --git a/include/srsran/phy/upper/upper_phy_rx_results_notifier.h b/include/srsran/phy/upper/upper_phy_rx_results_notifier.h index 7231227ad1..a44107aff5 100644 --- a/include/srsran/phy/upper/upper_phy_rx_results_notifier.h +++ b/include/srsran/phy/upper/upper_phy_rx_results_notifier.h @@ -51,9 +51,9 @@ struct ul_pusch_results_data { span payload; /// \brief Creates a data-related decoding result produced from a discarded transmission. - /// \param rnti_ Parameter \f$n_{RNTI}\f$ from TS38.211 Section 6.3.1.1. - /// \param slot_ Slot description (also specifies the numerology). - /// \param harq_id HARQ process ID. + /// \param[in] rnti_ Parameter \f$n_{RNTI}\f$ from TS38.211 Section 6.3.1.1. + /// \param[in] slot_ Slot description (also specifies the numerology). + /// \param[in] harq_id_ HARQ process ID. /// \return The data-related PUSCH processing results without CSI measurements and marked as failed transmission. static ul_pusch_results_data create_discarded(rnti_t rnti_, slot_point slot_, unsigned harq_id_) { From 78cba1326d7d4f4d22d226cb5253f8322a7f7ed0 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Mon, 5 Aug 2024 10:56:35 +0000 Subject: [PATCH 090/407] gnb,ofh: configuration of number of ru_txrx threads and their affinities --- apps/services/worker_manager.cpp | 28 +++++++++++++---- apps/services/worker_manager.h | 2 ++ .../flexible_du/split_7_2/ru_ofh_config.h | 2 ++ .../split_7_2/ru_ofh_config_cli11_schema.cpp | 30 +++++++++++++++++++ .../split_7_2/ru_ofh_config_validator.cpp | 16 +++++++++- .../split_7_2/ru_ofh_config_yaml_writer.cpp | 16 ++++++++++ .../split_7_2/ru_ofh_factories.cpp | 10 ++++--- 7 files changed, 93 insertions(+), 11 deletions(-) diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager.cpp index 9f0865e3ec..dda928764b 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager.cpp @@ -73,6 +73,20 @@ worker_manager::worker_manager(const dynamic_du_unit_config& du_cfg, ru)); } + if (std::holds_alternative(du_cfg.ru_cfg)) { + auto exec_cfg = std::get(du_cfg.ru_cfg).config.expert_execution_cfg; + for (auto& affinity_mask : exec_cfg.txrx_affinities) { + ru_txrx_affinity_masks.emplace_back(affinity_mask); + } + // If ru_txrx_cpus parameters are not specified, use the affinities of ru_cpus parameters of the cells. + if (ru_txrx_affinity_masks.empty()) { + for (unsigned i = 0, e = nof_cells; i != e; ++i) { + auto affinity_cfg = exec_cfg.cell_affinities[i].ru_cpu_cfg; + ru_txrx_affinity_masks.emplace_back(affinity_cfg.mask); + } + } + } + // Determine whether the gnb app is running in realtime or in simulated environment. bool is_blocking_mode_active = false; if (std::holds_alternative(du_cfg.ru_cfg)) { @@ -539,13 +553,17 @@ void worker_manager::create_ofh_executors(const ru_ofh_unit_expert_execution_con const std::string name = "ru_timing"; const std::string exec_name = "ru_timing_exec"; - // As the timer worker is shared for all the RU cells, pick the first cell from the affinity manager. + // Use the ru_timing_cpu configuration if specified, otherwise use the ru_cpus of the first cell, as the timer + // worker is shared for all the RU cells. + os_sched_affinity_bitmask ru_timing_cpu_mask = + ru_timing_mask.any() ? ru_timing_mask + : affinity_mng.front().calcute_affinity_mask(sched_affinity_mask_types::ru); const single_worker ru_worker{name, {concurrent_queue_policy::lockfree_spsc, 4}, {{exec_name}}, std::chrono::microseconds{0}, os_thread_realtime_priority::max() - 0, - ru_timing_mask}; + ru_timing_cpu_mask}; if (!exec_mng.add_execution_context(create_execution_context(ru_worker))) { report_fatal_error("Failed to instantiate {} execution context", ru_worker.name); } @@ -591,9 +609,7 @@ void worker_manager::create_ofh_executors(const ru_ofh_unit_expert_execution_con } // Executor for Open Fronthaul messages transmission and reception. { - unsigned nof_txrx_workers = std::max(static_cast(std::ceil(nof_cells / 2.0f)), 1U); - - for (unsigned i = 0; i != nof_txrx_workers; ++i) { + for (unsigned i = 0, e = ru_txrx_affinity_masks.size(); i != e; ++i) { const std::string name = "ru_txrx_#" + std::to_string(i); const std::string exec_name = "ru_txrx_exec_#" + std::to_string(i); @@ -602,7 +618,7 @@ void worker_manager::create_ofh_executors(const ru_ofh_unit_expert_execution_con {{exec_name}}, std::chrono::microseconds{1}, os_thread_realtime_priority::max() - 1, - affinity_mng.front().calcute_affinity_mask(sched_affinity_mask_types::ru)}; + ru_txrx_affinity_masks[i]}; if (not exec_mng.add_execution_context(create_execution_context(ru_worker))) { report_fatal_error("Failed to instantiate {} execution context", ru_worker.name); } diff --git a/apps/services/worker_manager.h b/apps/services/worker_manager.h index 6d0f8125cd..809f72d8fe 100644 --- a/apps/services/worker_manager.h +++ b/apps/services/worker_manager.h @@ -102,6 +102,8 @@ struct worker_manager : public worker_manager_executor_getter { os_sched_affinity_manager low_prio_affinity_mng; os_sched_affinity_bitmask ru_timing_mask; + std::vector ru_txrx_affinity_masks; + /// CPU affinity bitmask manager per cell. std::vector affinity_mng; diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config.h b/apps/units/flexible_du/split_7_2/ru_ofh_config.h index 2e7005b9ca..b5a0b39fd9 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config.h +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config.h @@ -129,6 +129,8 @@ struct ru_ofh_unit_expert_execution_config { os_sched_affinity_bitmask ru_timing_cpu; /// Expert thread configuration of the Open Fronthaul Radio Unit. ru_ofh_unit_expert_threads_config threads; + /// CPU affinities per RU txrx thread. + std::vector txrx_affinities; /// CPU affinities per cell. std::vector cell_affinities = {{}}; }; diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp b/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp index 26fb6bb17d..c051f44191 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp @@ -269,6 +269,15 @@ static void configure_cli11_ofh_threads_args(CLI::App& app, ru_ofh_unit_expert_t ->capture_default_str(); } +static void configure_cli11_txrx_affinity_args(CLI::App& app, os_sched_affinity_bitmask& mask) +{ + add_option_function( + app, + "--ru_txrx_cpus", + [&mask](const std::string& value) { parse_affinity_mask(mask, value, "txrx_cpus"); }, + "Number of CPUs used for the Radio Unit tasks"); +} + static void configure_cli11_expert_execution_args(CLI::App& app, ru_ofh_unit_expert_execution_config& config) { // Affinity section. @@ -287,6 +296,27 @@ static void configure_cli11_expert_execution_args(CLI::App& app, ru_ofh_unit_exp add_subcommand(*threads_subcmd, "ofh", "Open Fronthaul thread configuration")->configurable(); configure_cli11_ofh_threads_args(*ofh_threads_subcmd, config.threads); + // RU txrx affinity section. + add_option_cell( + *affinities_subcmd, + "--ofh", + [&config](const std::vector& values) { + config.txrx_affinities.resize(values.size()); + + for (unsigned i = 0, e = values.size(); i != e; ++i) { + CLI::App subapp("RU tx-rx thread CPU affinities", + "RU tx-rx thread CPU affinities config #" + std::to_string(i)); + subapp.config_formatter(create_yaml_config_parser()); + subapp.allow_config_extras(); + configure_cli11_txrx_affinity_args(subapp, config.txrx_affinities[i]); + std::istringstream ss(values[i]); + subapp.parse_from_stream(ss); + } + }, + "Sets the CPU affinities configuration for RU cells tx-rx threads. Number of entries specified defines the " + "number of tx-rx threads created. By default if no entries is specifies, the number of tx-rx threads equals the " + "number of RU cells"); + // Cell affinity section. add_option_cell( app, diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config_validator.cpp b/apps/units/flexible_du/split_7_2/ru_ofh_config_validator.cpp index 7c9389e502..95b9e143d2 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config_validator.cpp +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config_validator.cpp @@ -17,7 +17,7 @@ static bool validate_expert_execution_unit_config(const ru_ofh_unit_expert_execu unsigned nof_cells, const os_sched_affinity_bitmask& available_cpus) { - // Configure more cells for expert execution than the number of cells is an error. + // Configuring more cells for expert execution than the number of cells is an error. if (config.cell_affinities.size() != nof_cells) { fmt::print("Using different number of cells for Open Fronthaul expert execution '{}' than the number of defined " "cells '{}'\n", @@ -27,6 +27,14 @@ static bool validate_expert_execution_unit_config(const ru_ofh_unit_expert_execu return false; } + // Configuring more entries for tx-rx affinities than the number of cells is an error. + if (config.txrx_affinities.size() > nof_cells) { + fmt::print("Using more txrx cells for Open Fronthaul expert execution '{}' than the number of defined cells '{}'\n", + config.txrx_affinities.size(), + nof_cells); + return false; + } + auto validate_cpu_range = [](const os_sched_affinity_bitmask& allowed_cpus_mask, const os_sched_affinity_bitmask& mask, const std::string& name) { @@ -39,6 +47,12 @@ static bool validate_expert_execution_unit_config(const ru_ofh_unit_expert_execu return true; }; + for (const auto& mask : config.txrx_affinities) { + if (!validate_cpu_range(available_cpus, mask, "ru_txrx_cpus")) { + return false; + } + } + for (const auto& cell : config.cell_affinities) { if (!validate_cpu_range(available_cpus, cell.ru_cpu_cfg.mask, "ru_cpus")) { return false; diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp b/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp index 81b2095bd4..d4032f25ae 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp @@ -31,6 +31,22 @@ static void fill_ru_ofh_expert_execution_section(YAML::Node node, const ru_ofh_u ofh_node["enable_dl_parallelization"] = config.threads.is_downlink_parallelized; } + if (config.txrx_affinities.size() > 0) { + YAML::Node affinities_node = node["affinities"]; + YAML::Node ofh_node = affinities_node["ofh"]; + while (config.txrx_affinities.size() > ofh_node.size()) { + ofh_node.push_back(YAML::Node()); + } + + unsigned index = 0; + for (auto subnode : ofh_node) { + const auto& mask = config.txrx_affinities[index]; + + subnode["ru_txrx_cpus"] = fmt::format("{:,}", span(mask.get_cpu_ids())); + ++index; + } + } + auto cell_affinities_node = node["cell_affinities"]; while (config.cell_affinities.size() > cell_affinities_node.size()) { cell_affinities_node.push_back(YAML::Node()); diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_factories.cpp b/apps/units/flexible_du/split_7_2/ru_ofh_factories.cpp index f330ed2b6b..b21769e319 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_factories.cpp +++ b/apps/units/flexible_du/split_7_2/ru_ofh_factories.cpp @@ -15,9 +15,6 @@ using namespace srsran; -// Number of OFH sectors served by a single executor for transmitter and receiver tasks. -static const unsigned NOF_SECTORS_PER_TXRX_EXECUTOR = 2; - /// Resolves the Open Fronthaul Radio Unit dependencies and adds them to the configuration. static void configure_ru_ofh_executors_and_notifiers(unsigned nof_sectors, ru_ofh_dependencies& dependencies, @@ -32,12 +29,17 @@ static void configure_ru_ofh_executors_and_notifiers(unsigned dependencies.rx_symbol_notifier = &symbol_notifier; dependencies.error_notifier = &error_notifier; + // Number of OFH sectors served by a single executor for transmitter and receiver tasks. + unsigned nof_txrx_threads = workers.ru_txrx_exec.size(); + unsigned nof_sectors_per_txrx_thread = + (nof_sectors > nof_txrx_threads) ? static_cast(std::ceil(nof_sectors / float(nof_txrx_threads))) : 1; + // Configure sector. for (unsigned i = 0; i != nof_sectors; ++i) { dependencies.sector_dependencies.emplace_back(); ru_ofh_sector_dependencies& sector_deps = dependencies.sector_dependencies.back(); // Note, one executor for transmitter and receiver tasks is shared per two sectors. - sector_deps.txrx_executor = workers.ru_txrx_exec[i / NOF_SECTORS_PER_TXRX_EXECUTOR]; + sector_deps.txrx_executor = workers.ru_txrx_exec[i / nof_sectors_per_txrx_thread]; sector_deps.uplink_executor = workers.ru_rx_exec[i]; sector_deps.downlink_executor = workers.ru_dl_exec[i]; sector_deps.logger = dependencies.logger; From adf0e7d61b45b5eb97bab756d09fc5a117a6ff50 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Mon, 5 Aug 2024 11:46:11 +0200 Subject: [PATCH 091/407] ci: temporal disable uesim --- .gitlab/ci/e2e.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 31398437e2..37289a8f51 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -444,23 +444,23 @@ cudu amari 32UE: matrix: - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] -uesim 32UE beta: - stage: zmq - extends: .e2e-run - variables: - GROUP: uesim - TESTBED: zmq_uesim - MARKERS: "zmq and not smoke" - KEYWORDS: ping - E2E_LOG_LEVEL: "info" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - needs: - - job: "basic relwithdeb" - artifacts: true - - job: "build uesim zmq driver" - artifacts: true - - *retina-needs - allow_failure: true +# uesim 32UE beta: +# stage: zmq +# extends: .e2e-run +# variables: +# GROUP: uesim +# TESTBED: zmq_uesim +# MARKERS: "zmq and not smoke" +# KEYWORDS: ping +# E2E_LOG_LEVEL: "info" +# RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" +# needs: +# - job: "basic relwithdeb" +# artifacts: true +# - job: "build uesim zmq driver" +# artifacts: true +# - *retina-needs +# allow_failure: true ################################################################################ # TEST MODE From 3bfef5c1afa2da580a7eb888be96e2adea9c3ad1 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 2 Aug 2024 11:41:43 +0200 Subject: [PATCH 092/407] phy: optimize LDPC encoder for AVX2 --- .../channel_coding/ldpc/ldpc_encoder_avx2.cpp | 100 ++++++++---------- .../channel_coding/ldpc/ldpc_encoder_avx2.h | 13 +-- 2 files changed, 49 insertions(+), 64 deletions(-) diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp index 8791f4caf7..5ff5815e49 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp @@ -98,24 +98,6 @@ ldpc_encoder_avx2::strategy_method ldpc_encoder_avx2::select_sys_bits_strategy<1 return &ldpc_encoder_avx2::systematic_bits_inner; } -// Recursively selects the proper strategy for the extended region by successively decreasing the value of the template -// parameter. -template -ldpc_encoder_avx2::strategy_method ldpc_encoder_avx2::select_ext_strategy(unsigned node_size_avx2) -{ - if (node_size_avx2 == NODE_SIZE_AVX2_PH) { - return &ldpc_encoder_avx2::ext_region_inner; - } - return select_ext_strategy(node_size_avx2); -} - -// Ensures that the recursion stops when NODE_SIZE_AVX2_PH == 1. -template <> -ldpc_encoder_avx2::strategy_method ldpc_encoder_avx2::select_ext_strategy<1>(unsigned /*node_size_avx2*/) -{ - return &ldpc_encoder_avx2::ext_region_inner<1>; -} - void ldpc_encoder_avx2::select_strategy() { ldpc_base_graph_type current_bg = current_graph->get_base_graph(); @@ -126,7 +108,6 @@ void ldpc_encoder_avx2::select_strategy() systematic_bits = select_sys_bits_strategy(current_bg, node_size_avx2); high_rate = select_hr_strategy(current_bg, current_ls_index, node_size_avx2); - ext_region = select_ext_strategy(node_size_avx2); } void ldpc_encoder_avx2::load_input(const bit_buffer& in) @@ -152,8 +133,10 @@ void ldpc_encoder_avx2::load_input(const bit_buffer& in) // Computes the XOR logical operation (modulo-2 sum) between the contents of "in0" and "in1". The result is stored in // "out". The representation is unpacked (1 byte represents 1 bit). -static void fast_xor(span out, span in0, span in1) +template +static void fast_xor(span out, span in0, span in1) { + static_assert(sizeof(Type) == 1, "Type size must be one byte."); #if defined(__AVX512F__) && defined(__AVX512BW__) // Upgrades the XOR to AVX512 if it is possible. unsigned nof_vectors = in0.size() / AVX512_SIZE_BYTE; @@ -235,7 +218,7 @@ void ldpc_encoder_avx2::systematic_bits_inner() span plain_auxiliary = set_plain_auxiliary(); if (m_mask[m]) { - fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); + fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); } else { srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); m_mask[m] = true; @@ -396,42 +379,29 @@ void ldpc_encoder_avx2::high_rate_bg2_other_inner() } } -template -void ldpc_encoder_avx2::ext_region_inner() +void ldpc_encoder_avx2::ext_region_inner(span out_node, unsigned m) const { - // We only compute the variable nodes needed to fill the codeword. - // Also, recall the high-rate region has length (bg_K + 4) * lifting_size. - unsigned nof_layers = codeblock_length / lifting_size - bg_K; - - mm256::avx2_span codeblock(codeblock_buffer, codeblock_used_size); - - mm256::avx2_const_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_AVX2_PH); - - mm256::avx2_span rotated_node(rotated_node_buffer, NODE_SIZE_AVX2_PH); - - // Encode the extended region. - for (unsigned m = bg_hr_parity_nodes; m != nof_layers; ++m) { - unsigned skip = (bg_K + m) * NODE_SIZE_AVX2_PH; + unsigned node_size_byte = node_size_avx2 * AVX2_SIZE_BYTE; + span codeblock(codeblock_buffer); - for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { - unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); + // Copy the current data in the node. + srsvec::copy(out_node, codeblock.subspan((bg_K + m) * node_size_byte, lifting_size)); - if (node_shift == NO_EDGE) { - continue; - } + for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { + unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); - // At this point, the codeblock nodes in the extended region already contain the contribution from the systematic - // bits (they were computed in systematic_bits_inner). All is left to do is to sum the contribution due to the - // high-rate region (also stored in codeblock), with the proper circular shifts. - srsvec::circ_shift_backward(rotated_node.plain_span(0, lifting_size), - codeblock.plain_span((bg_K + k) * NODE_SIZE_AVX2_PH, lifting_size), - node_shift); - - for (unsigned j = 0; j != NODE_SIZE_AVX2_PH; ++j) { - codeblock.set_at(skip + j, _mm256_xor_si256(codeblock.get_at(skip + j), rotated_node.get_at(j))); - } + if (node_shift == NO_EDGE) { + continue; } - skip += NODE_SIZE_AVX2_PH; + + // At this point, the codeblock nodes in the extended region already contain the contribution from the systematic + // bits (they were computed in systematic_bits_inner). All is left to do is to sum the contribution due to the + // high-rate region (also stored in codeblock), with the proper circular shifts. + span in_node = codeblock.subspan((bg_K + k) * node_size_byte, lifting_size); + fast_xor(out_node.first(lifting_size - node_shift), + out_node.first(lifting_size - node_shift), + in_node.last(lifting_size - node_shift)); + fast_xor(out_node.last(node_shift), out_node.last(node_shift), in_node.first(node_shift)); } } @@ -464,8 +434,30 @@ void ldpc_encoder_avx2::write_codeblock(span out, unsigned offset) cons // Determine the number of bits to read from this node. unsigned count = std::min(lifting_size - offset, static_cast(out.size())); - // Copy node bits. - srsvec::copy(out.first(count), codeblock.subspan(offset, count)); + // Check if it is operating in the extended region. + if (i_node < bg_hr_parity_nodes + bg_K) { + srsvec::copy(out.first(count), codeblock.subspan(offset, count)); + } else { + // Detect if the extended region can be done directly on the output. + bool inplace = ((offset == 0) && (count == lifting_size)); + + // Create temporary data. + static_vector temp(lifting_size); + span node_view = temp; + + // Use direct output for the extended node. + if (inplace) { + node_view = out.first(lifting_size); + } + + // Process extended region for the given node. + ext_region_inner(node_view, i_node - bg_K); + + // Copy data if temporal buffer was used. + if (!inplace) { + srsvec::copy(out.first(count), node_view.subspan(offset, count)); + } + } // Advance codeblock. codeblock = codeblock.last(codeblock.size() - node_size_byte); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h index 798b02364e..57de70d7b6 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h @@ -26,7 +26,7 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl void load_input(const bit_buffer& in) override; void preprocess_systematic_bits() override { (this->*systematic_bits)(); } void encode_high_rate() override { (this->*high_rate)(); } - void encode_ext_region() override { (this->*ext_region)(); } + void encode_ext_region() override {} void write_codeblock(span out, unsigned offset) const override; /// Alias for pointer to private methods. @@ -36,8 +36,6 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl strategy_method systematic_bits; /// Placeholder for strategy implementation of encode_high_rate. strategy_method high_rate; - /// Placeholder for strategy implementation of encode_ext_region. - strategy_method ext_region; /// Helper method to set the high-rate encoding strategy. template @@ -47,9 +45,6 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl /// Helper method to set the strategy for the systematic bits. template static strategy_method select_sys_bits_strategy(ldpc_base_graph_type current_bg, unsigned node_size_avx2); - /// Helper method to set the extended-region encoding strategy. - template - static strategy_method select_ext_strategy(unsigned node_size_avx2); /// \brief Long lifting size version of preprocess_systematic_bits - short lifting size. /// \tparam BG_K_PH Placeholder for the number of information nodes (i.e., K) for the current base graph. @@ -75,10 +70,8 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl /// \tparam NODE_SIZE_AVX2_PH Placeholder for the number of AVX2 registers used to represent a code node. template void high_rate_bg2_other_inner(); - /// \brief Carries out the extended region encoding when the lifting size is long. - /// \tparam NODE_SIZE_AVX2_PH Placeholder for the number of AVX2 registers used to represent a code node. - template - void ext_region_inner(); + /// Carries out the extended region encoding when the lifting size is long. + void ext_region_inner(span output_node, unsigned i_layer) const; /// Buffer containing the codeblock. std::array codeblock_buffer; From 557d755299aadd21b68ee74188908252dcb39158 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 2 Aug 2024 12:09:28 +0200 Subject: [PATCH 093/407] phy: optimize LDPC encoder for NEON --- .../channel_coding/ldpc/ldpc_encoder_avx2.h | 1 - .../ldpc/ldpc_encoder_generic.cpp | 98 +++++++++++++---- .../ldpc/ldpc_encoder_generic.h | 3 +- .../channel_coding/ldpc/ldpc_encoder_impl.cpp | 2 - .../channel_coding/ldpc/ldpc_encoder_impl.h | 2 - .../channel_coding/ldpc/ldpc_encoder_neon.cpp | 102 ++++++++---------- .../channel_coding/ldpc/ldpc_encoder_neon.h | 12 +-- 7 files changed, 131 insertions(+), 89 deletions(-) diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h index 57de70d7b6..354c133cba 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h @@ -26,7 +26,6 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl void load_input(const bit_buffer& in) override; void preprocess_systematic_bits() override { (this->*systematic_bits)(); } void encode_high_rate() override { (this->*high_rate)(); } - void encode_ext_region() override {} void write_codeblock(span out, unsigned offset) const override; /// Alias for pointer to private methods. diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp index fbec570e95..f7cb981c35 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp @@ -84,31 +84,93 @@ void ldpc_encoder_generic::preprocess_systematic_bits() } } -void ldpc_encoder_generic::encode_ext_region() +void ldpc_encoder_generic::ext_region_inner(span out_node, unsigned m) const { - // We only compute the variable nodes needed to fill the codeword. - // Also, recall the high-rate region has length (bg_K + 4) * lifting_size. - unsigned nof_layers = codeblock_length / lifting_size - bg_K; - for (unsigned m = bg_hr_parity_nodes; m < nof_layers; ++m) { - unsigned skip = (bg_K + m) * lifting_size; - for (unsigned i = 0; i != lifting_size; ++i) { - for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { - uint16_t node_shift = current_graph->get_lifted_node(m, bg_K + k); - if (node_shift == NO_EDGE) { - continue; - } - unsigned current_index = (bg_K + k) * lifting_size + ((i + node_shift) % lifting_size); - codeblock[skip + i] ^= codeblock[current_index]; - } + span codeblock_view(codeblock); + + // Copy the current data in the node. + srsvec::copy(out_node, codeblock_view.subspan((bg_K + m) * lifting_size, lifting_size)); + + for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { + unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); + + if (node_shift == NO_EDGE) { + continue; } + + // At this point, the codeblock nodes in the extended region already contain the contribution from the systematic + // bits (they were computed in systematic_bits_inner). All is left to do is to sum the contribution due to the + // high-rate region (also stored in codeblock), with the proper circular shifts. + span in_node = codeblock_view.subspan((bg_K + k) * lifting_size, lifting_size); + srsvec::binary_xor(out_node.first(lifting_size - node_shift), + in_node.last(lifting_size - node_shift), + out_node.first(lifting_size - node_shift)); + srsvec::binary_xor(out_node.last(node_shift), in_node.first(node_shift), out_node.last(node_shift)); } } void ldpc_encoder_generic::write_codeblock(span out, unsigned offset) const { - // The encoder shortens the codeblock by discarding the first 2 * LS bits. - span first = span(codeblock).subspan(2UL * lifting_size + offset, out.size()); - srsvec::copy(out, first); + srsran_assert(out.size() + offset <= bg_N_short * lifting_size, + "The output size (i.e., {}) plus the offset (i.e., {}) exceeds the codeblock length (i.e., {}).", + out.size(), + offset, + bg_N_short * lifting_size); + + // Calculate the node size in bytes, considering SIMD alignment. + span codeblock_view(codeblock); + + // Select the initial node. The first two blocks are shortened and the last node is not considered, since it can be + // incomplete. + unsigned i_node_begin = 2 + offset / lifting_size; + + // Advance the codeblock to the initial node. + codeblock_view = codeblock_view.last(codeblock.size() - i_node_begin * lifting_size); + + // End node. + unsigned i_node_end = i_node_begin + divide_ceil(out.size(), lifting_size); + + // Calculate the offset within the first node. + offset = offset % lifting_size; + + for (unsigned i_node = i_node_begin; i_node != i_node_end; ++i_node) { + // Determine the number of bits to read from this node. + unsigned count = std::min(lifting_size - offset, static_cast(out.size())); + + // Check if it is operating in the extended region. + if (i_node < bg_hr_parity_nodes + bg_K) { + srsvec::copy(out.first(count), codeblock_view.subspan(offset, count)); + } else { + // Detect if the extended region can be done directly on the output. + bool inplace = ((offset == 0) && (count == lifting_size)); + + // Create temporary data. + static_vector temp(lifting_size); + span node_view = temp; + + // Use direct output for the extended node. + if (inplace) { + node_view = out.first(lifting_size); + } + + // Process extended region for the given node. + ext_region_inner(node_view, i_node - bg_K); + + // Copy data if temporal buffer was used. + if (!inplace) { + srsvec::copy(out.first(count), node_view.subspan(offset, count)); + } + } + + // Advance codeblock. + codeblock_view = codeblock_view.last(codeblock_view.size() - lifting_size); + + // Advance output. + out = out.last(out.size() - count); + + // The offset is no longer required after the first node. + offset = 0; + } } void ldpc_encoder_generic::high_rate_bg1_i6() diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h index 80d62c3a4f..e9e62e8c86 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h @@ -31,7 +31,6 @@ class ldpc_encoder_generic : public ldpc_encoder_impl } void preprocess_systematic_bits() override; void encode_high_rate() override { (this->*high_rate)(); } - void encode_ext_region() override; void write_codeblock(span out, unsigned offset) const override; /// Pointer type shortcut. @@ -47,6 +46,8 @@ class ldpc_encoder_generic : public ldpc_encoder_impl void high_rate_bg2_i3_7(); /// Carries out the high-rate region encoding for BG2 and lifting size index in {0, 1, 2, 4, 5, 6}. void high_rate_bg2_other(); + /// Carries out the extended region encoding when the lifting size is long. + void ext_region_inner(span output_node, unsigned i_layer) const; /// Unpacked local copy of the message to encode. std::array temp_message; diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp index 6a91f861f3..99c74d7cb7 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.cpp @@ -58,8 +58,6 @@ ldpc_encoder_buffer& ldpc_encoder_impl::encode(const bit_buffer& encode_high_rate(); - encode_ext_region(); - return *this; } diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h index e97733594a..46f4c8739c 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_impl.h @@ -40,8 +40,6 @@ class ldpc_encoder_impl : public ldpc_encoder, private ldpc_encoder_buffer /// Computes the shortest possible codeword (systematic part plus high-rate region, that is the first /// 4 x lifting size redundancy bits). virtual void encode_high_rate() = 0; - /// Computes the rest of the redundancy bits (extension region). - virtual void encode_ext_region() = 0; // See ldpc_encoder_buffer interface for documentation. virtual void write_codeblock(span data, unsigned offset) const override = 0; // See ldpc_encoder_buffer interface for documentation. diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp index 5c28669bab..b7c0812ac1 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp @@ -98,24 +98,6 @@ ldpc_encoder_neon::strategy_method ldpc_encoder_neon::select_sys_bits_strategy<1 return &ldpc_encoder_neon::systematic_bits_inner; } -// Recursively selects the proper strategy for the extended region by successively decreasing the value of the template -// parameter. -template -ldpc_encoder_neon::strategy_method ldpc_encoder_neon::select_ext_strategy(unsigned node_size_neon) -{ - if (node_size_neon == NODE_SIZE_NEON_PH) { - return &ldpc_encoder_neon::ext_region_inner; - } - return select_ext_strategy(node_size_neon); -} - -// Ensures that the recursion stops when NODE_SIZE_NEON_PH == 1. -template <> -ldpc_encoder_neon::strategy_method ldpc_encoder_neon::select_ext_strategy<1>(unsigned /*node_size_neon*/) -{ - return &ldpc_encoder_neon::ext_region_inner<1>; -} - void ldpc_encoder_neon::select_strategy() { ldpc_base_graph_type current_bg = current_graph->get_base_graph(); @@ -126,7 +108,6 @@ void ldpc_encoder_neon::select_strategy() systematic_bits = select_sys_bits_strategy(current_bg, node_size_neon); high_rate = select_hr_strategy(current_bg, current_ls_index, node_size_neon); - ext_region = select_ext_strategy(node_size_neon); } void ldpc_encoder_neon::load_input(const bit_buffer& in) @@ -151,8 +132,10 @@ void ldpc_encoder_neon::load_input(const bit_buffer& in) // Computes the XOR logical operation (modulo-2 sum) between the contents of "in0" and "in1". The result is stored in // "out". The representation is unpacked (1 byte represents 1 bit). -static void fast_xor(span out, span in0, span in1) +template +static void fast_xor(span out, span in0, span in1) { + static_assert(sizeof(Type) == 1, "Type size must be one byte."); unsigned nof_vectors = in0.size() / NEON_SIZE_BYTE; neon::neon_const_span in0_local(in0, nof_vectors); neon::neon_const_span in1_local(in1, nof_vectors); @@ -212,7 +195,7 @@ void ldpc_encoder_neon::systematic_bits_inner() span plain_auxiliary = set_plain_auxiliary(); if (m_mask[m]) { - fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); + fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); } else { srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); m_mask[m] = true; @@ -373,42 +356,29 @@ void ldpc_encoder_neon::high_rate_bg2_other_inner() } } -template -void ldpc_encoder_neon::ext_region_inner() +void ldpc_encoder_neon::ext_region_inner(span out_node, unsigned m) const { - // We only compute the variable nodes needed to fill the codeword. - // Also, recall the high-rate region has length (bg_K + 4) * lifting_size. - unsigned nof_layers = codeblock_length / lifting_size - bg_K; - - neon::neon_span codeblock(codeblock_buffer, codeblock_used_size); - - neon::neon_const_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_NEON_PH); - - neon::neon_span rotated_node(rotated_node_buffer, NODE_SIZE_NEON_PH); - - // Encode the extended region. - for (unsigned m = bg_hr_parity_nodes; m != nof_layers; ++m) { - unsigned skip = (bg_K + m) * NODE_SIZE_NEON_PH; - - for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { - unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); + unsigned node_size_byte = node_size_neon * NEON_SIZE_BYTE; + span codeblock(codeblock_buffer); - if (node_shift == NO_EDGE) { - continue; - } + // Copy the current data in the node. + srsvec::copy(out_node, codeblock.subspan((bg_K + m) * node_size_byte, lifting_size)); - // At this point, the codeblock nodes in the extended region already contain the contribution from the systematic - // bits (they were computed in systematic_bits_inner). All is left to do is to sum the contribution due to the - // high-rate region (also stored in codeblock), with the proper circular shifts. - srsvec::circ_shift_backward(rotated_node.plain_span(0, lifting_size), - codeblock.plain_span((bg_K + k) * NODE_SIZE_NEON_PH, lifting_size), - node_shift); + for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { + unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); - for (unsigned j = 0; j != NODE_SIZE_NEON_PH; ++j) { - codeblock.set_at(skip + j, veorq_s8(codeblock.get_at(skip + j), rotated_node.get_at(j))); - } + if (node_shift == NO_EDGE) { + continue; } - skip += NODE_SIZE_NEON_PH; + + // At this point, the codeblock nodes in the extended region already contain the contribution from the systematic + // bits (they were computed in systematic_bits_inner). All is left to do is to sum the contribution due to the + // high-rate region (also stored in codeblock), with the proper circular shifts. + span in_node = codeblock.subspan((bg_K + k) * node_size_byte, lifting_size); + fast_xor(out_node.first(lifting_size - node_shift), + out_node.first(lifting_size - node_shift), + in_node.last(lifting_size - node_shift)); + fast_xor(out_node.last(node_shift), out_node.last(node_shift), in_node.first(node_shift)); } } @@ -441,8 +411,30 @@ void ldpc_encoder_neon::write_codeblock(span out, unsigned offset) cons // Determine the number of bits to read from this node. unsigned count = std::min(lifting_size - offset, static_cast(out.size())); - // Copy node bits. - srsvec::copy(out.first(count), codeblock.subspan(offset, count)); + // Check if it is operating in the extended region. + if (i_node < bg_hr_parity_nodes + bg_K) { + srsvec::copy(out.first(count), codeblock.subspan(offset, count)); + } else { + // Detect if the extended region can be done directly on the output. + bool inplace = ((offset == 0) && (count == lifting_size)); + + // Create temporary data. + static_vector temp(lifting_size); + span node_view = temp; + + // Use direct output for the extended node. + if (inplace) { + node_view = out.first(lifting_size); + } + + // Process extended region for the given node. + ext_region_inner(node_view, i_node - bg_K); + + // Copy data if temporal buffer was used. + if (!inplace) { + srsvec::copy(out.first(count), node_view.subspan(offset, count)); + } + } // Advance codeblock. codeblock = codeblock.last(codeblock.size() - node_size_byte); @@ -453,4 +445,4 @@ void ldpc_encoder_neon::write_codeblock(span out, unsigned offset) cons // The offset is no longer required after the first node. offset = 0; } -} +} \ No newline at end of file diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h index 366bb39a33..6abe2e3e2c 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h @@ -26,7 +26,6 @@ class ldpc_encoder_neon : public ldpc_encoder_impl void load_input(const bit_buffer& in) override; void preprocess_systematic_bits() override { (this->*systematic_bits)(); } void encode_high_rate() override { (this->*high_rate)(); } - void encode_ext_region() override { (this->*ext_region)(); } void write_codeblock(span out, unsigned offset) const override; /// Alias for pointer to private methods. @@ -36,8 +35,6 @@ class ldpc_encoder_neon : public ldpc_encoder_impl strategy_method systematic_bits; /// Placeholder for strategy implementation of encode_high_rate. strategy_method high_rate; - /// Placeholder for strategy implementation of encode_ext_region. - strategy_method ext_region; /// Helper method to set the high-rate encoding strategy. template @@ -47,9 +44,6 @@ class ldpc_encoder_neon : public ldpc_encoder_impl /// Helper method to set the strategy for the systematic bits. template static strategy_method select_sys_bits_strategy(ldpc_base_graph_type current_bg, unsigned node_size_neon); - /// Helper method to set the extended-region encoding strategy. - template - static strategy_method select_ext_strategy(unsigned node_size_neon); /// \brief Long lifting size version of preprocess_systematic_bits - short lifting size. /// \tparam BG_K_PH Placeholder for the number of information nodes (i.e., K) for the current base graph. @@ -75,10 +69,8 @@ class ldpc_encoder_neon : public ldpc_encoder_impl /// \tparam NODE_SIZE_NEON_PH Placeholder for the number of NEON registers used to represent a code node. template void high_rate_bg2_other_inner(); - /// \brief Carries out the extended region encoding when the lifting size is long. - /// \tparam NODE_SIZE_NEON_PH Placeholder for the number of NEON registers used to represent a code node. - template - void ext_region_inner(); + /// Carries out the extended region encoding when the lifting size is long. + void ext_region_inner(span output_node, unsigned i_layer) const; /// Buffer containing the codeblock. std::array codeblock_buffer; From 9dfb280302524bfe5f03bf13cdccf66b131ccfb5 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 16 Jul 2024 18:02:02 +0200 Subject: [PATCH 094/407] phy: improve pucch f0 detector Make false alarm independent of SNR and choose detection threshold based on the PUCCH configuration. --- .../pucch_detector_format0.cpp | 96 +++++++++++++------ .../pucch_detector_format0.h | 4 - 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/lib/phy/upper/channel_processors/pucch_detector_format0.cpp b/lib/phy/upper/channel_processors/pucch_detector_format0.cpp index 704ce9ec29..cb94f2303e 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_format0.cpp +++ b/lib/phy/upper/channel_processors/pucch_detector_format0.cpp @@ -9,14 +9,16 @@ */ #include "pucch_detector_format0.h" +#include "srsran/phy/constants.h" #include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/ran/pucch/pucch_constants.h" -#include "srsran/srsvec/accumulate.h" #include "srsran/srsvec/dot_prod.h" -#include "srsran/srsvec/prod.h" +#include +#include using namespace srsran; +namespace { + /// \brief PUCCH Format 0 dictionary entry. /// /// Pairs a cyclic shift with a corresponding UCI message. @@ -27,21 +29,23 @@ struct pucch_detector_format0_entry { pucch_uci_message message; }; +} // namespace + /// Table for positive SR only. Defined in TS38.213 Section 9.2.4. -static std::array pucch_detector_format0_noharq_sr = {{{0, {{1}, {}, {}, {}}}}}; +static const std::array pucch_detector_format0_noharq_sr = {{{0, {{1}, {}, {}, {}}}}}; /// Table for one HARQ-ACK feedback bit. Defined in TS38.213 Section 9.2.4 Table 9.2.3-3. -static std::array pucch_detector_format0_oneharq_nosr = { +static const std::array pucch_detector_format0_oneharq_nosr = { {{0, {{}, {0}, {}, {}}}, {6, {{}, {1}, {}, {}}}}}; /// Table for two HARQ-ACK feedback bit. Defined in TS38.213 Section 9.2.4 Table 9.2.3-4. -static std::array pucch_detector_format0_twoharq_nosr = { +static const std::array pucch_detector_format0_twoharq_nosr = { {{0, {{}, {0, 0}, {}, {}}}, {3, {{}, {0, 1}, {}, {}}}, {6, {{}, {1, 1}, {}, {}}}, {9, {{}, {1, 0}, {}, {}}}}}; /// Table for one HARQ-ACK feedback bit and one SR bit. Defined in TS38.213 Table 9.2.3-3 for negative SR and Table /// 9.2.5-1 for positive SR. -static std::array pucch_detector_format0_oneharq_onesr = { +static const std::array pucch_detector_format0_oneharq_onesr = { {{0, {{0}, {0}, {}, {}}}, {6, {{0}, {1}, {}, {}}}, {3, {{1}, {0}, {}, {}}}, {9, {{1}, {1}, {}, {}}}}}; /// Table for two HARQ-ACK feedback bit and one SR bit. Defined in TS38.213 Table 9.2.3-4 for negative SR and Table /// 9.2.5-2 for positive SR. -static std::array pucch_detector_format0_twoharq_onesr = { +static const std::array pucch_detector_format0_twoharq_onesr = { {{0, {{0}, {0, 0}, {}, {}}}, {3, {{0}, {0, 1}, {}, {}}}, {6, {{0}, {1, 1}, {}, {}}}, @@ -51,6 +55,51 @@ static std::array pucch_detector_format0_twohar {7, {{1}, {1, 1}, {}, {}}}, {10, {{1}, {1, 0}, {}, {}}}}}; +static float pick_threshold(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sequences) +{ + using threshold_index = std::pair; + using threshold_entry = std::pair; + + // Detection thresholds. + // + // Thresholds depend on the number of degrees of freedom (i.e., the number of Rx antenna ports times the number of + // symbols carrying PUCCH) and on the number of sequences that have to be evaluated (1, 2, 4 or 8 depending on the ACK + // and SR bits in the PUCCH). + // + // Thresholds marked as TS38.104 correspond to the cases evaluated in the 3GPP conformance tests. + // Thresholds marked as TBR (to be refined) haven't been tested yet. + static constexpr std::array pucch_detector_format0_thresholds = {{{{1, 1}, 0.5373}, + {{1, 2}, 0.6460}, + {{1, 4}, 0.7556}, + {{1, 8}, 1.6818}, // TBR + {{2, 1}, 0.5273}, // TBR + {{2, 2}, 0.4038}, // TS38.104 + {{2, 4}, 0.7273}, // TBR + {{2, 8}, 0.8364}, // TBR + {{4, 1}, 0.3455}, // TBR + {{4, 2}, 0.2800}, // TS38.104 + {{4, 4}, 0.4455}, // TBR + {{4, 8}, 0.5000}, // TBR + {{8, 1}, 0.2545}, // TBR + {{8, 2}, 0.2083}, // TS38.104 + {{8, 4}, 0.3000}, // TBR + {{8, 8}, 0.3273}}}; // TBR + // Number of degrees of freedom. + unsigned nof_degrees = nof_ports * nof_symbols; + + auto* it = std::lower_bound(pucch_detector_format0_thresholds.begin(), + pucch_detector_format0_thresholds.end(), + threshold_index(nof_degrees, nof_sequences), + [](const threshold_entry& a, const threshold_index& b) { return (a.first < b); }); + + srsran_assert(it != pucch_detector_format0_thresholds.end(), + "Requested configuration ({} antenna ports, {} OFDM symbols, {} sequences) not supported.", + nof_ports, + nof_symbols, + nof_sequences); + return it->second; +} + std::pair pucch_detector_format0::detect(const srsran::resource_grid_reader& grid, const pucch_detector::format0_configuration& config) @@ -139,31 +188,23 @@ pucch_detector_format0::detect(const srsran::resource_grid_reader& grid // Select received symbols. span rx_symbols = temp_re.get_view({i_symbol, i_port}); - // Calculate least square estimates. - srsvec::prod_conj(rx_symbols, sequence, lse); - - // Calculate the average power of the LSE. - float avg_pwr = srsvec::average_power(lse); - - // Calculate the correlation between the received signal and the low PAPR sequence. - float corr = std::norm(srsvec::accumulate(lse) / static_cast(NRE)); - - // Estimate noise variance. Assume noise and signal are orthogonal and the EPRE is equal to the sum of the - // signal and the noise. - float noise_var = std::max(0.0F, avg_pwr - corr); + // Received power. + float rx_power = srsvec::average_power(rx_symbols); - // Accumulate correlation for each channel. - sum_corr += corr; + // Correlation between received symbols and spreading sequence. + cf_t rx_seq_corr = srsvec::dot_prod(rx_symbols, sequence); - // Accumulate noise variance weighted by the correlation. - sum_noise_var += noise_var * corr; + // Update cumulative values. + float corr_contribution = std::norm(rx_seq_corr) / static_cast(NRE); + sum_corr += corr_contribution; + sum_noise_var += rx_power * static_cast(NRE) - corr_contribution; } } // Calculate detection metric. float detection_metric = 0.0F; if (std::isnormal(sum_noise_var)) { - detection_metric = sum_corr * sum_corr / sum_noise_var; + detection_metric = sum_corr / sum_noise_var; } // Update the best metric and the actual message. @@ -174,7 +215,8 @@ pucch_detector_format0::detect(const srsran::resource_grid_reader& grid } } - pucch_uci_message message = *best_message; + pucch_uci_message message = *best_message; + float detection_threshold = pick_threshold(nof_ports, nof_symbols, m_cs_table.size()); if (best_metric > detection_threshold) { message.set_status(uci_status::valid); } else { @@ -187,4 +229,4 @@ pucch_detector_format0::detect(const srsran::resource_grid_reader& grid csi.set_epre(convert_power_to_dB(epre)); return std::make_pair(message, csi); -} \ No newline at end of file +} diff --git a/lib/phy/upper/channel_processors/pucch_detector_format0.h b/lib/phy/upper/channel_processors/pucch_detector_format0.h index bd20df0db9..3daf722d38 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_format0.h +++ b/lib/phy/upper/channel_processors/pucch_detector_format0.h @@ -37,8 +37,6 @@ class pucch_detector_format0 const pucch_detector::format0_configuration& config); private: - /// Detection threshold. - static constexpr float detection_threshold = 4.0F; /// Maximum number of RE used for PUCCH Format 0. Recall that PUCCH format 0 occupies a single RB. static constexpr unsigned max_nof_re = NRE * MAX_PORTS * pucch_constants::format0_nof_symbols_range.stop(); @@ -52,8 +50,6 @@ class pucch_detector_format0 /// Temporary storage of the resource elements. static_tensor(dims::nof_dims), cf_t, max_nof_re, dims> temp_re; - /// Temporary least square estimates for a single OFDM symbol. - std::array lse; }; } // namespace srsran From 155edff0884973f1d01ce7e114a0afcff9f207f3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 5 Aug 2024 12:08:42 +0200 Subject: [PATCH 095/407] phy: update OFDM modulation/Demodulation test vectors for FR2 --- .../phy/lower_phy_example_factory.cpp | 8 +- .../lower/modulation/modulation_factories.h | 5 +- .../lower/modulation/ofdm_prach_demodulator.h | 10 +- .../dft_processor_generic_impl.cpp | 2 + .../lower/modulation/modulation_factories.cpp | 50 ++++-- .../ofdm_prach_demodulator_impl.cpp | 65 ++++--- .../modulation/ofdm_prach_demodulator_impl.h | 20 +-- .../uplink/prach/prach_processor_worker.cpp | 2 +- lib/ru/generic/lower_phy_factory.h | 8 +- .../modulation/ofdm_demodulator_test_data.h | 7 +- .../ofdm_demodulator_test_data.tar.gz | 4 +- .../modulation/ofdm_modulator_test_data.h | 7 +- .../ofdm_modulator_test_data.tar.gz | 4 +- .../ofdm_prach_demodulator_test.cpp | 25 ++- .../ofdm_prach_demodulator_test_data.h | 162 ++++++------------ .../ofdm_prach_demodulator_test_data.tar.gz | 4 +- .../uplink/prach/prach_processor_test.cpp | 4 +- 17 files changed, 194 insertions(+), 193 deletions(-) diff --git a/apps/examples/phy/lower_phy_example_factory.cpp b/apps/examples/phy/lower_phy_example_factory.cpp index f1c4ec3e2d..880d181c69 100644 --- a/apps/examples/phy/lower_phy_example_factory.cpp +++ b/apps/examples/phy/lower_phy_example_factory.cpp @@ -15,6 +15,12 @@ using namespace srsran; std::unique_ptr srsran::create_lower_phy(lower_phy_configuration& config) { + // Deduce frequency range from the subcarrier spacing. + frequency_range fr = frequency_range::FR1; + if (config.scs > subcarrier_spacing::kHz60) { + fr = frequency_range::FR2; + } + // Get the maximum number of receive ports. unsigned max_nof_rx_ports = std::max_element(config.sectors.begin(), @@ -45,7 +51,7 @@ std::unique_ptr srsran::create_lower_phy(lower_phy_configuration& con // Create OFDM PRACH demodulator factory. std::shared_ptr prach_demodulator_factory = - create_ofdm_prach_demodulator_factory_sw(dft_factory, config.srate); + create_ofdm_prach_demodulator_factory_sw(dft_factory, config.srate, fr); // Create PDxCH processor factory. std::shared_ptr pdxch_proc_factory = diff --git a/include/srsran/phy/lower/modulation/modulation_factories.h b/include/srsran/phy/lower/modulation/modulation_factories.h index ea09f24678..5b6f04663e 100644 --- a/include/srsran/phy/lower/modulation/modulation_factories.h +++ b/include/srsran/phy/lower/modulation/modulation_factories.h @@ -86,7 +86,10 @@ create_ofdm_demodulator_factory_generic(ofdm_factory_generic_configuration& conf /// \brief Creates a software generic PRACH demodulator. /// \param[in] dft_factory DFT factory. /// \param[in] srate Sampling rate. +/// \param[in] fr Frequency range. std::shared_ptr -create_ofdm_prach_demodulator_factory_sw(std::shared_ptr dft_factory, sampling_rate srate); +create_ofdm_prach_demodulator_factory_sw(std::shared_ptr dft_factory, + sampling_rate srate, + frequency_range fr); } // namespace srsran diff --git a/include/srsran/phy/lower/modulation/ofdm_prach_demodulator.h b/include/srsran/phy/lower/modulation/ofdm_prach_demodulator.h index 5d3eb84501..465f15b5b8 100644 --- a/include/srsran/phy/lower/modulation/ofdm_prach_demodulator.h +++ b/include/srsran/phy/lower/modulation/ofdm_prach_demodulator.h @@ -12,7 +12,7 @@ #include "srsran/phy/support/prach_buffer.h" #include "srsran/ran/prach/prach_format_type.h" -#include "srsran/ran/subcarrier_spacing.h" +#include "srsran/ran/slot_point.h" namespace srsran { @@ -26,6 +26,10 @@ class ofdm_prach_demodulator public: /// Collects the necessary parameters to demodulate PRACH frequency- and time-domain occasions within a slot. struct configuration { + /// \brief OFDM slot in which the PRACH window starts. + /// + /// The slot contains uplink resource grid subcarrier spacing. Expresses the numerology \f$\mu\f$. + slot_point slot; /// PRACH preamble format. prach_format_type format; /// Number of time-domain occasions. @@ -38,8 +42,6 @@ class ofdm_prach_demodulator unsigned rb_offset; /// Uplink resource grid size (see \ref prach_buffer_context::nof_prb_ul_grid). unsigned nof_prb_ul_grid; - /// Uplink resource grid subcarrier spacing. Expresses the numerology \f$\mu\f$. - subcarrier_spacing pusch_scs; /// Destination port identifier. unsigned port; }; @@ -64,4 +66,4 @@ class ofdm_prach_demodulator /// \param[in] config PRACH demodulator configuration parameters. virtual void demodulate(prach_buffer& buffer, span input, const configuration& config) = 0; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/phy/generic_functions/dft_processor_generic_impl.cpp b/lib/phy/generic_functions/dft_processor_generic_impl.cpp index 9f22564fba..d489e14678 100644 --- a/lib/phy/generic_functions/dft_processor_generic_impl.cpp +++ b/lib/phy/generic_functions/dft_processor_generic_impl.cpp @@ -208,12 +208,14 @@ dft_processor_generic_impl::dft_processor_generic_impl(const configuration& dft_ CREATE_GENERIC_DFT_DIT(4096); CREATE_GENERIC_DFT_DIT(4608); CREATE_GENERIC_DFT_DIT(6144); + CREATE_GENERIC_DFT_DIT(8192); CREATE_GENERIC_DFT_DIT(9216); CREATE_GENERIC_DFT_DIT(12288); CREATE_GENERIC_DFT_DIT(18432); CREATE_GENERIC_DFT_DIT(24576); CREATE_GENERIC_DFT_DIT(36864); CREATE_GENERIC_DFT_DIT(49152); + CREATE_GENERIC_DFT_DIT(98304); } span dft_processor_generic_impl::run() diff --git a/lib/phy/lower/modulation/modulation_factories.cpp b/lib/phy/lower/modulation/modulation_factories.cpp index 27f6e2e750..705e712aee 100644 --- a/lib/phy/lower/modulation/modulation_factories.cpp +++ b/lib/phy/lower/modulation/modulation_factories.cpp @@ -78,27 +78,50 @@ class ofdm_prach_demodulator_factory_sw : public ofdm_prach_demodulator_factory private: std::shared_ptr dft_factory; sampling_rate srate; + frequency_range fr; + + static constexpr std::array fr1_prach_scs = {prach_subcarrier_spacing::kHz15, + prach_subcarrier_spacing::kHz30, + prach_subcarrier_spacing::kHz60, + prach_subcarrier_spacing::kHz1_25, + prach_subcarrier_spacing::kHz5}; + + static constexpr std::array fr2_prach_scs = {prach_subcarrier_spacing::kHz120}; public: - ofdm_prach_demodulator_factory_sw(std::shared_ptr dft_factory_, sampling_rate srate_) : - dft_factory(std::move(dft_factory_)), srate(srate_) + ofdm_prach_demodulator_factory_sw(std::shared_ptr dft_factory_, + sampling_rate srate_, + frequency_range fr_) : + dft_factory(std::move(dft_factory_)), srate(srate_), fr(fr_) { srsran_assert(dft_factory, "Invalid DFT factory."); } std::unique_ptr create() override { - using int_type = std::underlying_type_t; + // Select set of valid PRACH subcarrier spacing for the given frequency range. This avoids having extremely large + // unused DFTs. + span possible_prach_scs = (fr == frequency_range::FR1) + ? span(fr1_prach_scs) + : span(fr2_prach_scs); + ofdm_prach_demodulator_impl::dft_processors_table dft_processors; - for (int_type i_scs = static_cast(prach_subcarrier_spacing::kHz15), - i_scs_end = static_cast(prach_subcarrier_spacing::invalid); - i_scs != i_scs_end; - ++i_scs) { - prach_subcarrier_spacing ra_scs = static_cast(i_scs); - dft_processor::configuration dft_config = {.size = srate.get_dft_size(ra_scs_to_Hz(ra_scs)), - .dir = dft_processor::direction::DIRECT}; - dft_processors.emplace(ra_scs, dft_factory->create(dft_config)); + + for (prach_subcarrier_spacing ra_scs : possible_prach_scs) { + // Create DFT for the given PRACH subcarrier spacing. + dft_processor::configuration dft_config = {.size = srate.get_dft_size(ra_scs_to_Hz(ra_scs)), + .dir = dft_processor::direction::DIRECT}; + std::unique_ptr dft_proc = dft_factory->create(dft_config); + srsran_assert(dft_proc, + "Invalid DFT processor of size {}, for subcarrier spacing of {} and sampling rate {}.", + dft_config.size, + to_string(ra_scs), + srate); + + // Emplace the DFT into the dictionary. + dft_processors.emplace(ra_scs, std::move(dft_proc)); } + return std::make_unique(srate, std::move(dft_processors)); } }; @@ -119,7 +142,8 @@ srsran::create_ofdm_demodulator_factory_generic(ofdm_factory_generic_configurati std::shared_ptr srsran::create_ofdm_prach_demodulator_factory_sw(std::shared_ptr dft_factory, - sampling_rate srate) + sampling_rate srate, + frequency_range fr) { - return std::make_shared(std::move(dft_factory), srate); + return std::make_shared(std::move(dft_factory), srate, fr); } diff --git a/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp b/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp index be518186a1..9bc9e2a748 100644 --- a/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp +++ b/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.cpp @@ -24,14 +24,20 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& // Cyclic prefix extension for short preambles at 0 and 0.5 ms from the start of the subframe. static constexpr phy_time_unit sixteen_kappa = phy_time_unit::from_units_of_kappa(16); + // Assumes that each slot has 14 OFDM symbols. + static constexpr unsigned nof_ofdm_symbols_slot = 14; + + // Deduce PUSCH subcarrier spacing. + subcarrier_spacing pusch_scs = to_subcarrier_spacing(config.slot.numerology()); + unsigned pusch_scs_Hz = scs_to_khz(pusch_scs) * 1000; + // PUSCH symbol duration. - phy_time_unit pusch_symbol_duration = - phy_time_unit::from_units_of_kappa((144U + 2048U) >> to_numerology_value(config.pusch_scs)); + phy_time_unit pusch_symbol_duration = phy_time_unit::from_units_of_kappa((144U + 2048U) >> config.slot.numerology()); // Validate configuration. if (is_short_preamble(config.format)) { unsigned prach_window_length = - get_prach_window_duration(config.format, config.pusch_scs, config.start_symbol, config.nof_td_occasions) + get_prach_window_duration(config.format, pusch_scs, config.start_symbol, config.nof_td_occasions) .to_samples(srate.to_Hz()); srsran_assert( input.size() >= prach_window_length, @@ -62,42 +68,49 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& // Get preamble information for the time occasion. prach_preamble_information preamble_info = - is_long_preamble(config.format) ? get_prach_preamble_long_info(config.format) - : get_prach_preamble_short_info(config.format, - to_ra_subcarrier_spacing(config.pusch_scs), - is_last_occasion); - - unsigned pusch_scs_Hz = scs_to_khz(config.pusch_scs) * 1000; + is_long_preamble(config.format) + ? get_prach_preamble_long_info(config.format) + : get_prach_preamble_short_info(config.format, to_ra_subcarrier_spacing(pusch_scs), is_last_occasion); // Calculate time-domain occasion symbol start. unsigned t_occasion_start_symbol = config.start_symbol + get_preamble_duration(config.format) * i_td_occasion; - // Calculate time-domain occasion start time. + // Calculate time-domain occasion start time relative to the beginning of the slot. phy_time_unit t_occasion_start = pusch_symbol_duration * t_occasion_start_symbol; - // Add sixteen kappa units if the symbol doesn't start at the beginning of the slot. - if (t_occasion_start > phy_time_unit::from_seconds(0.0)) { - t_occasion_start += sixteen_kappa; - } + // Calculate the slot start time within the subframe. + phy_time_unit t_slot_start = pusch_symbol_duration * config.slot.subframe_slot_index() * nof_ofdm_symbols_slot; - // Add sixteen kappa units if the symbol starts more than 0.5 ms after the beginning of the slot. - if (t_occasion_start > phy_time_unit::from_seconds(0.5e-3)) { - t_occasion_start += sixteen_kappa; + // Calculate time-domain occasion start time relative to the beginning of the subframe. + phy_time_unit t_ra_start = t_occasion_start + t_slot_start; + + // Apply correction of the beginning of the window for 1.25, 5, 15 and 30kHz subcarrier spacing. + if ((preamble_info.scs == prach_subcarrier_spacing::kHz1_25) || + (preamble_info.scs == prach_subcarrier_spacing::kHz5) || + (preamble_info.scs == prach_subcarrier_spacing::kHz15) || + (preamble_info.scs == prach_subcarrier_spacing::kHz30)) { + // Add sixteen kappa units if the symbol doesn't start at the beginning of the slot. + if (t_occasion_start > phy_time_unit::from_seconds(0.0)) { + t_occasion_start += sixteen_kappa; + } + + // Add sixteen kappa units if the symbol starts more than 0.5 ms after the beginning of the slot. + if (t_occasion_start > phy_time_unit::from_seconds(0.5e-3)) { + t_occasion_start += sixteen_kappa; + } } // Calculate time-domain occasion end time. - phy_time_unit t_occasion_end = t_occasion_start + preamble_info.cp_length + preamble_info.symbol_length(); + phy_time_unit t_ra_end = t_ra_start + preamble_info.cp_length + preamble_info.symbol_length(); // Add sixteen kappa to the cyclic prefix length if ... if (is_short_preamble(preamble_info.scs)) { // The occasion overlaps with time zero. - if ((t_occasion_start <= phy_time_unit::from_seconds(0.0)) && - (t_occasion_end >= phy_time_unit::from_seconds(0.0))) { + if ((t_ra_start <= phy_time_unit::from_seconds(0.0)) && (t_ra_end >= phy_time_unit::from_seconds(0.0))) { preamble_info.cp_length += sixteen_kappa; } - // The occasion overlaps with time 0.5ms from the beginning of the slot. - if ((t_occasion_start <= phy_time_unit::from_seconds(0.5e-3)) && - (t_occasion_end >= phy_time_unit::from_seconds(0.5e-3))) { + // The occasion overlaps with time 0.5ms from the beginning of the subframe. + if ((t_ra_start <= phy_time_unit::from_seconds(0.5e-3)) && (t_ra_end >= phy_time_unit::from_seconds(0.5e-3))) { preamble_info.cp_length += sixteen_kappa; } } @@ -105,6 +118,7 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& // Calculate occasion duration. phy_time_unit occasion_duration = preamble_info.cp_length + preamble_info.symbol_length(); + // Get the time occasion boundaries in samples. unsigned sample_offset = t_occasion_start.to_samples(srate.to_Hz()); unsigned nof_samples = occasion_duration.to_samples(srate.to_Hz()); @@ -112,8 +126,7 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& span input_occasion = input.subspan(sample_offset, nof_samples); // Get frequency mapping information, common for all frequency-domain occasions. - prach_frequency_mapping_information freq_mapping_info = - prach_frequency_mapping_get(preamble_info.scs, config.pusch_scs); + prach_frequency_mapping_information freq_mapping_info = prach_frequency_mapping_get(preamble_info.scs, pusch_scs); srsran_assert(freq_mapping_info.nof_rb_ra != PRACH_FREQUENCY_MAPPING_INFORMATION_RESERVED.nof_rb_ra, "The PRACH and PUSCH subcarrier spacing combination resulted in a reserved configuration."); srsran_assert(freq_mapping_info.k_bar != PRACH_FREQUENCY_MAPPING_INFORMATION_RESERVED.k_bar, @@ -189,4 +202,4 @@ void ofdm_prach_demodulator_impl::demodulate(prach_buffer& } } } -} \ No newline at end of file +} diff --git a/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.h b/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.h index 0beadaeed9..7ef2144399 100644 --- a/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.h +++ b/lib/phy/lower/modulation/ofdm_prach_demodulator_impl.h @@ -38,23 +38,9 @@ class ofdm_prach_demodulator_impl : public ofdm_prach_demodulator ofdm_prach_demodulator_impl(sampling_rate srate_, dft_processors_table dft_processors_) : srate(srate_), dft_processors(std::move(dft_processors_)) { - using int_type = std::underlying_type_t; - for (int_type i_scs = static_cast(prach_subcarrier_spacing::kHz15), - i_scs_end = static_cast(prach_subcarrier_spacing::invalid); - i_scs != i_scs_end; - ++i_scs) { - prach_subcarrier_spacing ra_scs = static_cast(i_scs); - srsran_assert(dft_processors.contains(ra_scs), - "Table does not contain a DFT processor for {} subcarrier spacing.", - to_string(ra_scs)); - srsran_assert(dft_processors[ra_scs], "Invalid DFT processor for {} subcarrier spacing.", to_string(ra_scs)); - srsran_assert(dft_processors[ra_scs]->get_direction() == dft_processor::direction::DIRECT, - "Invalid DFT processor direction for {} subcarrier spacing.", - to_string(ra_scs)); - srsran_assert(dft_processors[ra_scs]->get_size() == srate.get_dft_size(ra_scs_to_Hz(ra_scs)), - "Invalid DFT processor size (i.e., {}) for {} subcarrier spacing.", - dft_processors[ra_scs]->get_size(), - to_string(ra_scs)); + for (const auto& dft_proc : dft_processors) { + srsran_assert(dft_proc, "Invalid DFT processor."); + srsran_assert(dft_proc->get_direction() == dft_processor::direction::DIRECT, "Invalid DFT processor direction."); } } diff --git a/lib/phy/lower/processors/uplink/prach/prach_processor_worker.cpp b/lib/phy/lower/processors/uplink/prach/prach_processor_worker.cpp index a1c7f858aa..19b834aa65 100644 --- a/lib/phy/lower/processors/uplink/prach/prach_processor_worker.cpp +++ b/lib/phy/lower/processors/uplink/prach/prach_processor_worker.cpp @@ -101,13 +101,13 @@ void prach_processor_worker::accumulate_samples(const baseband_gateway_buffer_re for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { // Prepare PRACH demodulator configuration. ofdm_prach_demodulator::configuration config; + config.slot = prach_context.slot; config.format = prach_context.format; config.nof_td_occasions = prach_context.nof_td_occasions; config.nof_fd_occasions = prach_context.nof_fd_occasions; config.start_symbol = prach_context.start_symbol; config.rb_offset = prach_context.rb_offset; config.nof_prb_ul_grid = prach_context.nof_prb_ul_grid; - config.pusch_scs = prach_context.pusch_scs; config.port = i_port; // Make a view of the first samples in the buffer. diff --git a/lib/ru/generic/lower_phy_factory.h b/lib/ru/generic/lower_phy_factory.h index f05ea9f5cb..35bde3735f 100644 --- a/lib/ru/generic/lower_phy_factory.h +++ b/lib/ru/generic/lower_phy_factory.h @@ -23,6 +23,12 @@ class task_executor; inline std::shared_ptr create_lower_phy_factory(lower_phy_configuration& config, unsigned max_nof_prach_concurrent_requests) { + // Deduce frequency range from the subcarrier spacing. + frequency_range fr = frequency_range::FR1; + if (config.scs > subcarrier_spacing::kHz60) { + fr = frequency_range::FR2; + } + // Get the maximum number of receive ports. unsigned max_nof_rx_ports = std::max_element(config.sectors.begin(), @@ -53,7 +59,7 @@ inline std::shared_ptr create_lower_phy_factory(lower_phy_con // Create OFDM PRACH demodulator factory. std::shared_ptr prach_demodulator_factory = - create_ofdm_prach_demodulator_factory_sw(dft_factory, config.srate); + create_ofdm_prach_demodulator_factory_sw(dft_factory, config.srate, fr); report_fatal_error_if_not(prach_demodulator_factory, "Failed to create PRACH demodulator factory."); // Create PDxCH processor factory. diff --git a/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.h b/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.h index de650440b2..5560fd4e80 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.h +++ b/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 14-09-2023 (seed 0): +// This file was generated using the following MATLAB class on 30-07-2024 (seed 0): // + "srsOFDMDemodulatorUnittest.m" #include "srsran/phy/lower/modulation/ofdm_demodulator.h" @@ -52,6 +52,11 @@ static const std::vector ofdm_demodulator_test_data = { {{{2, 96, 2048, cyclic_prefix::EXTENDED, 9, -0.24786, 587300000}, 5, 1}, {"test_data/ofdm_demodulator_test_input17.dat"}, {"test_data/ofdm_demodulator_test_output17.dat"}}, {{{2, 192, 4096, cyclic_prefix::NORMAL, 138, 0.79273, 409800000}, 11, 0}, {"test_data/ofdm_demodulator_test_input18.dat"}, {"test_data/ofdm_demodulator_test_output18.dat"}}, {{{2, 192, 4096, cyclic_prefix::EXTENDED, 129, -0.5615, 2965400000}, 8, 3}, {"test_data/ofdm_demodulator_test_input19.dat"}, {"test_data/ofdm_demodulator_test_output19.dat"}}, + {{{3, 12, 256, cyclic_prefix::NORMAL, 8, -0.20632, 1101900000}, 4, 1}, {"test_data/ofdm_demodulator_test_input20.dat"}, {"test_data/ofdm_demodulator_test_output20.dat"}}, + {{{3, 24, 512, cyclic_prefix::NORMAL, 8, -0.52499, 2907500000}, 2, 4}, {"test_data/ofdm_demodulator_test_input21.dat"}, {"test_data/ofdm_demodulator_test_output21.dat"}}, + {{{3, 48, 1024, cyclic_prefix::NORMAL, 18, 0.34035, 2073300000}, 9, 7}, {"test_data/ofdm_demodulator_test_input22.dat"}, {"test_data/ofdm_demodulator_test_output22.dat"}}, + {{{3, 96, 2048, cyclic_prefix::NORMAL, 43, 0.90053, 2675800000}, 8, 1}, {"test_data/ofdm_demodulator_test_input23.dat"}, {"test_data/ofdm_demodulator_test_output23.dat"}}, + {{{3, 192, 4096, cyclic_prefix::NORMAL, 132, 0.9089, 1736000000}, 14, 4}, {"test_data/ofdm_demodulator_test_input24.dat"}, {"test_data/ofdm_demodulator_test_output24.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.tar.gz b/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.tar.gz index 1ca85fd46f..587df84f59 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.tar.gz +++ b/tests/unittests/phy/lower/modulation/ofdm_demodulator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e2f4411d3e815d99a42aef544de3e1deddc7c968875000e7805597181addbea -size 5839035 +oid sha256:e2df4f3b3897a98999c95e94c9419134832fc54b42aef473d3ecadbfc53d052b +size 7338566 diff --git a/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.h b/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.h index 5de8b2f3b7..456f7b2a8a 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.h +++ b/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 27-06-2024 (seed 0): +// This file was generated using the following MATLAB class on 30-07-2024 (seed 0): // + "srsOFDMModulatorUnittest.m" #include "srsran/phy/lower/modulation/ofdm_modulator.h" @@ -52,6 +52,11 @@ static const std::vector ofdm_modulator_test_data = { {{{2, 96, 2048, cyclic_prefix::EXTENDED, -0.93258, 2059300000}, 14, 3}, {"test_data/ofdm_modulator_test_input17.dat"}, {"test_data/ofdm_modulator_test_output17.dat"}}, {{{2, 192, 4096, cyclic_prefix::NORMAL, -0.10732, 76300000}, 5, 1}, {"test_data/ofdm_modulator_test_input18.dat"}, {"test_data/ofdm_modulator_test_output18.dat"}}, {{{2, 192, 4096, cyclic_prefix::EXTENDED, -0.82195, 605900000}, 3, 2}, {"test_data/ofdm_modulator_test_input19.dat"}, {"test_data/ofdm_modulator_test_output19.dat"}}, + {{{3, 12, 256, cyclic_prefix::NORMAL, -0.12962, 965500000}, 12, 5}, {"test_data/ofdm_modulator_test_input20.dat"}, {"test_data/ofdm_modulator_test_output20.dat"}}, + {{{3, 24, 512, cyclic_prefix::NORMAL, -0.64413, 2770200000}, 5, 2}, {"test_data/ofdm_modulator_test_input21.dat"}, {"test_data/ofdm_modulator_test_output21.dat"}}, + {{{3, 48, 1024, cyclic_prefix::NORMAL, -0.64012, 622100000}, 9, 2}, {"test_data/ofdm_modulator_test_input22.dat"}, {"test_data/ofdm_modulator_test_output22.dat"}}, + {{{3, 96, 2048, cyclic_prefix::NORMAL, -0.91491, 253100000}, 6, 2}, {"test_data/ofdm_modulator_test_input23.dat"}, {"test_data/ofdm_modulator_test_output23.dat"}}, + {{{3, 192, 4096, cyclic_prefix::NORMAL, 0.73052, 2633100000}, 10, 6}, {"test_data/ofdm_modulator_test_input24.dat"}, {"test_data/ofdm_modulator_test_output24.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.tar.gz b/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.tar.gz index 9044548778..f88a767afe 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.tar.gz +++ b/tests/unittests/phy/lower/modulation/ofdm_modulator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea539026b2258f3f4f9eea4338435bed20e64a4a3eed866a3ad1533d1966f8b5 -size 5836965 +oid sha256:e6b576bdef5021aef989719535878fb2c68ae701aa27f8005ed8909f77d23154 +size 7334347 diff --git a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp index 8a1d16eb45..5114702ca9 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp +++ b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test.cpp @@ -37,15 +37,16 @@ static bool operator==(span lhs, span rhs) std::ostream& operator<<(std::ostream& os, const ofdm_prach_demodulator::configuration& config) { fmt::print(os, - "Format={}; nof_td_occasions={}; nof_fd_occasions={}; start_symbol={}; rb_offset={}; " + "slot={}; Format={}; nof_td_occasions={}; nof_fd_occasions={}; start_symbol={}; rb_offset={}; " "nof_prb_ul_grid={}; pusch_scs={};", + config.slot, to_string(config.format), config.nof_td_occasions, config.nof_fd_occasions, config.start_symbol, config.rb_offset, config.nof_prb_ul_grid, - to_string(config.pusch_scs)); + to_string(to_subcarrier_spacing(config.slot.numerology()))); return os; } @@ -66,13 +67,19 @@ class ofdm_prach_demodulator_tester : public ::testing::TestWithParam subcarrier_spacing::kHz60) { + fr = frequency_range::FR2; + } std::shared_ptr dft_factory = create_dft_processor_factory_generic(); ASSERT_TRUE(dft_factory); std::shared_ptr ofdm_factory = - create_ofdm_prach_demodulator_factory_sw(dft_factory, srate); + create_ofdm_prach_demodulator_factory_sw(dft_factory, srate, fr); ASSERT_TRUE(ofdm_factory); demodulator = ofdm_factory->create(); @@ -84,6 +91,7 @@ TEST_P(ofdm_prach_demodulator_tester, vector) { const test_case_t& test_case = GetParam(); const ofdm_prach_demodulator::configuration& config = test_case.context.config; + subcarrier_spacing pusch_scs = to_subcarrier_spacing(GetParam().context.config.slot.numerology()); bool long_preamble = is_long_preamble(config.format); std::unique_ptr output = @@ -99,7 +107,7 @@ TEST_P(ofdm_prach_demodulator_tester, vector) // Select preamble information. prach_preamble_information preamble_info = long_preamble ? get_prach_preamble_long_info(config.format) - : get_prach_preamble_short_info(config.format, to_ra_subcarrier_spacing(config.pusch_scs), false); + : get_prach_preamble_short_info(config.format, to_ra_subcarrier_spacing(pusch_scs), false); // Calculate number of symbols. unsigned nof_symbols = preamble_info.nof_symbols; @@ -117,7 +125,12 @@ TEST_P(ofdm_prach_demodulator_tester, vector) for (unsigned i_fd_occasion = 0; i_fd_occasion != config.nof_fd_occasions; ++i_fd_occasion) { for (unsigned i_symbol = 0; i_symbol != nof_symbols; ++i_symbol) { ASSERT_EQ(span(expected_buffer.get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol)), - span(output->get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol))); + span(output->get_symbol(i_port, i_td_occasion, i_fd_occasion, i_symbol))) + << fmt::format("i_port={}; i_td_occasion={}; i_fd_occasion={}; i_symbol={};", + i_port, + i_td_occasion, + i_fd_occasion, + i_symbol); } } } diff --git a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.h b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.h index 987b4834a0..fb0f2b65a2 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.h +++ b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 14-09-2023 (seed 0): +// This file was generated using the following MATLAB class on 01-08-2024 (seed 0): // + "srsPRACHDemodulatorUnittest.m" #include "srsran/phy/lower/modulation/ofdm_prach_demodulator.h" @@ -32,118 +32,54 @@ struct test_case_t { static const std::vector ofdm_prach_demodulator_test_data = { // clang-format off - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("0"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input0.dat"}, {"test_data/ofdm_prach_demodulator_test_output0.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("0"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input1.dat"}, {"test_data/ofdm_prach_demodulator_test_output1.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("1"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input2.dat"}, {"test_data/ofdm_prach_demodulator_test_output2.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("1"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input3.dat"}, {"test_data/ofdm_prach_demodulator_test_output3.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("2"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input4.dat"}, {"test_data/ofdm_prach_demodulator_test_output4.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("2"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input5.dat"}, {"test_data/ofdm_prach_demodulator_test_output5.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("3"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input6.dat"}, {"test_data/ofdm_prach_demodulator_test_output6.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("3"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input7.dat"}, {"test_data/ofdm_prach_demodulator_test_output7.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1"), 6, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input8.dat"}, {"test_data/ofdm_prach_demodulator_test_output8.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1"), 6, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input9.dat"}, {"test_data/ofdm_prach_demodulator_test_output9.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1/B1"), 7, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input10.dat"}, {"test_data/ofdm_prach_demodulator_test_output10.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1/B1"), 7, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input11.dat"}, {"test_data/ofdm_prach_demodulator_test_output11.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2"), 3, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input12.dat"}, {"test_data/ofdm_prach_demodulator_test_output12.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2"), 3, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input13.dat"}, {"test_data/ofdm_prach_demodulator_test_output13.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2/B2"), 3, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input14.dat"}, {"test_data/ofdm_prach_demodulator_test_output14.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2/B2"), 3, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input15.dat"}, {"test_data/ofdm_prach_demodulator_test_output15.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3"), 2, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input16.dat"}, {"test_data/ofdm_prach_demodulator_test_output16.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3"), 2, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input17.dat"}, {"test_data/ofdm_prach_demodulator_test_output17.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3/B3"), 2, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input18.dat"}, {"test_data/ofdm_prach_demodulator_test_output18.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3/B3"), 2, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input19.dat"}, {"test_data/ofdm_prach_demodulator_test_output19.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B1"), 7, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input20.dat"}, {"test_data/ofdm_prach_demodulator_test_output20.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B1"), 7, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input21.dat"}, {"test_data/ofdm_prach_demodulator_test_output21.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B4"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input22.dat"}, {"test_data/ofdm_prach_demodulator_test_output22.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B4"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input23.dat"}, {"test_data/ofdm_prach_demodulator_test_output23.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C0"), 7, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input24.dat"}, {"test_data/ofdm_prach_demodulator_test_output24.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C0"), 7, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input25.dat"}, {"test_data/ofdm_prach_demodulator_test_output25.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C2"), 2, 2, 0, 0, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input26.dat"}, {"test_data/ofdm_prach_demodulator_test_output26.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C2"), 2, 2, 0, 2, 79, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input27.dat"}, {"test_data/ofdm_prach_demodulator_test_output27.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("0"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input28.dat"}, {"test_data/ofdm_prach_demodulator_test_output28.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("0"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input29.dat"}, {"test_data/ofdm_prach_demodulator_test_output29.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("1"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input30.dat"}, {"test_data/ofdm_prach_demodulator_test_output30.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("1"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input31.dat"}, {"test_data/ofdm_prach_demodulator_test_output31.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("2"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input32.dat"}, {"test_data/ofdm_prach_demodulator_test_output32.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("2"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input33.dat"}, {"test_data/ofdm_prach_demodulator_test_output33.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("3"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input34.dat"}, {"test_data/ofdm_prach_demodulator_test_output34.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("3"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input35.dat"}, {"test_data/ofdm_prach_demodulator_test_output35.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1"), 6, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input36.dat"}, {"test_data/ofdm_prach_demodulator_test_output36.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1"), 6, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input37.dat"}, {"test_data/ofdm_prach_demodulator_test_output37.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1/B1"), 7, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input38.dat"}, {"test_data/ofdm_prach_demodulator_test_output38.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A1/B1"), 7, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input39.dat"}, {"test_data/ofdm_prach_demodulator_test_output39.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2"), 3, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input40.dat"}, {"test_data/ofdm_prach_demodulator_test_output40.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2"), 3, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input41.dat"}, {"test_data/ofdm_prach_demodulator_test_output41.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2/B2"), 3, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input42.dat"}, {"test_data/ofdm_prach_demodulator_test_output42.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A2/B2"), 3, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input43.dat"}, {"test_data/ofdm_prach_demodulator_test_output43.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3"), 2, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input44.dat"}, {"test_data/ofdm_prach_demodulator_test_output44.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3"), 2, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input45.dat"}, {"test_data/ofdm_prach_demodulator_test_output45.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3/B3"), 2, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input46.dat"}, {"test_data/ofdm_prach_demodulator_test_output46.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("A3/B3"), 2, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input47.dat"}, {"test_data/ofdm_prach_demodulator_test_output47.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B1"), 7, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input48.dat"}, {"test_data/ofdm_prach_demodulator_test_output48.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B1"), 7, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input49.dat"}, {"test_data/ofdm_prach_demodulator_test_output49.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B4"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input50.dat"}, {"test_data/ofdm_prach_demodulator_test_output50.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("B4"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input51.dat"}, {"test_data/ofdm_prach_demodulator_test_output51.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C0"), 7, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input52.dat"}, {"test_data/ofdm_prach_demodulator_test_output52.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C0"), 7, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input53.dat"}, {"test_data/ofdm_prach_demodulator_test_output53.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C2"), 2, 2, 0, 0, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input54.dat"}, {"test_data/ofdm_prach_demodulator_test_output54.dat"}}, - {{sampling_rate::from_MHz(30.72), {to_prach_format_type("C2"), 2, 2, 0, 2, 106, subcarrier_spacing::kHz15}}, {"test_data/ofdm_prach_demodulator_test_input55.dat"}, {"test_data/ofdm_prach_demodulator_test_output55.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("0"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input56.dat"}, {"test_data/ofdm_prach_demodulator_test_output56.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("0"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input57.dat"}, {"test_data/ofdm_prach_demodulator_test_output57.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("1"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input58.dat"}, {"test_data/ofdm_prach_demodulator_test_output58.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("1"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input59.dat"}, {"test_data/ofdm_prach_demodulator_test_output59.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("2"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input60.dat"}, {"test_data/ofdm_prach_demodulator_test_output60.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("2"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input61.dat"}, {"test_data/ofdm_prach_demodulator_test_output61.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("3"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input62.dat"}, {"test_data/ofdm_prach_demodulator_test_output62.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("3"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input63.dat"}, {"test_data/ofdm_prach_demodulator_test_output63.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1"), 6, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input64.dat"}, {"test_data/ofdm_prach_demodulator_test_output64.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1"), 6, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input65.dat"}, {"test_data/ofdm_prach_demodulator_test_output65.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1/B1"), 6, 2, 2, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input66.dat"}, {"test_data/ofdm_prach_demodulator_test_output66.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1/B1"), 6, 2, 2, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input67.dat"}, {"test_data/ofdm_prach_demodulator_test_output67.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2"), 3, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input68.dat"}, {"test_data/ofdm_prach_demodulator_test_output68.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2"), 3, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input69.dat"}, {"test_data/ofdm_prach_demodulator_test_output69.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2/B2"), 3, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input70.dat"}, {"test_data/ofdm_prach_demodulator_test_output70.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2/B2"), 3, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input71.dat"}, {"test_data/ofdm_prach_demodulator_test_output71.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3"), 2, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input72.dat"}, {"test_data/ofdm_prach_demodulator_test_output72.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3"), 2, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input73.dat"}, {"test_data/ofdm_prach_demodulator_test_output73.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3/B3"), 2, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input74.dat"}, {"test_data/ofdm_prach_demodulator_test_output74.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3/B3"), 2, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input75.dat"}, {"test_data/ofdm_prach_demodulator_test_output75.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B1"), 6, 2, 2, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input76.dat"}, {"test_data/ofdm_prach_demodulator_test_output76.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B1"), 6, 2, 2, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input77.dat"}, {"test_data/ofdm_prach_demodulator_test_output77.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B4"), 1, 2, 0, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input78.dat"}, {"test_data/ofdm_prach_demodulator_test_output78.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B4"), 1, 2, 0, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input79.dat"}, {"test_data/ofdm_prach_demodulator_test_output79.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C0"), 6, 2, 2, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input80.dat"}, {"test_data/ofdm_prach_demodulator_test_output80.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C0"), 6, 2, 2, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input81.dat"}, {"test_data/ofdm_prach_demodulator_test_output81.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C2"), 2, 2, 2, 0, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input82.dat"}, {"test_data/ofdm_prach_demodulator_test_output82.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C2"), 2, 2, 2, 2, 79, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input83.dat"}, {"test_data/ofdm_prach_demodulator_test_output83.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("0"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input84.dat"}, {"test_data/ofdm_prach_demodulator_test_output84.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("0"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input85.dat"}, {"test_data/ofdm_prach_demodulator_test_output85.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("1"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input86.dat"}, {"test_data/ofdm_prach_demodulator_test_output86.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("1"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input87.dat"}, {"test_data/ofdm_prach_demodulator_test_output87.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("2"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input88.dat"}, {"test_data/ofdm_prach_demodulator_test_output88.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("2"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input89.dat"}, {"test_data/ofdm_prach_demodulator_test_output89.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("3"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input90.dat"}, {"test_data/ofdm_prach_demodulator_test_output90.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("3"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input91.dat"}, {"test_data/ofdm_prach_demodulator_test_output91.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1"), 6, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input92.dat"}, {"test_data/ofdm_prach_demodulator_test_output92.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1"), 6, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input93.dat"}, {"test_data/ofdm_prach_demodulator_test_output93.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1/B1"), 6, 2, 2, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input94.dat"}, {"test_data/ofdm_prach_demodulator_test_output94.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A1/B1"), 6, 2, 2, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input95.dat"}, {"test_data/ofdm_prach_demodulator_test_output95.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2"), 3, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input96.dat"}, {"test_data/ofdm_prach_demodulator_test_output96.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2"), 3, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input97.dat"}, {"test_data/ofdm_prach_demodulator_test_output97.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2/B2"), 3, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input98.dat"}, {"test_data/ofdm_prach_demodulator_test_output98.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A2/B2"), 3, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input99.dat"}, {"test_data/ofdm_prach_demodulator_test_output99.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3"), 2, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input100.dat"}, {"test_data/ofdm_prach_demodulator_test_output100.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3"), 2, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input101.dat"}, {"test_data/ofdm_prach_demodulator_test_output101.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3/B3"), 2, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input102.dat"}, {"test_data/ofdm_prach_demodulator_test_output102.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("A3/B3"), 2, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input103.dat"}, {"test_data/ofdm_prach_demodulator_test_output103.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B1"), 6, 2, 2, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input104.dat"}, {"test_data/ofdm_prach_demodulator_test_output104.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B1"), 6, 2, 2, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input105.dat"}, {"test_data/ofdm_prach_demodulator_test_output105.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B4"), 1, 2, 0, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input106.dat"}, {"test_data/ofdm_prach_demodulator_test_output106.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("B4"), 1, 2, 0, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input107.dat"}, {"test_data/ofdm_prach_demodulator_test_output107.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C0"), 6, 2, 2, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input108.dat"}, {"test_data/ofdm_prach_demodulator_test_output108.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C0"), 6, 2, 2, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input109.dat"}, {"test_data/ofdm_prach_demodulator_test_output109.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C2"), 2, 2, 2, 0, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input110.dat"}, {"test_data/ofdm_prach_demodulator_test_output110.dat"}}, - {{sampling_rate::from_MHz(61.44), {to_prach_format_type("C2"), 2, 2, 2, 2, 106, subcarrier_spacing::kHz30}}, {"test_data/ofdm_prach_demodulator_test_input111.dat"}, {"test_data/ofdm_prach_demodulator_test_output111.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 4}, to_prach_format_type("B4"), 1, 2, 0, 0, 79}}, {"test_data/ofdm_prach_demodulator_test_input0.dat"}, {"test_data/ofdm_prach_demodulator_test_output0.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 14}, to_prach_format_type("A3"), 2, 2, 0, 2, 79}}, {"test_data/ofdm_prach_demodulator_test_input1.dat"}, {"test_data/ofdm_prach_demodulator_test_output1.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 2}, to_prach_format_type("2"), 1, 2, 0, 4, 79}}, {"test_data/ofdm_prach_demodulator_test_input2.dat"}, {"test_data/ofdm_prach_demodulator_test_output2.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 4}, to_prach_format_type("B4"), 1, 2, 0, 10, 79}}, {"test_data/ofdm_prach_demodulator_test_input3.dat"}, {"test_data/ofdm_prach_demodulator_test_output3.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 4}, to_prach_format_type("B4"), 1, 2, 0, 0, 106}}, {"test_data/ofdm_prach_demodulator_test_input4.dat"}, {"test_data/ofdm_prach_demodulator_test_output4.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 4}, to_prach_format_type("B4"), 1, 2, 0, 2, 106}}, {"test_data/ofdm_prach_demodulator_test_input5.dat"}, {"test_data/ofdm_prach_demodulator_test_output5.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 4}, to_prach_format_type("B1"), 7, 2, 0, 4, 106}}, {"test_data/ofdm_prach_demodulator_test_input6.dat"}, {"test_data/ofdm_prach_demodulator_test_output6.dat"}}, + {{sampling_rate::from_MHz(30.72), {{0, 4}, to_prach_format_type("B1"), 7, 2, 0, 10, 106}}, {"test_data/ofdm_prach_demodulator_test_input7.dat"}, {"test_data/ofdm_prach_demodulator_test_output7.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 14}, to_prach_format_type("A3"), 2, 2, 0, 0, 212}}, {"test_data/ofdm_prach_demodulator_test_input8.dat"}, {"test_data/ofdm_prach_demodulator_test_output8.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 14}, to_prach_format_type("C0"), 7, 2, 0, 2, 212}}, {"test_data/ofdm_prach_demodulator_test_input9.dat"}, {"test_data/ofdm_prach_demodulator_test_output9.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 4}, to_prach_format_type("A1"), 6, 2, 0, 4, 212}}, {"test_data/ofdm_prach_demodulator_test_input10.dat"}, {"test_data/ofdm_prach_demodulator_test_output10.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 14}, to_prach_format_type("C2"), 2, 2, 0, 10, 212}}, {"test_data/ofdm_prach_demodulator_test_input11.dat"}, {"test_data/ofdm_prach_demodulator_test_output11.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 2}, to_prach_format_type("2"), 1, 2, 0, 0, 275}}, {"test_data/ofdm_prach_demodulator_test_input12.dat"}, {"test_data/ofdm_prach_demodulator_test_output12.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 2}, to_prach_format_type("2"), 1, 2, 0, 2, 275}}, {"test_data/ofdm_prach_demodulator_test_input13.dat"}, {"test_data/ofdm_prach_demodulator_test_output13.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 12}, to_prach_format_type("A3/B3"), 2, 2, 0, 4, 275}}, {"test_data/ofdm_prach_demodulator_test_input14.dat"}, {"test_data/ofdm_prach_demodulator_test_output14.dat"}}, + {{sampling_rate::from_MHz(61.44), {{0, 2}, to_prach_format_type("2"), 1, 2, 0, 10, 275}}, {"test_data/ofdm_prach_demodulator_test_input15.dat"}, {"test_data/ofdm_prach_demodulator_test_output15.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 5}, to_prach_format_type("1"), 1, 2, 0, 0, 79}}, {"test_data/ofdm_prach_demodulator_test_input16.dat"}, {"test_data/ofdm_prach_demodulator_test_output16.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 19}, to_prach_format_type("0"), 1, 2, 0, 2, 79}}, {"test_data/ofdm_prach_demodulator_test_input17.dat"}, {"test_data/ofdm_prach_demodulator_test_output17.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 5}, to_prach_format_type("1"), 1, 2, 0, 4, 79}}, {"test_data/ofdm_prach_demodulator_test_input18.dat"}, {"test_data/ofdm_prach_demodulator_test_output18.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 39}, to_prach_format_type("A2"), 3, 2, 0, 10, 79}}, {"test_data/ofdm_prach_demodulator_test_input19.dat"}, {"test_data/ofdm_prach_demodulator_test_output19.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 39}, to_prach_format_type("A2/B2"), 3, 2, 0, 0, 106}}, {"test_data/ofdm_prach_demodulator_test_input20.dat"}, {"test_data/ofdm_prach_demodulator_test_output20.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 19}, to_prach_format_type("3"), 1, 2, 0, 2, 106}}, {"test_data/ofdm_prach_demodulator_test_input21.dat"}, {"test_data/ofdm_prach_demodulator_test_output21.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 39}, to_prach_format_type("A1/B1"), 6, 2, 2, 4, 106}}, {"test_data/ofdm_prach_demodulator_test_input22.dat"}, {"test_data/ofdm_prach_demodulator_test_output22.dat"}}, + {{sampling_rate::from_MHz(61.44), {{1, 5}, to_prach_format_type("1"), 1, 2, 0, 10, 106}}, {"test_data/ofdm_prach_demodulator_test_input23.dat"}, {"test_data/ofdm_prach_demodulator_test_output23.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 39}, to_prach_format_type("A3"), 2, 2, 0, 0, 212}}, {"test_data/ofdm_prach_demodulator_test_input24.dat"}, {"test_data/ofdm_prach_demodulator_test_output24.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 19}, to_prach_format_type("0"), 1, 2, 0, 2, 212}}, {"test_data/ofdm_prach_demodulator_test_input25.dat"}, {"test_data/ofdm_prach_demodulator_test_output25.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 39}, to_prach_format_type("A3/B3"), 2, 2, 0, 4, 212}}, {"test_data/ofdm_prach_demodulator_test_input26.dat"}, {"test_data/ofdm_prach_demodulator_test_output26.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 39}, to_prach_format_type("A3/B3"), 2, 2, 0, 10, 212}}, {"test_data/ofdm_prach_demodulator_test_input27.dat"}, {"test_data/ofdm_prach_demodulator_test_output27.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 39}, to_prach_format_type("C2"), 2, 2, 2, 0, 275}}, {"test_data/ofdm_prach_demodulator_test_input28.dat"}, {"test_data/ofdm_prach_demodulator_test_output28.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 39}, to_prach_format_type("A2/B2"), 3, 2, 0, 2, 275}}, {"test_data/ofdm_prach_demodulator_test_input29.dat"}, {"test_data/ofdm_prach_demodulator_test_output29.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 39}, to_prach_format_type("A1"), 6, 2, 0, 4, 275}}, {"test_data/ofdm_prach_demodulator_test_input30.dat"}, {"test_data/ofdm_prach_demodulator_test_output30.dat"}}, + {{sampling_rate::from_MHz(122.88), {{1, 19}, to_prach_format_type("3"), 1, 2, 0, 10, 275}}, {"test_data/ofdm_prach_demodulator_test_input31.dat"}, {"test_data/ofdm_prach_demodulator_test_output31.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("A3"), 2, 2, 0, 0, 79}}, {"test_data/ofdm_prach_demodulator_test_input32.dat"}, {"test_data/ofdm_prach_demodulator_test_output32.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("A2"), 3, 2, 0, 2, 79}}, {"test_data/ofdm_prach_demodulator_test_input33.dat"}, {"test_data/ofdm_prach_demodulator_test_output33.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("A2"), 3, 2, 0, 4, 79}}, {"test_data/ofdm_prach_demodulator_test_input34.dat"}, {"test_data/ofdm_prach_demodulator_test_output34.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("C2"), 2, 2, 0, 10, 79}}, {"test_data/ofdm_prach_demodulator_test_input35.dat"}, {"test_data/ofdm_prach_demodulator_test_output35.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("C2"), 2, 2, 0, 0, 106}}, {"test_data/ofdm_prach_demodulator_test_input36.dat"}, {"test_data/ofdm_prach_demodulator_test_output36.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("B1"), 6, 2, 2, 2, 106}}, {"test_data/ofdm_prach_demodulator_test_input37.dat"}, {"test_data/ofdm_prach_demodulator_test_output37.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("A1/B1"), 6, 2, 2, 4, 106}}, {"test_data/ofdm_prach_demodulator_test_input38.dat"}, {"test_data/ofdm_prach_demodulator_test_output38.dat"}}, + {{sampling_rate::from_MHz(245.76), {{3, 89}, to_prach_format_type("C2"), 2, 2, 0, 10, 106}}, {"test_data/ofdm_prach_demodulator_test_input39.dat"}, {"test_data/ofdm_prach_demodulator_test_output39.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("A1/B1"), 6, 2, 2, 0, 212}}, {"test_data/ofdm_prach_demodulator_test_input40.dat"}, {"test_data/ofdm_prach_demodulator_test_output40.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("A3/B3"), 2, 2, 2, 2, 212}}, {"test_data/ofdm_prach_demodulator_test_input41.dat"}, {"test_data/ofdm_prach_demodulator_test_output41.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("B1"), 6, 2, 2, 4, 212}}, {"test_data/ofdm_prach_demodulator_test_input42.dat"}, {"test_data/ofdm_prach_demodulator_test_output42.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("A1"), 6, 2, 0, 10, 212}}, {"test_data/ofdm_prach_demodulator_test_input43.dat"}, {"test_data/ofdm_prach_demodulator_test_output43.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("A3"), 2, 2, 0, 0, 275}}, {"test_data/ofdm_prach_demodulator_test_input44.dat"}, {"test_data/ofdm_prach_demodulator_test_output44.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("A2"), 3, 2, 0, 2, 275}}, {"test_data/ofdm_prach_demodulator_test_input45.dat"}, {"test_data/ofdm_prach_demodulator_test_output45.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("B1"), 6, 2, 2, 4, 275}}, {"test_data/ofdm_prach_demodulator_test_input46.dat"}, {"test_data/ofdm_prach_demodulator_test_output46.dat"}}, + {{sampling_rate::from_MHz(491.52), {{3, 89}, to_prach_format_type("A3"), 2, 2, 0, 10, 275}}, {"test_data/ofdm_prach_demodulator_test_input47.dat"}, {"test_data/ofdm_prach_demodulator_test_output47.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.tar.gz b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.tar.gz index 37a49a31bc..4924e3a8a8 100644 --- a/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.tar.gz +++ b/tests/unittests/phy/lower/modulation/ofdm_prach_demodulator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f2fbbfd9f80a2edce2b74ecdcd3877865a9f783c6f262506abf4d1d96764e6b -size 25548071 +oid sha256:fbce2bbbcd106e99cc3e24326ee45669006397d3e2be473d9b07a23cc0c7a90a +size 19180140 diff --git a/tests/unittests/phy/lower/processors/uplink/prach/prach_processor_test.cpp b/tests/unittests/phy/lower/processors/uplink/prach/prach_processor_test.cpp index 29df4b445c..e5807197de 100644 --- a/tests/unittests/phy/lower/processors/uplink/prach/prach_processor_test.cpp +++ b/tests/unittests/phy/lower/processors/uplink/prach/prach_processor_test.cpp @@ -506,10 +506,10 @@ TEST_P(PrachProcessorFixture, SingleBasebandSymbols) const auto demodulate_entry = ofdm_prach_factory_spy->get_total_demodulate_entries().back(); ASSERT_EQ(demodulate_entry.buffer, &buffer); ASSERT_EQ(demodulate_entry.input.size(), prach_window_length); + ASSERT_EQ(demodulate_entry.config.slot, context.slot); ASSERT_EQ(demodulate_entry.config.format, context.format); ASSERT_EQ(demodulate_entry.config.rb_offset, context.rb_offset); ASSERT_EQ(demodulate_entry.config.nof_prb_ul_grid, context.nof_prb_ul_grid); - ASSERT_EQ(demodulate_entry.config.pusch_scs, context.pusch_scs); ASSERT_EQ(span(demodulate_entry.input), samples.get_reader().get_channel_buffer(context.ports.front()).first(prach_window_length)); @@ -645,10 +645,10 @@ TEST_P(PrachProcessorFixture, ThreeBasebandSymbols) const auto demodulate_entry = ofdm_prach_factory_spy->get_total_demodulate_entries().back(); ASSERT_EQ(demodulate_entry.buffer, &buffer); ASSERT_EQ(demodulate_entry.input.size(), prach_window_length); + ASSERT_EQ(demodulate_entry.config.slot, context.slot); ASSERT_EQ(demodulate_entry.config.format, context.format); ASSERT_EQ(demodulate_entry.config.rb_offset, context.rb_offset); ASSERT_EQ(demodulate_entry.config.nof_prb_ul_grid, context.nof_prb_ul_grid); - ASSERT_EQ(demodulate_entry.config.pusch_scs, context.pusch_scs); ASSERT_EQ(span(demodulate_entry.input), samples.get_reader().get_channel_buffer(context.ports.front()).first(prach_window_length)); From 2b050fc7941f079a8926a17eb81ce5acedef4d50 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 5 Aug 2024 15:05:36 +0200 Subject: [PATCH 096/407] cmake, docs: avoid file creation in git-tracked folder --- docs/CMakeGenerateTeXMacros.txt | 2 +- docs/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CMakeGenerateTeXMacros.txt b/docs/CMakeGenerateTeXMacros.txt index d1a886d975..b37eaeae25 100644 --- a/docs/CMakeGenerateTeXMacros.txt +++ b/docs/CMakeGenerateTeXMacros.txt @@ -6,7 +6,7 @@ # the distribution. # -file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/math_macros.tex +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/math_macros.tex "\\renewcommand{\\Re}{\\mathbb{R}\\mathrm{e}}\n" "\\renewcommand{\\Im}{\\mathbb{I}\\mathrm{m}}\n" "\n" diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 30b8900a1b..19b648b5d7 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -20,7 +20,7 @@ if (DOXYGEN_FOUND) set(DOXYGEN_WARN_LOGFILE ${CMAKE_CURRENT_BINARY_DIR}/doxygen.log) set(DOXYGEN_USE_MATHJAX "YES") set(DOXYGEN_MATHJAX_EXTENSIONS "TeX/AMSmath") - set(DOXYGEN_FORMULA_MACROFILE ${CMAKE_CURRENT_SOURCE_DIR}/math_macros.tex) + set(DOXYGEN_FORMULA_MACROFILE ${CMAKE_CURRENT_BINARY_DIR}/math_macros.tex) set(DOXYGEN_STRIP_FROM_PATH ${CMAKE_HOME_DIRECTORY}) set(DOXYGEN_EXTRACT_STATIC "YES") set(DOXYGEN_EXTRACT_PRIVATE "YES") From db4fb43e75dfeba5acbf6c835fb4bc1a956f2e2c Mon Sep 17 00:00:00 2001 From: sauka Date: Mon, 5 Aug 2024 14:36:19 +0300 Subject: [PATCH 097/407] ofh: update compression unit-test according to the new matlab test using bf16 approximation --- .../ofh/compression/ofh_compression_test.cpp | 18 +----- .../compression/ofh_compression_test_data.h | 62 +++++++++---------- .../ofh_compression_test_data.tar.gz | 4 +- 3 files changed, 36 insertions(+), 48 deletions(-) diff --git a/tests/unittests/ofh/compression/ofh_compression_test.cpp b/tests/unittests/ofh/compression/ofh_compression_test.cpp index d7100eda1e..ab42fba35a 100644 --- a/tests/unittests/ofh/compression/ofh_compression_test.cpp +++ b/tests/unittests/ofh/compression/ofh_compression_test.cpp @@ -70,19 +70,8 @@ TEST_P(OFHCompressionFixture, match_test_case_result_and_decompress_to_original) std::vector test_compr_param = test_case.compressed_params.read(); std::vector test_data_cbf16(test_data.size()); - std::vector test_data_cf(test_data.size()); srsvec::convert(test_data_cbf16, test_data); - // Calculate error introduced by single-precision float to brain float conversion. - srsvec::convert(test_data_cf, test_data_cbf16); - std::vector f_bf16_error; - for (unsigned i = 0, e = test_data.size(); i != e; ++i) { - float re_err = std::abs(std::real(test_data[i]) - std::real(test_data_cf[i])); - float im_err = std::abs(std::imag(test_data[i]) - std::imag(test_data_cf[i])); - f_bf16_error.push_back(re_err); - f_bf16_error.push_back(im_err); - } - // Prepare vectors to store compression/decompression results. std::vector compressed_data(nof_prb); std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); @@ -101,8 +90,7 @@ TEST_P(OFHCompressionFixture, match_test_case_result_and_decompress_to_original) int16_t sample = q.sign_extend(unpacker.unpack(read_pos, params.data_width)); read_pos += params.data_width; - uint16_t err_tolerance = - 1 + std::ceil(f_bf16_error[j * NOF_SUBCARRIERS_PER_RB * 2 + i] * iq_scaling * (1 << (params.data_width - 1))); + constexpr uint16_t err_tolerance = 1; ASSERT_TRUE(std::abs(sample - test_compr_data[j * NOF_SUBCARRIERS_PER_RB * 2 + i]) <= err_tolerance) << fmt::format("Compressed samples mismatch at position {}", j * NOF_SUBCARRIERS_PER_RB * 2 + i); @@ -122,8 +110,8 @@ TEST_P(OFHCompressionFixture, match_test_case_result_and_decompress_to_original) result = {std::real(result) / iq_scaling, std::imag(result) / iq_scaling}; } - ASSERT_TRUE(std::equal(test_data_cf.begin(), - test_data_cf.end(), + ASSERT_TRUE(std::equal(test_data.begin(), + test_data.end(), decompressed_data_cf.begin(), [&](cf_t& test_value, cf_t& result) { // Make sure the sign is the same and diff is minimal. diff --git a/tests/unittests/ofh/compression/ofh_compression_test_data.h b/tests/unittests/ofh/compression/ofh_compression_test_data.h index 1509a1d5fd..8caf8a34e8 100644 --- a/tests/unittests/ofh/compression/ofh_compression_test_data.h +++ b/tests/unittests/ofh/compression/ofh_compression_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 14-09-2023 (seed 0): +// This file was generated using the following MATLAB class on 05-08-2024 (seed 0): // + "srsOFHCompressionUnittest.m" #include "srsran/adt/complex.h" @@ -31,42 +31,42 @@ struct test_case_t { static const std::vector ofh_compression_test_data = { // clang-format off - {25, ofh::compression_type::none, 8, 1, {"test_data/ofh_compression_test_input0.dat"}, {"test_data/ofh_compression_test_c_output0.dat"}, {"test_data/ofh_compression_test_c_param0.dat"}}, - {25, ofh::compression_type::none, 9, 0.73959, {"test_data/ofh_compression_test_input1.dat"}, {"test_data/ofh_compression_test_c_output1.dat"}, {"test_data/ofh_compression_test_c_param1.dat"}}, - {25, ofh::compression_type::none, 10, 0.57684, {"test_data/ofh_compression_test_input2.dat"}, {"test_data/ofh_compression_test_c_output2.dat"}, {"test_data/ofh_compression_test_c_param2.dat"}}, - {25, ofh::compression_type::none, 11, 1, {"test_data/ofh_compression_test_input3.dat"}, {"test_data/ofh_compression_test_c_output3.dat"}, {"test_data/ofh_compression_test_c_param3.dat"}}, - {25, ofh::compression_type::none, 12, 0.66318, {"test_data/ofh_compression_test_input4.dat"}, {"test_data/ofh_compression_test_c_output4.dat"}, {"test_data/ofh_compression_test_c_param4.dat"}}, - {25, ofh::compression_type::none, 13, 0.5015, {"test_data/ofh_compression_test_input5.dat"}, {"test_data/ofh_compression_test_c_output5.dat"}, {"test_data/ofh_compression_test_c_param5.dat"}}, - {25, ofh::compression_type::none, 14, 0.38347, {"test_data/ofh_compression_test_input6.dat"}, {"test_data/ofh_compression_test_c_output6.dat"}, {"test_data/ofh_compression_test_c_param6.dat"}}, + {25, ofh::compression_type::none, 8, 0.39651, {"test_data/ofh_compression_test_input0.dat"}, {"test_data/ofh_compression_test_c_output0.dat"}, {"test_data/ofh_compression_test_c_param0.dat"}}, + {25, ofh::compression_type::none, 9, 0.91693, {"test_data/ofh_compression_test_input1.dat"}, {"test_data/ofh_compression_test_c_output1.dat"}, {"test_data/ofh_compression_test_c_param1.dat"}}, + {25, ofh::compression_type::none, 10, 1, {"test_data/ofh_compression_test_input2.dat"}, {"test_data/ofh_compression_test_c_output2.dat"}, {"test_data/ofh_compression_test_c_param2.dat"}}, + {25, ofh::compression_type::none, 11, 0.57147, {"test_data/ofh_compression_test_input3.dat"}, {"test_data/ofh_compression_test_c_output3.dat"}, {"test_data/ofh_compression_test_c_param3.dat"}}, + {25, ofh::compression_type::none, 12, 0.48425, {"test_data/ofh_compression_test_input4.dat"}, {"test_data/ofh_compression_test_c_output4.dat"}, {"test_data/ofh_compression_test_c_param4.dat"}}, + {25, ofh::compression_type::none, 13, 1, {"test_data/ofh_compression_test_input5.dat"}, {"test_data/ofh_compression_test_c_output5.dat"}, {"test_data/ofh_compression_test_c_param5.dat"}}, + {25, ofh::compression_type::none, 14, 0.78642, {"test_data/ofh_compression_test_input6.dat"}, {"test_data/ofh_compression_test_c_output6.dat"}, {"test_data/ofh_compression_test_c_param6.dat"}}, {25, ofh::compression_type::none, 15, 1, {"test_data/ofh_compression_test_input7.dat"}, {"test_data/ofh_compression_test_c_output7.dat"}, {"test_data/ofh_compression_test_c_param7.dat"}}, - {25, ofh::compression_type::none, 16, 0.84982, {"test_data/ofh_compression_test_input8.dat"}, {"test_data/ofh_compression_test_c_output8.dat"}, {"test_data/ofh_compression_test_c_param8.dat"}}, - {25, ofh::compression_type::BFP, 8, 0.88188, {"test_data/ofh_compression_test_input9.dat"}, {"test_data/ofh_compression_test_c_output9.dat"}, {"test_data/ofh_compression_test_c_param9.dat"}}, - {25, ofh::compression_type::BFP, 9, 0.48734, {"test_data/ofh_compression_test_input10.dat"}, {"test_data/ofh_compression_test_c_output10.dat"}, {"test_data/ofh_compression_test_c_param10.dat"}}, - {25, ofh::compression_type::BFP, 10, 0.6155, {"test_data/ofh_compression_test_input11.dat"}, {"test_data/ofh_compression_test_c_output11.dat"}, {"test_data/ofh_compression_test_c_param11.dat"}}, - {25, ofh::compression_type::BFP, 11, 0.79188, {"test_data/ofh_compression_test_input12.dat"}, {"test_data/ofh_compression_test_c_output12.dat"}, {"test_data/ofh_compression_test_c_param12.dat"}}, + {25, ofh::compression_type::none, 16, 0.84911, {"test_data/ofh_compression_test_input8.dat"}, {"test_data/ofh_compression_test_c_output8.dat"}, {"test_data/ofh_compression_test_c_param8.dat"}}, + {25, ofh::compression_type::BFP, 8, 0.50221, {"test_data/ofh_compression_test_input9.dat"}, {"test_data/ofh_compression_test_c_output9.dat"}, {"test_data/ofh_compression_test_c_param9.dat"}}, + {25, ofh::compression_type::BFP, 9, 0.42441, {"test_data/ofh_compression_test_input10.dat"}, {"test_data/ofh_compression_test_c_output10.dat"}, {"test_data/ofh_compression_test_c_param10.dat"}}, + {25, ofh::compression_type::BFP, 10, 0.61318, {"test_data/ofh_compression_test_input11.dat"}, {"test_data/ofh_compression_test_c_output11.dat"}, {"test_data/ofh_compression_test_c_param11.dat"}}, + {25, ofh::compression_type::BFP, 11, 0.8596, {"test_data/ofh_compression_test_input12.dat"}, {"test_data/ofh_compression_test_c_output12.dat"}, {"test_data/ofh_compression_test_c_param12.dat"}}, {25, ofh::compression_type::BFP, 12, 1, {"test_data/ofh_compression_test_input13.dat"}, {"test_data/ofh_compression_test_c_output13.dat"}, {"test_data/ofh_compression_test_c_param13.dat"}}, - {25, ofh::compression_type::BFP, 13, 1, {"test_data/ofh_compression_test_input14.dat"}, {"test_data/ofh_compression_test_c_output14.dat"}, {"test_data/ofh_compression_test_c_param14.dat"}}, + {25, ofh::compression_type::BFP, 13, 0.97755, {"test_data/ofh_compression_test_input14.dat"}, {"test_data/ofh_compression_test_c_output14.dat"}, {"test_data/ofh_compression_test_c_param14.dat"}}, {25, ofh::compression_type::BFP, 14, 1, {"test_data/ofh_compression_test_input15.dat"}, {"test_data/ofh_compression_test_c_output15.dat"}, {"test_data/ofh_compression_test_c_param15.dat"}}, - {25, ofh::compression_type::BFP, 15, 1, {"test_data/ofh_compression_test_input16.dat"}, {"test_data/ofh_compression_test_c_output16.dat"}, {"test_data/ofh_compression_test_c_param16.dat"}}, - {25, ofh::compression_type::BFP, 16, 0.46123, {"test_data/ofh_compression_test_input17.dat"}, {"test_data/ofh_compression_test_c_output17.dat"}, {"test_data/ofh_compression_test_c_param17.dat"}}, - {275, ofh::compression_type::none, 8, 0.67528, {"test_data/ofh_compression_test_input18.dat"}, {"test_data/ofh_compression_test_c_output18.dat"}, {"test_data/ofh_compression_test_c_param18.dat"}}, - {275, ofh::compression_type::none, 9, 0.97605, {"test_data/ofh_compression_test_input19.dat"}, {"test_data/ofh_compression_test_c_output19.dat"}, {"test_data/ofh_compression_test_c_param19.dat"}}, - {275, ofh::compression_type::none, 10, 0.68678, {"test_data/ofh_compression_test_input20.dat"}, {"test_data/ofh_compression_test_c_output20.dat"}, {"test_data/ofh_compression_test_c_param20.dat"}}, + {25, ofh::compression_type::BFP, 15, 0.5511, {"test_data/ofh_compression_test_input16.dat"}, {"test_data/ofh_compression_test_c_output16.dat"}, {"test_data/ofh_compression_test_c_param16.dat"}}, + {25, ofh::compression_type::BFP, 16, 1, {"test_data/ofh_compression_test_input17.dat"}, {"test_data/ofh_compression_test_c_output17.dat"}, {"test_data/ofh_compression_test_c_param17.dat"}}, + {275, ofh::compression_type::none, 8, 0.96089, {"test_data/ofh_compression_test_input18.dat"}, {"test_data/ofh_compression_test_c_output18.dat"}, {"test_data/ofh_compression_test_c_param18.dat"}}, + {275, ofh::compression_type::none, 9, 1, {"test_data/ofh_compression_test_input19.dat"}, {"test_data/ofh_compression_test_c_output19.dat"}, {"test_data/ofh_compression_test_c_param19.dat"}}, + {275, ofh::compression_type::none, 10, 0.5279, {"test_data/ofh_compression_test_input20.dat"}, {"test_data/ofh_compression_test_c_output20.dat"}, {"test_data/ofh_compression_test_c_param20.dat"}}, {275, ofh::compression_type::none, 11, 1, {"test_data/ofh_compression_test_input21.dat"}, {"test_data/ofh_compression_test_c_output21.dat"}, {"test_data/ofh_compression_test_c_param21.dat"}}, - {275, ofh::compression_type::none, 12, 0.31654, {"test_data/ofh_compression_test_input22.dat"}, {"test_data/ofh_compression_test_c_output22.dat"}, {"test_data/ofh_compression_test_c_param22.dat"}}, - {275, ofh::compression_type::none, 13, 0.81136, {"test_data/ofh_compression_test_input23.dat"}, {"test_data/ofh_compression_test_c_output23.dat"}, {"test_data/ofh_compression_test_c_param23.dat"}}, + {275, ofh::compression_type::none, 12, 1, {"test_data/ofh_compression_test_input22.dat"}, {"test_data/ofh_compression_test_c_output22.dat"}, {"test_data/ofh_compression_test_c_param22.dat"}}, + {275, ofh::compression_type::none, 13, 0.97268, {"test_data/ofh_compression_test_input23.dat"}, {"test_data/ofh_compression_test_c_output23.dat"}, {"test_data/ofh_compression_test_c_param23.dat"}}, {275, ofh::compression_type::none, 14, 1, {"test_data/ofh_compression_test_input24.dat"}, {"test_data/ofh_compression_test_c_output24.dat"}, {"test_data/ofh_compression_test_c_param24.dat"}}, - {275, ofh::compression_type::none, 15, 0.49012, {"test_data/ofh_compression_test_input25.dat"}, {"test_data/ofh_compression_test_c_output25.dat"}, {"test_data/ofh_compression_test_c_param25.dat"}}, - {275, ofh::compression_type::none, 16, 0.2594, {"test_data/ofh_compression_test_input26.dat"}, {"test_data/ofh_compression_test_c_output26.dat"}, {"test_data/ofh_compression_test_c_param26.dat"}}, - {275, ofh::compression_type::BFP, 8, 0.41793, {"test_data/ofh_compression_test_input27.dat"}, {"test_data/ofh_compression_test_c_output27.dat"}, {"test_data/ofh_compression_test_c_param27.dat"}}, - {275, ofh::compression_type::BFP, 9, 0.35178, {"test_data/ofh_compression_test_input28.dat"}, {"test_data/ofh_compression_test_c_output28.dat"}, {"test_data/ofh_compression_test_c_param28.dat"}}, - {275, ofh::compression_type::BFP, 10, 0.85194, {"test_data/ofh_compression_test_input29.dat"}, {"test_data/ofh_compression_test_c_output29.dat"}, {"test_data/ofh_compression_test_c_param29.dat"}}, - {275, ofh::compression_type::BFP, 11, 1, {"test_data/ofh_compression_test_input30.dat"}, {"test_data/ofh_compression_test_c_output30.dat"}, {"test_data/ofh_compression_test_c_param30.dat"}}, - {275, ofh::compression_type::BFP, 12, 1, {"test_data/ofh_compression_test_input31.dat"}, {"test_data/ofh_compression_test_c_output31.dat"}, {"test_data/ofh_compression_test_c_param31.dat"}}, - {275, ofh::compression_type::BFP, 13, 0.95338, {"test_data/ofh_compression_test_input32.dat"}, {"test_data/ofh_compression_test_c_output32.dat"}, {"test_data/ofh_compression_test_c_param32.dat"}}, + {275, ofh::compression_type::none, 15, 0.83187, {"test_data/ofh_compression_test_input25.dat"}, {"test_data/ofh_compression_test_c_output25.dat"}, {"test_data/ofh_compression_test_c_param25.dat"}}, + {275, ofh::compression_type::none, 16, 0.44705, {"test_data/ofh_compression_test_input26.dat"}, {"test_data/ofh_compression_test_c_output26.dat"}, {"test_data/ofh_compression_test_c_param26.dat"}}, + {275, ofh::compression_type::BFP, 8, 1, {"test_data/ofh_compression_test_input27.dat"}, {"test_data/ofh_compression_test_c_output27.dat"}, {"test_data/ofh_compression_test_c_param27.dat"}}, + {275, ofh::compression_type::BFP, 9, 0.77352, {"test_data/ofh_compression_test_input28.dat"}, {"test_data/ofh_compression_test_c_output28.dat"}, {"test_data/ofh_compression_test_c_param28.dat"}}, + {275, ofh::compression_type::BFP, 10, 0.81769, {"test_data/ofh_compression_test_input29.dat"}, {"test_data/ofh_compression_test_c_output29.dat"}, {"test_data/ofh_compression_test_c_param29.dat"}}, + {275, ofh::compression_type::BFP, 11, 0.6722, {"test_data/ofh_compression_test_input30.dat"}, {"test_data/ofh_compression_test_c_output30.dat"}, {"test_data/ofh_compression_test_c_param30.dat"}}, + {275, ofh::compression_type::BFP, 12, 0.69926, {"test_data/ofh_compression_test_input31.dat"}, {"test_data/ofh_compression_test_c_output31.dat"}, {"test_data/ofh_compression_test_c_param31.dat"}}, + {275, ofh::compression_type::BFP, 13, 0.69226, {"test_data/ofh_compression_test_input32.dat"}, {"test_data/ofh_compression_test_c_output32.dat"}, {"test_data/ofh_compression_test_c_param32.dat"}}, {275, ofh::compression_type::BFP, 14, 1, {"test_data/ofh_compression_test_input33.dat"}, {"test_data/ofh_compression_test_c_output33.dat"}, {"test_data/ofh_compression_test_c_param33.dat"}}, - {275, ofh::compression_type::BFP, 15, 1, {"test_data/ofh_compression_test_input34.dat"}, {"test_data/ofh_compression_test_c_output34.dat"}, {"test_data/ofh_compression_test_c_param34.dat"}}, - {275, ofh::compression_type::BFP, 16, 0.82896, {"test_data/ofh_compression_test_input35.dat"}, {"test_data/ofh_compression_test_c_output35.dat"}, {"test_data/ofh_compression_test_c_param35.dat"}}, + {275, ofh::compression_type::BFP, 15, 0.67731, {"test_data/ofh_compression_test_input34.dat"}, {"test_data/ofh_compression_test_c_output34.dat"}, {"test_data/ofh_compression_test_c_param34.dat"}}, + {275, ofh::compression_type::BFP, 16, 1, {"test_data/ofh_compression_test_input35.dat"}, {"test_data/ofh_compression_test_c_output35.dat"}, {"test_data/ofh_compression_test_c_param35.dat"}}, // clang-format on }; diff --git a/tests/unittests/ofh/compression/ofh_compression_test_data.tar.gz b/tests/unittests/ofh/compression/ofh_compression_test_data.tar.gz index 5cc325a8d3..0f80de6237 100644 --- a/tests/unittests/ofh/compression/ofh_compression_test_data.tar.gz +++ b/tests/unittests/ofh/compression/ofh_compression_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:076a11ffc88b7e1a320a3554ebae3c5854cc709497e4388b0fe25c147c39c51c -size 718663 +oid sha256:f160727bc62619da73156deb082442cea35fac21ea1a352d54214133b392d055 +size 485266 From 9cd713991199c01eae3410c0d01851fbc20201d5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 2 Aug 2024 15:35:37 +0200 Subject: [PATCH 098/407] f1ap: create common types for DRBs in the F1AP --- .../srsran/f1ap/common/ue_context_config.h | 58 +++++++++++++++++++ .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 36 ++++-------- .../f1ap/du/f1ap_du_ue_context_update.h | 10 +--- .../mobility/inter_du_handover_routine.cpp | 6 +- .../routines/mobility/mobility_helpers.cpp | 4 +- .../routines/pdu_session_routine_helpers.cpp | 8 +-- ...blishment_context_modification_routine.cpp | 8 +-- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 10 ++-- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 2 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 6 +- .../f1ap/cu_cp/f1ap_cu_test_helpers.cpp | 2 +- 11 files changed, 92 insertions(+), 58 deletions(-) create mode 100644 include/srsran/f1ap/common/ue_context_config.h diff --git a/include/srsran/f1ap/common/ue_context_config.h b/include/srsran/f1ap/common/ue_context_config.h new file mode 100644 index 0000000000..bb8f1ebd86 --- /dev/null +++ b/include/srsran/f1ap/common/ue_context_config.h @@ -0,0 +1,58 @@ +/* + * + * 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/pdcp/pdcp_sn_size.h" +#include "srsran/ran/cause/f1ap_cause.h" +#include "srsran/ran/lcid.h" +#include "srsran/ran/up_transport_layer_info.h" +#include "srsran/rlc/rlc_mode.h" + +namespace srsran { + +/// Parameters of a new DRB to be setup in the DU UE context. +struct f1ap_drb_to_setup { + /// DRB-Id of the new DRB. + drb_id_t drb_id = drb_id_t::invalid; + /// RLC mode of the new DRB (e.g. AM, UM-BiDir, etc). + rlc_mode mode; + /// UL Transport layer info for the given DRB. See ulUPTNLInformation-ToBeSetup-List in TS 38.473. + std::vector uluptnl_info_list; + /// \brief PDCP SN length of the DRB. + /// \remark (Implementation-defined) We use the same length for DL and UL. + pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; +}; + +/// New parameters to set for an existing DRB in the DU UE context. +struct f1ap_drb_to_modify { + /// DRB-Id of the existing DRB. + drb_id_t drb_id = drb_id_t::invalid; + /// UL Transport layer info for the given DRB. See ulUPTNLInformation-ToBeSetup-List in TS 38.473. + std::vector uluptnl_info_list; + /// \brief PDCP SN length of the DRB. + /// \remark (Implementation-defined) We use the same length for DL and UL. + std::optional pdcp_sn_len; +}; + +/// Parameters of a setup/modified DRB in the DU UE context. +struct f1ap_drb_setupmod { + drb_id_t drb_id = drb_id_t::invalid; + std::optional lcid; + std::vector dluptnl_info_list; +}; + +/// Parameters of a failed DRB setup/modify in the DU UE context. +struct f1ap_drb_failed_to_setupmod { + drb_id_t drb_id = drb_id_t::invalid; + std::optional cause; +}; + +} // namespace srsran \ No newline at end of file diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index 1320983990..8dee3e4a84 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -12,6 +12,7 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/common/f1ap_ue_id.h" +#include "srsran/f1ap/common/ue_context_config.h" #include "srsran/ran/cause/f1ap_cause.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" @@ -24,10 +25,6 @@ namespace srsran { namespace srs_cu_cp { -struct f1ap_dl_up_tnl_info_to_be_setup_item { - up_transport_layer_info dl_up_tnl_info; -}; - enum class f1ap_cell_ul_cfg { none = 0, ul, sul, ul_and_sul }; struct f1ap_cu_to_du_rrc_info_ext_ies_container { @@ -105,14 +102,10 @@ struct f1ap_ul_cfg { enum class f1ap_dupl_activation { active = 0, inactive }; -struct f1ap_drbs_to_be_setup_mod_item { - drb_id_t drb_id = drb_id_t::invalid; - f1ap_drb_info qos_info; - std::vector ul_up_tnl_info_to_be_setup_list; - srsran::rlc_mode rlc_mod; - pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; - std::optional ul_cfg; - std::optional dupl_activation; +struct f1ap_drbs_to_be_setup_mod_item : public f1ap_drb_to_setup { + f1ap_drb_info qos_info; + std::optional ul_cfg; + std::optional dupl_activation; }; struct f1ap_rat_freq_prio_info { @@ -158,21 +151,14 @@ struct f1ap_du_to_cu_rrc_info { byte_buffer requested_p_max_fr1; }; -struct f1ap_drbs_setup_mod_item { - drb_id_t drb_id = drb_id_t::invalid; - std::optional lcid = lcid_t::INVALID_LCID; - std::vector dl_up_tnl_info_to_be_setup_list; -}; +using f1ap_drbs_setup_mod_item = f1ap_drb_setupmod; struct f1ap_srbs_failed_to_be_setup_mod_item { srb_id_t srb_id = srb_id_t::nulltype; std::optional cause; }; -struct f1ap_drbs_failed_to_be_setup_mod_item { - drb_id_t drb_id = drb_id_t::invalid; - std::optional cause; -}; +using f1ap_drbs_failed_to_be_setup_mod_item = f1ap_drb_failed_to_setupmod; struct f1ap_scell_failed_to_setup_mod_item { nr_cell_global_id_t scell_id; @@ -221,11 +207,9 @@ struct f1ap_scell_to_be_remd_item { nr_cell_global_id_t scell_id; }; -struct f1ap_drbs_to_be_modified_item { - drb_id_t drb_id = drb_id_t::invalid; - std::optional qos_info; - std::vector ul_up_tnl_info_to_be_setup_list; - std::optional ul_cfg; +struct f1ap_drbs_to_be_modified_item : public f1ap_drb_to_modify { + std::optional qos_info; + std::optional ul_cfg; }; struct f1ap_rlc_fail_ind { diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 44fcbd4c78..28df27511b 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -12,15 +12,13 @@ #include "srsran/adt/byte_buffer.h" #include "srsran/adt/optional.h" +#include "srsran/f1ap/common/ue_context_config.h" #include "srsran/pdcp/pdcp_sn_size.h" #include "srsran/ran/du_types.h" #include "srsran/ran/five_qi.h" -#include "srsran/ran/lcid.h" #include "srsran/ran/qos/qos_info.h" #include "srsran/ran/rnti.h" #include "srsran/ran/s_nssai.h" -#include "srsran/ran/up_transport_layer_info.h" -#include "srsran/rlc/rlc_mode.h" namespace srsran { namespace srs_du { @@ -62,11 +60,7 @@ struct f1ap_scell_to_setup { }; /// \brief DRB that was setup successfully in the F1AP UE context. -struct f1ap_drb_configured { - drb_id_t drb_id; - std::optional lcid; - std::vector dluptnl_info_list; -}; +using f1ap_drb_configured = f1ap_drb_setupmod; /// \brief Request from DU F1AP to DU manager to modify existing UE configuration. struct f1ap_ue_context_update_request { diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index 65458b7efa..483bd4c698 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -280,9 +280,9 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex flow_item.qos_flow_level_qos_params = flow.second.qos_params; drb_item.qos_info.flows_mapped_to_drb_list.emplace(flow_item.qos_flow_id, flow_item); } - drb_item.ul_up_tnl_info_to_be_setup_list = drb_context.ul_up_tnl_info_to_be_setup_list; - drb_item.rlc_mod = drb_context.rlc_mod; - drb_item.pdcp_sn_len = drb_context.pdcp_cfg.tx.sn_size; + drb_item.uluptnl_info_list = drb_context.ul_up_tnl_info_to_be_setup_list; + drb_item.mode = drb_context.rlc_mod; + drb_item.pdcp_sn_len = drb_context.pdcp_cfg.tx.sn_size; setup_request.drbs_to_be_setup_list.emplace(drb_item.drb_id, drb_item); } diff --git a/lib/cu_cp/routines/mobility/mobility_helpers.cpp b/lib/cu_cp/routines/mobility/mobility_helpers.cpp index 47e2b0d070..69657cdcf4 100644 --- a/lib/cu_cp/routines/mobility/mobility_helpers.cpp +++ b/lib/cu_cp/routines/mobility/mobility_helpers.cpp @@ -65,9 +65,9 @@ bool srsran::srs_cu_cp::handle_context_setup_response( e1ap_drb_to_modify_item_ng_ran e1ap_drb_item; e1ap_drb_item.drb_id = drb_item.first; - for (const auto& dl_up_param : context_setup_drb_item.dl_up_tnl_info_to_be_setup_list) { + for (const auto& dl_up_tnl_info : context_setup_drb_item.dluptnl_info_list) { e1ap_up_params_item e1ap_dl_up_param; - e1ap_dl_up_param.up_tnl_info = dl_up_param.dl_up_tnl_info; + e1ap_dl_up_param.up_tnl_info = dl_up_tnl_info; e1ap_dl_up_param.cell_group_id = 0; // TODO: Remove hardcoded value e1ap_drb_item.dl_up_params.push_back(e1ap_dl_up_param); diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index ef5aa669a0..b3f9fc82a4 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -209,12 +209,12 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ // S-NSSAI drb_setup_mod_item.qos_info.s_nssai = next_drb_config.s_nssai; - drb_setup_mod_item.rlc_mod = next_drb_config.rlc_mod; + drb_setup_mod_item.mode = next_drb_config.rlc_mod; drb_setup_mod_item.pdcp_sn_len = next_drb_config.pdcp_cfg.tx.sn_size; // Add up tnl info for (const auto& ul_up_transport_param : e1ap_drb_item.ul_up_transport_params) { - drb_setup_mod_item.ul_up_tnl_info_to_be_setup_list.push_back(ul_up_transport_param.up_tnl_info); + drb_setup_mod_item.uluptnl_info_list.push_back(ul_up_transport_param.up_tnl_info); // Store UL tunnel information in DRB context (required for mobility). next_drb_config.ul_up_tnl_info_to_be_setup_list.push_back(ul_up_transport_param.up_tnl_info); } @@ -622,9 +622,9 @@ void srsran::srs_cu_cp::fill_e1ap_bearer_context_list( e1ap_drb_to_modify_item_ng_ran e1ap_drb_item; e1ap_drb_item.drb_id = drb_item.drb_id; - for (const auto& dl_up_param : drb_item.dl_up_tnl_info_to_be_setup_list) { + for (const auto& dl_up_tnl_info : drb_item.dluptnl_info_list) { e1ap_up_params_item e1ap_dl_up_param; - e1ap_dl_up_param.up_tnl_info = dl_up_param.dl_up_tnl_info; + e1ap_dl_up_param.up_tnl_info = dl_up_tnl_info; e1ap_dl_up_param.cell_group_id = 0; // TODO: Remove hardcoded value e1ap_drb_item.dl_up_params.push_back(e1ap_dl_up_param); diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index b0c1d1d3c6..dd132b2ade 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -223,11 +223,11 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat // Add up tnl info for (const auto& ul_up_transport_param : e1ap_drb_item.ul_up_transport_params) { - drb_setup_mod_item.ul_up_tnl_info_to_be_setup_list.push_back(ul_up_transport_param.up_tnl_info); + drb_setup_mod_item.uluptnl_info_list.push_back(ul_up_transport_param.up_tnl_info); } // Add rlc mode - drb_setup_mod_item.rlc_mod = drb_up_context.rlc_mod; + drb_setup_mod_item.mode = drb_up_context.rlc_mod; drb_setup_mod_item.pdcp_sn_len = drb_up_context.pdcp_cfg.tx.sn_size; // fill QoS info @@ -306,9 +306,9 @@ bool reestablishment_context_modification_routine::generate_bearer_context_modif e1ap_drb_to_modify_item_ng_ran e1ap_drb_item; e1ap_drb_item.drb_id = drb_item.drb_id; - for (const auto& dl_up_param : drb_item.dl_up_tnl_info_to_be_setup_list) { + for (const auto& dl_up_tnl_info : drb_item.dluptnl_info_list) { e1ap_up_params_item e1ap_dl_up_param; - e1ap_dl_up_param.up_tnl_info = dl_up_param.dl_up_tnl_info; + e1ap_dl_up_param.up_tnl_info = dl_up_tnl_info; e1ap_dl_up_param.cell_group_id = 0; // TODO: Remove hardcoded value e1ap_drb_item.dl_up_params.push_back(e1ap_dl_up_param); diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 01b652f04b..b82217c144 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -490,14 +490,14 @@ inline void f1ap_drbs_to_be_setup_mod_item_to_asn1(template_asn1_item& asn1_drb_to_be_setup_mod_item.qos_info = f1ap_qos_info_to_asn1(drb_to_be_setup_mod_item.qos_info); // ul up tnl info to be setup list - for (const auto& ul_up_tnl_info_item : drb_to_be_setup_mod_item.ul_up_tnl_info_to_be_setup_list) { + for (const auto& ul_up_tnl_info_item : drb_to_be_setup_mod_item.uluptnl_info_list) { asn1::f1ap::ul_up_tnl_info_to_be_setup_item_s item; up_transport_layer_info_to_asn1(item.ul_up_tnl_info, ul_up_tnl_info_item); asn1_drb_to_be_setup_mod_item.ul_up_tnl_info_to_be_setup_list.push_back(item); } // rlc mode - asn1_drb_to_be_setup_mod_item.rlc_mode = rlc_mode_to_f1ap_asn1(drb_to_be_setup_mod_item.rlc_mod); + asn1_drb_to_be_setup_mod_item.rlc_mode = rlc_mode_to_f1ap_asn1(drb_to_be_setup_mod_item.mode); // pdcp sn size f1ap_drbs_to_be_setup_mod_item_ext_ies_to_asn1(asn1_drb_to_be_setup_mod_item.ie_exts, drb_to_be_setup_mod_item); @@ -725,10 +725,8 @@ inline f1ap_drbs_setup_mod_item asn1_to_f1ap_drbs_setup_mod_item(const template_ // Add DL UP TNL to be setup list for (auto asn1_dl_up_tnl_info_to_be_setup_item : asn1_drbs_setup_mod_item.dl_up_tnl_info_to_be_setup_list) { - f1ap_dl_up_tnl_info_to_be_setup_item dl_up_tnl_info_to_be_setup_item; - dl_up_tnl_info_to_be_setup_item.dl_up_tnl_info = - asn1_to_up_transport_layer_info(asn1_dl_up_tnl_info_to_be_setup_item.dl_up_tnl_info); - drb_setup_mod_item.dl_up_tnl_info_to_be_setup_list.push_back(dl_up_tnl_info_to_be_setup_item); + drb_setup_mod_item.dluptnl_info_list.push_back( + asn1_to_up_transport_layer_info(asn1_dl_up_tnl_info_to_be_setup_item.dl_up_tnl_info)); } if (asn1_drbs_setup_mod_item.lcid_present) { diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index 57cab185a3..b325625551 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -183,7 +183,7 @@ inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod } // ul up tnl info to be setup list - for (const auto& ul_up_tnl_info_item : drb_to_be_modified_item.ul_up_tnl_info_to_be_setup_list) { + for (const auto& ul_up_tnl_info_item : drb_to_be_modified_item.uluptnl_info_list) { asn1::f1ap::ul_up_tnl_info_to_be_setup_item_s item; up_transport_layer_info_to_asn1(item.ul_up_tnl_info, ul_up_tnl_info_item); asn1_drb_to_be_modified_item.ul_up_tnl_info_to_be_setup_list.push_back(item); diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 6b5d759051..83a3755a0b 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -285,10 +285,10 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // ul up tnl info to be setup list up_transport_layer_info ul_up_tnl_info_item = {transport_layer_address::create_from_string("127.0.0.1"), int_to_gtpu_teid(1)}; - drbs_to_be_setup_mod_item.ul_up_tnl_info_to_be_setup_list.push_back(ul_up_tnl_info_item); + drbs_to_be_setup_mod_item.uluptnl_info_list.push_back(ul_up_tnl_info_item); // rlc mode - drbs_to_be_setup_mod_item.rlc_mod = rlc_mode::am; + drbs_to_be_setup_mod_item.mode = rlc_mode::am; drbs_to_be_setup_mod_item.pdcp_sn_len = pdcp_sn_size::size12bits; // ul cfg @@ -338,7 +338,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_modified_item.qos_info = qos_info; // ul up tnl info to be setup list - drbs_to_be_modified_item.ul_up_tnl_info_to_be_setup_list.push_back(ul_up_tnl_info_item); + drbs_to_be_modified_item.uluptnl_info_list.push_back(ul_up_tnl_info_item); // ul cfg drbs_to_be_modified_item.ul_cfg = ul_cfg; diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp index 47850242e4..98cba32261 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp @@ -152,7 +152,7 @@ srsran::srs_cu_cp::create_ue_context_setup_request(const std::initializer_list Date: Fri, 2 Aug 2024 17:15:49 +0200 Subject: [PATCH 099/407] f1ap-du: separate modified and setup drb lists in ue context modification --- .../f1ap/du/f1ap_du_ue_context_update.h | 32 +++++--- .../procedures/ue_configuration_procedure.cpp | 41 +++++++--- .../du_ran_resource_manager_impl.cpp | 21 ++++- .../procedures/f1ap_du_ue_context_common.cpp | 80 ++++++++++++++++--- .../du/procedures/f1ap_du_ue_context_common.h | 15 +++- ...p_du_ue_context_modification_procedure.cpp | 79 ++++-------------- .../f1ap_du_ue_context_setup_procedure.cpp | 28 ++----- .../du_manager/du_manager_test_helpers.cpp | 15 ++-- .../du_manager_procedure_test_helpers.cpp | 2 +- .../procedures/ue_configuration_test.cpp | 24 +++--- .../f1ap_du_ue_context_modification_test.cpp | 17 ++-- ...1ap_du_ue_context_setup_procedure_test.cpp | 38 ++++----- 12 files changed, 213 insertions(+), 179 deletions(-) diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 28df27511b..0428f1e4b2 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -59,18 +59,18 @@ struct f1ap_scell_to_setup { du_cell_index_t cell_index; }; -/// \brief DRB that was setup successfully in the F1AP UE context. -using f1ap_drb_configured = f1ap_drb_setupmod; - /// \brief Request from DU F1AP to DU manager to modify existing UE configuration. struct f1ap_ue_context_update_request { du_ue_index_t ue_index; std::vector srbs_to_setup; - /// List of DRBs to either setup or modify. - std::vector drbs_to_setupmod; - std::vector drbs_to_rem; - std::vector scells_to_setup; - std::vector scells_to_rem; + /// List of new DRBs to setup. + std::vector drbs_to_setup; + /// List of DRBs to modify. + std::vector drbs_to_mod; + /// List of DRBs to remove. + std::vector drbs_to_rem; + std::vector scells_to_setup; + std::vector scells_to_rem; /// \brief If true, the gnb-DU shall generate a cell group configuration using full configuration. Otherwise, delta, /// should be used. bool full_config_required; @@ -84,11 +84,17 @@ struct f1ap_ue_context_update_request { /// \brief Response from DU manager to DU F1AP with the result of the UE context update. struct f1ap_ue_context_update_response { - bool result; - std::vector drbs_configured; - std::vector failed_drbs; - byte_buffer du_to_cu_rrc_container; - bool full_config_present = false; + bool result; + /// List of DRBs that were successfully setup. + std::vector drbs_setup; + /// List of DRBs that were successfully modified. + std::vector drbs_mod; + /// List of DRBs that failed to be setup. + std::vector failed_drbs_setups; + /// List of DRBs that failed to be modified. + std::vector failed_drb_mods; + byte_buffer du_to_cu_rrc_container; + bool full_config_present = false; }; /// \brief Handled causes for RLF. diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 82b24793e7..b0c76c6d0f 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -36,8 +36,8 @@ void ue_configuration_procedure::operator()(coro_contextbearers.remove_drb(drb_to_rem)); } - // > Create DU UE DRB objects. - for (const f1ap_drb_config_request& drbtoadd : request.drbs_to_setupmod) { + // > Create new DU UE DRB objects. + for (const f1ap_drb_config_request& drbtoadd : request.drbs_to_setup) { if (drbtoadd.uluptnl_info_list.empty()) { proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtoadd.drb_id); continue; } if (ue->bearers.drbs().count(drbtoadd.drb_id) > 0) { - proc_logger.log_proc_warning("Failed to modify {}. Cause: DRB modifications not supported.", drbtoadd.drb_id); + proc_logger.log_proc_warning("Failed to setup {}. Cause: DRB setup for an already existing DRB.", + drbtoadd.drb_id); continue; } @@ -180,6 +181,7 @@ void ue_configuration_procedure::update_ue_context() } ue->bearers.add_drb(std::move(drb)); } + // TODO: Support DRB modifications. } void ue_configuration_procedure::clear_old_ue_context() @@ -218,7 +220,7 @@ async_task ue_configuration_procedure::update_m mac_ue_reconf_req.bearers_to_rem.push_back(drb->lcid); } - for (const auto& drb : request.drbs_to_setupmod) { + for (const auto& drb : request.drbs_to_setup) { if (ue->bearers.drbs().count(drb.drb_id) == 0) { // The DRB failed to be setup. Carry on with other DRBs. continue; @@ -230,6 +232,7 @@ async_task ue_configuration_procedure::update_m lc_ch.ul_bearer = &bearer.connector.mac_rx_sdu_notifier; lc_ch.dl_bearer = &bearer.connector.mac_tx_sdu_notifier; } + // TODO: Support modifications in the MAC. // Create Scheduler UE Reconfig Request that will be embedded in the mac configuration request. mac_ue_reconf_req.sched_cfg = create_scheduler_ue_config_request(*ue); @@ -243,17 +246,31 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo resp.result = true; // > Handle DRBs that were setup or failed to be setup. - for (const f1ap_drb_config_request& drb_req : request.drbs_to_setupmod) { + for (const f1ap_drb_config_request& drb_req : request.drbs_to_setup) { if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { - resp.failed_drbs.push_back(drb_req.drb_id); + resp.failed_drbs_setups.push_back({drb_req.drb_id, f1ap_cause_radio_network_t::no_radio_res_available}); continue; } du_ue_drb& drb_added = *ue->bearers.drbs().at(drb_req.drb_id); - resp.drbs_configured.emplace_back(); - f1ap_drb_configured& drb_setup = resp.drbs_configured.back(); - drb_setup.drb_id = drb_added.drb_id; - drb_setup.dluptnl_info_list = drb_added.dluptnl_info_list; + resp.drbs_setup.emplace_back(); + f1ap_drb_setupmod& drb_setup = resp.drbs_setup.back(); + drb_setup.drb_id = drb_added.drb_id; + drb_setup.dluptnl_info_list = drb_added.dluptnl_info_list; + } + + // > Handle DRBs that were modified or failed to be modified. + for (const f1ap_drb_config_request& drb_req : request.drbs_to_mod) { + if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { + resp.failed_drb_mods.push_back({drb_req.drb_id, f1ap_cause_radio_network_t::unknown_drb_id}); + continue; + } + du_ue_drb& drb_modified = *ue->bearers.drbs().at(drb_req.drb_id); + + resp.drbs_mod.emplace_back(); + f1ap_drb_setupmod& drb_mod = resp.drbs_mod.back(); + drb_mod.drb_id = drb_modified.drb_id; + drb_mod.dluptnl_info_list = drb_modified.dluptnl_info_list; } // > Calculate ASN.1 CellGroupConfig to be sent in DU-to-CU container. diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index d6bfb09191..9d919a04f9 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -212,9 +212,8 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } - // > Allocate new or modify existing DRBs. - for (const f1ap_drb_config_request& drb : upd_req.drbs_to_setupmod) { - // >> New or Modified DRB. + // > Allocate new DRBs. + for (const f1ap_drb_config_request& drb : upd_req.drbs_to_setup) { auto res = validate_drb_config_request(drb, ue_mcg.rlc_bearers, qos_config); if (not res.has_value()) { resp.failed_drbs.push_back(drb.drb_id); @@ -222,7 +221,7 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } bool new_drb = res.value() == nullptr; if (not new_drb) { - // TODO: Support DRB modification. + resp.failed_drbs.push_back(drb.drb_id); continue; } @@ -262,6 +261,20 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t break; } } + // > Modify existing DRBs. + for (const f1ap_drb_config_request& drb : upd_req.drbs_to_mod) { + auto res = validate_drb_config_request(drb, ue_mcg.rlc_bearers, qos_config); + if (not res.has_value()) { + resp.failed_drbs.push_back(drb.drb_id); + continue; + } + bool new_drb = res.value() == nullptr; + if (new_drb) { + resp.failed_drbs.push_back(drb.drb_id); + continue; + } + // TODO: Support DRB modification. + } // >> Sort by LCID. std::sort(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [](const auto& lhs, const auto& rhs) { return lhs.lcid < rhs.lcid; diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp index 6f35eb45e9..959c433de2 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -9,6 +9,8 @@ */ #include "f1ap_du_ue_context_common.h" +#include "../../cu_cp/f1ap_asn1_converters.h" +#include "srsran/asn1/f1ap/common.h" using namespace srsran; using namespace srs_du; @@ -111,7 +113,7 @@ f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap // helper function to fill asn1 DRBs-SetupMod and DRBs-Modified types. template -static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_configured& drb) +static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_setupmod& drb) { asn1obj.drb_id = drb_id_to_uint(drb.drb_id); asn1obj.lcid_present = drb.lcid.has_value(); @@ -125,23 +127,75 @@ static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_configur } } -asn1::f1ap::drbs_setup_item_s srsran::srs_du::make_drbs_setup_item(const f1ap_drb_configured& drb_obj) +template +void fill_drb_failed_item(ASN1Type& asn1obj, const f1ap_drb_failed_to_setupmod& drb_obj) +{ + asn1obj.drb_id = drb_id_to_uint(drb_obj.drb_id); + asn1obj.cause_present = drb_obj.cause.has_value(); + if (asn1obj.cause_present) { + asn1obj.cause = srs_cu_cp::cause_to_asn1(drb_obj.cause.value()); + } +} + +asn1::f1ap::drbs_setup_list_l srsran::srs_du::make_drbs_setup_list(span drbs) +{ + asn1::f1ap::drbs_setup_list_l list(drbs.size()); + for (unsigned i = 0; i != drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_ITEM); + fill_drb_setup_mod_common(list[i]->drbs_setup_item(), drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_setup_mod_list_l srsran::srs_du::make_drbs_setup_mod_list(span drbs) +{ + asn1::f1ap::drbs_setup_mod_list_l list(drbs.size()); + for (unsigned i = 0; i != drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); + fill_drb_setup_mod_common(list[i]->drbs_setup_mod_item(), drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_modified_list_l srsran::srs_du::make_drbs_modified_list(span drbs) +{ + asn1::f1ap::drbs_modified_list_l list(drbs.size()); + for (unsigned i = 0; i != drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); + fill_drb_setup_mod_common(list[i]->drbs_modified_item(), drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_failed_to_be_setup_list_l +srsran::srs_du::make_drbs_failed_to_be_setup_list(span failed_drbs) { - asn1::f1ap::drbs_setup_item_s asn1_drb; - fill_drb_setup_mod_common(asn1_drb, drb_obj); - return asn1_drb; + asn1::f1ap::drbs_failed_to_be_setup_list_l list(failed_drbs.size()); + for (unsigned i = 0; i != failed_drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_ITEM); + fill_drb_failed_item(list[i]->drbs_failed_to_be_setup_item(), failed_drbs[i]); + } + return list; } -asn1::f1ap::drbs_setup_mod_item_s srsran::srs_du::make_drbs_setup_mod_item(const f1ap_drb_configured& drb_obj) +asn1::f1ap::drbs_failed_to_be_setup_mod_list_l +srsran::srs_du::make_drbs_failed_to_be_setup_mod_list(span failed_drbs) { - asn1::f1ap::drbs_setup_mod_item_s asn1_drb; - fill_drb_setup_mod_common(asn1_drb, drb_obj); - return asn1_drb; + asn1::f1ap::drbs_failed_to_be_setup_mod_list_l list(failed_drbs.size()); + for (unsigned i = 0; i != failed_drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); + fill_drb_failed_item(list[i]->drbs_failed_to_be_setup_mod_item(), failed_drbs[i]); + } + return list; } -asn1::f1ap::drbs_modified_item_s srsran::srs_du::make_drbs_modified_item(const f1ap_drb_configured& drb_obj) +asn1::f1ap::drbs_failed_to_be_modified_list_l +srsran::srs_du::make_drbs_failed_to_be_modified_list(span failed_drbs) { - asn1::f1ap::drbs_modified_item_s asn1_drb; - fill_drb_setup_mod_common(asn1_drb, drb_obj); - return asn1_drb; + asn1::f1ap::drbs_failed_to_be_modified_list_l list(failed_drbs.size()); + for (unsigned i = 0; i != failed_drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_MODIFIED_ITEM); + fill_drb_failed_item(list[i]->drbs_failed_to_be_modified_item(), failed_drbs[i]); + } + return list; } diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h index 780266042d..9bd8966a5a 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h @@ -11,6 +11,7 @@ #pragma once #include "../../common/asn1_helpers.h" +#include "srsran/asn1/f1ap/f1ap_pdu_items.h" #include "srsran/f1ap/du/f1ap_du_ue_context_update.h" #include "srsran/ran/up_transport_layer_info.h" @@ -40,9 +41,17 @@ f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_set /// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_config_request. f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); -asn1::f1ap::drbs_setup_item_s make_drbs_setup_item(const f1ap_drb_configured& drb_obj); -asn1::f1ap::drbs_setup_mod_item_s make_drbs_setup_mod_item(const f1ap_drb_configured& drb_obj); -asn1::f1ap::drbs_modified_item_s make_drbs_modified_item(const f1ap_drb_configured& drb_obj); +asn1::f1ap::drbs_setup_list_l make_drbs_setup_list(span drbs); +asn1::f1ap::drbs_setup_mod_list_l make_drbs_setup_mod_list(span drbs); +asn1::f1ap::drbs_modified_list_l make_drbs_modified_list(span drbs); + +/// Convert F1AP failed to setup/modify types to respective ASN.1 TS 48.473 types. +asn1::f1ap::drbs_failed_to_be_setup_list_l +make_drbs_failed_to_be_setup_list(span failed_drbs); +asn1::f1ap::drbs_failed_to_be_setup_mod_list_l +make_drbs_failed_to_be_setup_mod_list(span failed_drbs); +asn1::f1ap::drbs_failed_to_be_modified_list_l +make_drbs_failed_to_be_modified_list(span failed_drbs); /// \brief Creates a \c drb_id_t from ASN.1 type. /// diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index bf90ca786d..62fca88da6 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -71,15 +71,15 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 du_request.srbs_to_setup.push_back(make_srb_id(srb.value().srbs_to_be_setup_mod_item())); } - // >> Pass DRBs to setup/modify. + // >> Pass DRBs to setup. for (const auto& drb : msg->drbs_to_be_setup_mod_list) { - du_request.drbs_to_setupmod.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_mod_item())); + du_request.drbs_to_setup.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_mod_item())); } // >> Pass DRBs to modify. // Note: This field is used during RRC Reestablishment. for (const auto& drb : msg->drbs_to_be_modified_list) { - du_request.drbs_to_setupmod.push_back(make_drb_config_request(drb.value().drbs_to_be_modified_item())); + du_request.drbs_to_mod.push_back(make_drb_config_request(drb.value().drbs_to_be_modified_item())); } // >> Pass DRBs to remove @@ -99,67 +99,18 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res resp->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue.context.gnb_cu_ue_f1ap_id); resp->res_coordination_transfer_container_present = false; - // DRBs-SetupMod-List + DRBs-FailedToBeSetupMod-List. - for (const auto& req_drb : req->drbs_to_be_setup_mod_list) { - drb_id_t drb_id = uint_to_drb_id(req_drb.value().drbs_to_be_setup_mod_item().drb_id); - auto drb_it = std::find_if(du_response.drbs_configured.begin(), - du_response.drbs_configured.end(), - [drb_id](const f1ap_drb_configured& drb) { return drb.drb_id == drb_id; }); - if (drb_it != du_response.drbs_configured.end()) { - // > DRBs-SetupMod-List. - const f1ap_drb_configured& drb_setup = *drb_it; - resp->drbs_setup_mod_list_present = true; - resp->drbs_setup_mod_list.push_back({}); - resp->drbs_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); - resp->drbs_setup_mod_list.back().value().drbs_setup_mod_item() = make_drbs_setup_mod_item(drb_setup); - continue; - } - - // > DRBs-FailedToBeSetupMod-List. - if (std::count(du_response.failed_drbs.begin(), du_response.failed_drbs.end(), drb_id) == 0) { - logger.warning("DRB{} was not found in the list of configured DRBs by the DU.", drb_id); - continue; - } - resp->drbs_failed_to_be_setup_mod_list_present = true; - resp->drbs_failed_to_be_setup_mod_list.push_back({}); - resp->drbs_failed_to_be_setup_mod_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); - drbs_failed_to_be_setup_mod_item_s& asn1_drb = - resp->drbs_failed_to_be_setup_mod_list.back()->drbs_failed_to_be_setup_mod_item(); - asn1_drb.drb_id = drb_id_to_uint(drb_id); - asn1_drb.cause_present = true; - asn1_drb.cause.set_radio_network().value = cause_radio_network_opts::no_radio_res_available; - } - - // DRBs-Modified-List + DRBs-FailedToBeModified-List. - for (const auto& req_drb : req->drbs_to_be_modified_list) { - drb_id_t drb_id = uint_to_drb_id(req_drb.value().drbs_to_be_modified_item().drb_id); - auto drb_it = std::find_if(du_response.drbs_configured.begin(), - du_response.drbs_configured.end(), - [drb_id](const f1ap_drb_configured& drb) { return drb.drb_id == drb_id; }); - if (drb_it != du_response.drbs_configured.end()) { - // > DRBs-Modified-List. - const f1ap_drb_configured& drb_mod = *drb_it; - resp->drbs_modified_list_present = true; - resp->drbs_modified_list.push_back({}); - resp->drbs_modified_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); - resp->drbs_modified_list.back().value().drbs_modified_item() = make_drbs_modified_item(drb_mod); - continue; - } - - // > DRBs-FailedToBeModified-List. - if (std::count(du_response.failed_drbs.begin(), du_response.failed_drbs.end(), drb_id) == 0) { - logger.warning("DRB{} was not found in the list of configured DRBs by the DU.", drb_id); - continue; - } - resp->drbs_failed_to_be_modified_list_present = true; - resp->drbs_failed_to_be_modified_list.push_back({}); - resp->drbs_failed_to_be_modified_list.back().load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_MODIFIED_ITEM); - drbs_failed_to_be_modified_item_s& asn1_drb = - resp->drbs_failed_to_be_modified_list.back()->drbs_failed_to_be_modified_item(); - asn1_drb.drb_id = drb_id_to_uint(drb_id); - asn1_drb.cause_present = true; - asn1_drb.cause.set_radio_network().value = cause_radio_network_opts::no_radio_res_available; - } + // DRBs-SetupMod-List + resp->drbs_setup_mod_list = make_drbs_setup_mod_list(du_response.drbs_setup); + resp->drbs_setup_mod_list_present = resp->drbs_setup_mod_list.size() > 0; + // DRBs-FailedToBeSetupMod-List + resp->drbs_failed_to_be_setup_mod_list = make_drbs_failed_to_be_setup_mod_list(du_response.failed_drbs_setups); + resp->drbs_failed_to_be_setup_mod_list_present = resp->drbs_failed_to_be_setup_mod_list.size() > 0; + // DRBs-Modified-List + resp->drbs_modified_list = make_drbs_modified_list(du_response.drbs_mod); + resp->drbs_modified_list_present = resp->drbs_modified_list.size() > 0; + // DRBs-FailedToBeModified-List + resp->drbs_failed_to_be_modified_list = make_drbs_failed_to_be_modified_list(du_response.failed_drb_mods); + resp->drbs_failed_to_be_modified_list_present = resp->drbs_failed_to_be_modified_list.size() > 0; resp->scell_failedto_setup_mod_list_present = false; resp->inactivity_monitoring_resp_present = false; diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index 109a5fcb32..4a36e4a0d8 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -131,7 +131,7 @@ async_task f1ap_du_ue_context_setup_procedure:: // > Pass DRBs to setup. for (const auto& drb : msg->drbs_to_be_setup_list) { - du_request.drbs_to_setupmod.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_item())); + du_request.drbs_to_setup.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_item())); } if (msg->cu_to_du_rrc_info.ie_exts_present) { @@ -192,27 +192,11 @@ void f1ap_du_ue_context_setup_procedure::send_ue_context_setup_response() } // > DRBs setup List. - resp->drbs_setup_list_present = not du_ue_cfg_response.drbs_configured.empty(); - if (resp->drbs_setup_list_present) { - resp->drbs_setup_list.resize(du_ue_cfg_response.drbs_configured.size()); - for (unsigned i = 0; i != resp->drbs_setup_list.size(); ++i) { - resp->drbs_setup_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_ITEM); - resp->drbs_setup_list[i].value().drbs_setup_item() = make_drbs_setup_item(du_ue_cfg_response.drbs_configured[i]); - } - } - - // > DRBs-FailedToBeSetupMod-List. - resp->drbs_failed_to_be_setup_list_present = not du_ue_cfg_response.failed_drbs.empty(); - if (resp->drbs_failed_to_be_setup_list_present) { - resp->drbs_failed_to_be_setup_list.resize(du_ue_cfg_response.failed_drbs.size()); - for (unsigned i = 0; i != du_ue_cfg_response.failed_drbs.size(); ++i) { - resp->drbs_failed_to_be_setup_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); - drbs_failed_to_be_setup_item_s& asn1_drb = resp->drbs_failed_to_be_setup_list[i]->drbs_failed_to_be_setup_item(); - asn1_drb.drb_id = drb_id_to_uint(du_ue_cfg_response.failed_drbs[i]); - asn1_drb.cause_present = true; - asn1_drb.cause.set_radio_network().value = cause_radio_network_opts::no_radio_res_available; - } - } + resp->drbs_setup_list = make_drbs_setup_list(du_ue_cfg_response.drbs_setup); + resp->drbs_setup_list_present = resp->drbs_setup_list.size() > 0; + // > DRBs-FailedToBeSetup-List. + resp->drbs_failed_to_be_setup_list = make_drbs_failed_to_be_setup_list(du_ue_cfg_response.failed_drbs_setups); + resp->drbs_failed_to_be_setup_list_present = resp->drbs_failed_to_be_setup_list.size() > 0; // Send Response to CU-CP. ue->f1ap_msg_notifier.on_new_message(f1ap_msg); diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index ff8fdfc904..e5c1460bd2 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -85,14 +85,13 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t } for (drb_id_t drb_id : drbs_to_addmod) { - req.drbs_to_setupmod.emplace_back(); - req.drbs_to_setupmod.back().drb_id = drb_id; - req.drbs_to_setupmod.back().mode = rlc_mode::am; - req.drbs_to_setupmod.back().five_qi = uint_to_five_qi(9); - req.drbs_to_setupmod.back().uluptnl_info_list.resize(1); - req.drbs_to_setupmod.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); - req.drbs_to_setupmod.back().uluptnl_info_list[0].tp_address = - transport_layer_address::create_from_string("127.0.0.1"); + req.drbs_to_setup.emplace_back(); + req.drbs_to_setup.back().drb_id = drb_id; + req.drbs_to_setup.back().mode = rlc_mode::am; + req.drbs_to_setup.back().five_qi = uint_to_five_qi(9); + req.drbs_to_setup.back().uluptnl_info_list.resize(1); + req.drbs_to_setup.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); + req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); } return req; diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index b53b43331f..85b745f52c 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -82,7 +82,7 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_config_request& drb : req.drbs_to_setupmod) { + for (const f1ap_drb_config_request& drb : req.drbs_to_setup) { cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 2f7640720e..127eba11ee 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -42,7 +42,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test this->cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_config_request& drb : req.drbs_to_setupmod) { + for (const f1ap_drb_config_request& drb : req.drbs_to_setup) { this->cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; @@ -78,7 +78,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test } } - ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), req.srbs_to_setup.size() + req.drbs_to_setupmod.size()); + ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), req.srbs_to_setup.size() + req.drbs_to_setup.size()); for (srb_id_t srb_id : req.srbs_to_setup) { auto srb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), @@ -99,7 +99,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test ASSERT_FALSE(srb_it->reestablish_rlc_present); } } - for (const f1ap_drb_config_request& drb : req.drbs_to_setupmod) { + for (const f1ap_drb_config_request& drb : req.drbs_to_setup) { auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), [&drb](const auto& b) { @@ -284,9 +284,9 @@ TEST_F(ue_config_tester, when_f1u_gw_fails_to_create_bearer_then_drb_is_included ASSERT_TRUE(proc.ready()); f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); - ASSERT_EQ(resp.drbs_configured.size(), 0); - ASSERT_EQ(resp.failed_drbs.size(), 1); - ASSERT_EQ(resp.failed_drbs[0], drb_id_t::drb1); + ASSERT_EQ(resp.drbs_setup.size(), 0); + ASSERT_EQ(resp.failed_drbs_setups.size(), 1); + ASSERT_EQ(resp.failed_drbs_setups[0].drb_id, drb_id_t::drb1); } TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_included_in_failed_list) @@ -294,7 +294,7 @@ TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_inc // Start Procedure. f1ap_ue_context_update_request req = create_f1ap_ue_context_update_request(test_ue->ue_index, {srb_id_t::srb2}, {drb_id_t::drb1}); - req.drbs_to_setupmod[0].uluptnl_info_list.clear(); + req.drbs_to_setup[0].uluptnl_info_list.clear(); start_procedure(req); // Check MAC received request to update UE configuration without the DRB that could not be created. @@ -317,9 +317,9 @@ TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_inc ASSERT_TRUE(proc.ready()); f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); - ASSERT_EQ(resp.drbs_configured.size(), 0); - ASSERT_EQ(resp.failed_drbs.size(), 1); - ASSERT_EQ(resp.failed_drbs[0], drb_id_t::drb1); + ASSERT_EQ(resp.drbs_setup.size(), 0); + ASSERT_EQ(resp.failed_drbs_setups.size(), 1); + ASSERT_EQ(resp.failed_drbs_setups[0].drb_id, drb_id_t::drb1); } TEST_F(ue_config_tester, when_config_is_empty_then_procedure_avoids_configuring_other_layers_and_returns_success) @@ -337,8 +337,8 @@ TEST_F(ue_config_tester, when_config_is_empty_then_procedure_avoids_configuring_ f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); ASSERT_FALSE(resp.du_to_cu_rrc_container.empty()); - ASSERT_TRUE(resp.drbs_configured.empty()); - ASSERT_TRUE(resp.failed_drbs.empty()); + ASSERT_TRUE(resp.drbs_setup.empty()); + ASSERT_TRUE(resp.failed_drbs_setups.empty()); } TEST_F(ue_config_tester, when_drbs_are_released_then_they_are_added_in_rrc_container) diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp index 490d49fe9d..ca5a046cc5 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp @@ -35,8 +35,8 @@ class f1ap_du_ue_context_modification_test : public f1ap_du_test // Prepare DU manager response to F1AP. this->f1ap_du_cfg_handler.next_ue_context_update_response.result = true; for (drb_id_t drb_id : drbs) { - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured.emplace_back(); - auto& drb = this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured.back(); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup.emplace_back(); + auto& drb = this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup.back(); drb.drb_id = drb_id; drb.dluptnl_info_list.resize(1); drb.dluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(test_rgen::uniform_int()); @@ -74,9 +74,9 @@ TEST_F(f1ap_du_ue_context_modification_test, when_f1ap_receives_request_then_f1a const f1ap_ue_context_update_request& req = *this->f1ap_du_cfg_handler.last_ue_context_update_req; ASSERT_EQ(req.ue_index, test_ue_index); ASSERT_EQ(req.srbs_to_setup.size(), 0); - ASSERT_EQ(req.drbs_to_setupmod.size(), 1); - ASSERT_EQ(req.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); - ASSERT_FALSE(req.drbs_to_setupmod[0].lcid.has_value()); + ASSERT_EQ(req.drbs_to_setup.size(), 1); + ASSERT_EQ(req.drbs_to_setup[0].drb_id, drb_id_t::drb1); + ASSERT_FALSE(req.drbs_to_setup[0].lcid.has_value()); } TEST_F(f1ap_du_ue_context_modification_test, @@ -100,10 +100,10 @@ TEST_F(f1ap_du_ue_context_modification_test, ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list.size(), 1); ASSERT_EQ( int_to_gtpu_teid(drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().gtp_teid.to_number()), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list[0].gtp_teid); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list[0].gtp_teid); ASSERT_EQ( drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().transport_layer_address.to_string(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0] + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0] .dluptnl_info_list[0] .tp_address.to_bitstring()); ASSERT_EQ(resp->du_to_cu_rrc_info.cell_group_cfg, @@ -115,7 +115,8 @@ TEST_F(f1ap_du_ue_context_modification_test, { // Prepare DU manager response to F1AP with failed DRB. this->f1ap_du_cfg_handler.next_ue_context_update_response.result = true; - this->f1ap_du_cfg_handler.next_ue_context_update_response.failed_drbs.push_back(drb_id_t::drb1); + this->f1ap_du_cfg_handler.next_ue_context_update_response.failed_drbs_setups.push_back( + {drb_id_t::drb1, f1ap_cause_radio_network_t::no_radio_res_available}); this->f1ap_du_cfg_handler.next_ue_context_update_response.du_to_cu_rrc_container = byte_buffer::create({0x1, 0x2, 0x3}).value(); diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index 64a8f45cb1..ca918fa045 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -67,13 +67,13 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test du_to_f1_resp.result = true; du_to_f1_resp.du_to_cu_rrc_container = byte_buffer::create({0x1, 0x2, 0x3}).value(); if (ue_ctx_setup.drbs_to_be_setup_list_present) { - du_to_f1_resp.drbs_configured.resize(ue_ctx_setup.drbs_to_be_setup_list.size()); + du_to_f1_resp.drbs_setup.resize(ue_ctx_setup.drbs_to_be_setup_list.size()); for (size_t i = 0; i < ue_ctx_setup.drbs_to_be_setup_list.size(); ++i) { - uint8_t drb_id = ue_ctx_setup.drbs_to_be_setup_list[i]->drbs_to_be_setup_item().drb_id; - du_to_f1_resp.drbs_configured[i].drb_id = uint_to_drb_id(drb_id); - du_to_f1_resp.drbs_configured[i].lcid = uint_to_lcid((uint8_t)LCID_MIN_DRB + drb_id); - du_to_f1_resp.drbs_configured[i].dluptnl_info_list.resize(1); - du_to_f1_resp.drbs_configured[i].dluptnl_info_list[0] = + uint8_t drb_id = ue_ctx_setup.drbs_to_be_setup_list[i]->drbs_to_be_setup_item().drb_id; + du_to_f1_resp.drbs_setup[i].drb_id = uint_to_drb_id(drb_id); + du_to_f1_resp.drbs_setup[i].lcid = uint_to_lcid((uint8_t)LCID_MIN_DRB + drb_id); + du_to_f1_resp.drbs_setup[i].dluptnl_info_list.resize(1); + du_to_f1_resp.drbs_setup[i].dluptnl_info_list[0] = up_transport_layer_info{transport_layer_address::create_from_string("127.0.0.1"), int_to_gtpu_teid(1)}; } } @@ -109,11 +109,11 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notif ASSERT_EQ(req.ue_index, test_ue->ue_index); ASSERT_EQ(req.srbs_to_setup.size(), 1); ASSERT_EQ(req.srbs_to_setup[0], srb_id_t::srb2); - ASSERT_EQ(req.drbs_to_setupmod.size(), 1); - ASSERT_EQ(req.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); - ASSERT_FALSE(req.drbs_to_setupmod[0].lcid.has_value()); - ASSERT_EQ(req.drbs_to_setupmod[0].mode, rlc_mode::am); - ASSERT_EQ(req.drbs_to_setupmod[0].pdcp_sn_len, pdcp_sn_size::size12bits); + ASSERT_EQ(req.drbs_to_setup.size(), 1); + ASSERT_EQ(req.drbs_to_setup[0].drb_id, drb_id_t::drb1); + ASSERT_FALSE(req.drbs_to_setup[0].lcid.has_value()); + ASSERT_EQ(req.drbs_to_setup[0].mode, rlc_mode::am); + ASSERT_EQ(req.drbs_to_setup[0].pdcp_sn_len, pdcp_sn_size::size12bits); } TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_responds_back_with_ue_context_setup_response) @@ -144,9 +144,9 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_respo ASSERT_EQ(drb_setup.drb_id, 1); ASSERT_TRUE(drb_setup.lcid_present); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list.size(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list.size()); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list.size()); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().gtp_teid.to_number(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list[0].gtp_teid); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list[0].gtp_teid); ASSERT_EQ(resp->du_to_cu_rrc_info.cell_group_cfg, this->f1ap_du_cfg_handler.next_ue_context_update_response.du_to_cu_rrc_container); } @@ -204,10 +204,10 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ ASSERT_TRUE(this->f1ap_du_cfg_handler.last_ue_context_update_req.has_value()); auto& request_to_du = *this->f1ap_du_cfg_handler.last_ue_context_update_req; ASSERT_EQ(test_ue->ue_index, request_to_du.ue_index); - ASSERT_EQ(request_to_du.drbs_to_setupmod.size(), 1); - ASSERT_EQ(request_to_du.drbs_to_setupmod[0].drb_id, drb_id_t::drb1); - ASSERT_EQ(request_to_du.drbs_to_setupmod[0].mode, rlc_mode::am); - ASSERT_EQ(request_to_du.drbs_to_setupmod[0].pdcp_sn_len, pdcp_sn_size::size12bits); + ASSERT_EQ(request_to_du.drbs_to_setup.size(), 1); + ASSERT_EQ(request_to_du.drbs_to_setup[0].drb_id, drb_id_t::drb1); + ASSERT_EQ(request_to_du.drbs_to_setup[0].mode, rlc_mode::am); + ASSERT_EQ(request_to_du.drbs_to_setup[0].pdcp_sn_len, pdcp_sn_size::size12bits); } TEST_F( @@ -235,9 +235,9 @@ TEST_F( ASSERT_EQ(drb_setup.drb_id, 1); ASSERT_TRUE(drb_setup.lcid_present); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list.size(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list.size()); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list.size()); ASSERT_EQ(drb_setup.dl_up_tnl_info_to_be_setup_list[0].dl_up_tnl_info.gtp_tunnel().gtp_teid.to_number(), - this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_configured[0].dluptnl_info_list[0].gtp_teid); + this->f1ap_du_cfg_handler.next_ue_context_update_response.drbs_setup[0].dluptnl_info_list[0].gtp_teid); } TEST_F(f1ap_du_test, f1ap_handles_precanned_ue_context_setup_request_correctly) From 5ce2268f6e2dab8c07a9dcf0fae3eddbc52deaa5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 2 Aug 2024 19:04:46 +0200 Subject: [PATCH 100/407] f1ap: remove cu-cp specific drb types from interface --- .../srsran/f1ap/common/ue_context_config.h | 21 ++- .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 64 ++++----- .../f1ap/du/f1ap_du_ue_context_update.h | 21 +-- .../pdu_session_resource_setup_routine.cpp | 6 +- .../routines/pdu_session_routine_helpers.cpp | 19 ++- .../routines/pdu_session_routine_helpers.h | 10 +- ...blishment_context_modification_routine.cpp | 7 +- .../procedures/ue_configuration_procedure.cpp | 6 +- .../du_ran_resource_manager_impl.cpp | 89 +++++-------- lib/f1ap/common/asn1_helpers.cpp | 111 +++++++++++++++- lib/f1ap/common/asn1_helpers.h | 31 ++++- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 26 ++-- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 43 ++---- .../procedures/ue_context_setup_procedure.cpp | 17 +-- .../procedures/f1ap_du_ue_context_common.cpp | 122 +----------------- .../du/procedures/f1ap_du_ue_context_common.h | 32 +---- ...p_du_ue_context_modification_procedure.cpp | 4 +- tests/unittests/cu_cp/test_helpers.h | 4 +- .../du_manager_procedure_test_helpers.cpp | 2 +- .../procedures/ue_configuration_test.cpp | 4 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 37 +----- ...ue_context_modification_procedure_test.cpp | 10 +- .../f1ap_du_ue_context_modification_test.cpp | 1 - ...1ap_du_ue_context_setup_procedure_test.cpp | 1 - 24 files changed, 291 insertions(+), 397 deletions(-) diff --git a/include/srsran/f1ap/common/ue_context_config.h b/include/srsran/f1ap/common/ue_context_config.h index bb8f1ebd86..e89846bc32 100644 --- a/include/srsran/f1ap/common/ue_context_config.h +++ b/include/srsran/f1ap/common/ue_context_config.h @@ -18,6 +18,13 @@ namespace srsran { +/// Parameters of a failed SRB setup in the DU UE context. +struct f1ap_srb_failed_to_setup { + srb_id_t srb_id = srb_id_t::nulltype; + /// Reason for the failure + std::optional cause; +}; + /// Parameters of a new DRB to be setup in the DU UE context. struct f1ap_drb_to_setup { /// DRB-Id of the new DRB. @@ -37,21 +44,23 @@ struct f1ap_drb_to_modify { drb_id_t drb_id = drb_id_t::invalid; /// UL Transport layer info for the given DRB. See ulUPTNLInformation-ToBeSetup-List in TS 38.473. std::vector uluptnl_info_list; - /// \brief PDCP SN length of the DRB. - /// \remark (Implementation-defined) We use the same length for DL and UL. - std::optional pdcp_sn_len; }; /// Parameters of a setup/modified DRB in the DU UE context. struct f1ap_drb_setupmod { - drb_id_t drb_id = drb_id_t::invalid; - std::optional lcid; + /// DRB-Id of the setup/modified DRB. + drb_id_t drb_id = drb_id_t::invalid; + /// LCID assigned to the setup/modified DRB. + std::optional lcid; + /// DL Transport layer info for the given DRB. std::vector dluptnl_info_list; }; /// Parameters of a failed DRB setup/modify in the DU UE context. struct f1ap_drb_failed_to_setupmod { - drb_id_t drb_id = drb_id_t::invalid; + /// DRB-Id of the failed to setup/modify DRB. + drb_id_t drb_id = drb_id_t::invalid; + /// Reason for the failure std::optional cause; }; diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index 8dee3e4a84..deb84380ef 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -151,15 +151,6 @@ struct f1ap_du_to_cu_rrc_info { byte_buffer requested_p_max_fr1; }; -using f1ap_drbs_setup_mod_item = f1ap_drb_setupmod; - -struct f1ap_srbs_failed_to_be_setup_mod_item { - srb_id_t srb_id = srb_id_t::nulltype; - std::optional cause; -}; - -using f1ap_drbs_failed_to_be_setup_mod_item = f1ap_drb_failed_to_setupmod; - struct f1ap_scell_failed_to_setup_mod_item { nr_cell_global_id_t scell_id; std::optional cause; @@ -180,16 +171,16 @@ struct f1ap_ue_context_setup_response { ue_index_t ue_index = ue_index_t::invalid; // UE Context Setup Response - f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; - std::optional c_rnti; - std::optional res_coordination_transfer_container; - std::optional full_cfg; - slotted_id_vector drbs_setup_list; - slotted_id_vector srbs_failed_to_be_setup_list; // max size = 8 - slotted_id_vector drbs_failed_to_be_setup_list; // max size = 64 - std::vector scell_failed_to_setup_list; // max size = 32 - std::optional inactivity_monitoring_resp; - slotted_id_vector srbs_setup_list; // max size = 8 + f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; + std::optional c_rnti; + std::optional res_coordination_transfer_container; + std::optional full_cfg; + slotted_id_vector drbs_setup_list; + slotted_id_vector srbs_failed_to_be_setup_list; + slotted_id_vector drbs_failed_to_be_setup_list; + std::vector scell_failed_to_setup_list; + std::optional inactivity_monitoring_resp; + slotted_id_vector srbs_setup_list; // max size = 8 // UE Context Setup Failure std::optional cause; @@ -207,11 +198,6 @@ struct f1ap_scell_to_be_remd_item { nr_cell_global_id_t scell_id; }; -struct f1ap_drbs_to_be_modified_item : public f1ap_drb_to_modify { - std::optional qos_info; - std::optional ul_cfg; -}; - struct f1ap_rlc_fail_ind { lcid_t assocated_lcid = lcid_t::INVALID_LCID; }; @@ -232,7 +218,7 @@ struct f1ap_ue_context_modification_request { std::vector scell_to_be_remd_list; slotted_id_vector srbs_to_be_setup_mod_list; slotted_id_vector drbs_to_be_setup_mod_list; - slotted_id_vector drbs_to_be_modified_list; + slotted_id_vector drbs_to_be_modified_list; std::vector srbs_to_be_released_list; std::vector drbs_to_be_released_list; std::optional inactivity_monitoring_request; @@ -258,20 +244,20 @@ struct f1ap_associated_scell_item { struct f1ap_ue_context_modification_response { bool success = false; // ue context modification response - byte_buffer res_coordination_transfer_container; - f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; - slotted_id_vector drbs_setup_mod_list; - slotted_id_vector drbs_modified_list; - slotted_id_vector srbs_failed_to_be_setup_mod_list; - slotted_id_vector drbs_failed_to_be_setup_mod_list; - std::vector scell_failed_to_setup_mod_list; - slotted_id_vector drbs_failed_to_be_modified_list; - std::optional inactivity_monitoring_resp; - std::optional c_rnti; - std::vector associated_scell_list; - slotted_id_vector srbs_setup_mod_list; - slotted_id_vector srbs_modified_list; - std::optional full_cfg; + byte_buffer res_coordination_transfer_container; + f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; + slotted_id_vector drbs_setup_list; + slotted_id_vector drbs_modified_list; + slotted_id_vector srbs_failed_to_be_setup_list; + slotted_id_vector drbs_failed_to_be_setup_list; + std::vector scell_failed_to_be_setup_list; + slotted_id_vector drbs_failed_to_be_modified_list; + std::optional inactivity_monitoring_resp; + std::optional c_rnti; + std::vector associated_scell_list; + slotted_id_vector srbs_setup_mod_list; + slotted_id_vector srbs_modified_list; + std::optional full_cfg; // UE Context Modification Failure std::optional cause; diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 0428f1e4b2..7a27fc00fd 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -38,19 +38,12 @@ struct f1ap_ue_context_creation_response { }; /// \brief DRB to be setup or modify in the UE context. -struct f1ap_drb_config_request { - drb_id_t drb_id; - std::optional lcid; - /// \brief RLC mode. If it is a new bearer to setup, this field is present. If it is an existing bearer that needs - /// to be modified, this field is absent. - std::optional mode; - pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; - five_qi_t five_qi; - uint8_t arp_priority_level; - s_nssai_t s_nssai; +struct f1ap_drb_setup_request : public f1ap_drb_to_setup { + five_qi_t five_qi; + uint8_t arp_priority_level; + s_nssai_t s_nssai; /// GBR flow information is present only for GBR QoS flows. See TS 38.473, clause 9.3.1.45. - std::optional gbr_flow_info; - std::vector uluptnl_info_list; + std::optional gbr_flow_info; }; /// \brief SCell to be setup in the UE context. @@ -64,9 +57,9 @@ struct f1ap_ue_context_update_request { du_ue_index_t ue_index; std::vector srbs_to_setup; /// List of new DRBs to setup. - std::vector drbs_to_setup; + std::vector drbs_to_setup; /// List of DRBs to modify. - std::vector drbs_to_mod; + std::vector drbs_to_mod; /// List of DRBs to remove. std::vector drbs_to_rem; std::vector scells_to_setup; diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 52b309a0b1..1fd215a2fa 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -338,14 +338,14 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r const srslog::basic_logger& logger) { // Fail procedure if (single) DRB couldn't be setup - if (!ue_context_modification_response.drbs_failed_to_be_setup_mod_list.empty()) { + if (!ue_context_modification_response.drbs_failed_to_be_setup_list.empty()) { logger.warning("Couldn't setup {} DRBs at DU", - ue_context_modification_response.drbs_failed_to_be_setup_mod_list.size()); + ue_context_modification_response.drbs_failed_to_be_setup_list.size()); return false; } if (!update_setup_list( - bearer_ctxt_mod_request, ue_context_modification_response.drbs_setup_mod_list, next_config, logger)) { + bearer_ctxt_mod_request, ue_context_modification_response.drbs_setup_list, next_config, logger)) { return false; } diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index b3f9fc82a4..e44b6028ad 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -606,7 +606,7 @@ bool srsran::srs_cu_cp::update_modify_list( void srsran::srs_cu_cp::fill_e1ap_bearer_context_list( slotted_id_vector& e1ap_list, - const slotted_id_vector& drb_setup_items, + const slotted_id_vector& drb_setup_items, const std::map& pdu_sessions_update_list) { /// Iterate over all PDU sessions to be updated and match the containing DRBs. @@ -683,14 +683,14 @@ bool srsran::srs_cu_cp::update_modify_list( const srslog::basic_logger& logger) { // Fail procedure if (single) DRB couldn't be setup - if (!ue_context_modification_response.drbs_failed_to_be_setup_mod_list.empty()) { + if (!ue_context_modification_response.drbs_failed_to_be_setup_list.empty()) { logger.warning("Couldn't setup {} DRBs at DU", - ue_context_modification_response.drbs_failed_to_be_setup_mod_list.size()); + ue_context_modification_response.drbs_failed_to_be_setup_list.size()); return false; } // Only prepare bearer context modifcation request if needed - if (ue_context_modification_response.drbs_setup_mod_list.empty() and + if (ue_context_modification_response.drbs_setup_list.empty() and ue_context_modification_response.drbs_modified_list.empty()) { // No DRB added or updated. logger.debug("Skipping preparation of bearer context modification request"); @@ -703,7 +703,7 @@ bool srsran::srs_cu_cp::update_modify_list( bearer_ctxt_mod_request.ng_ran_bearer_context_mod_request.emplace(); fill_e1ap_bearer_context_list(e1ap_bearer_context_mod.pdu_session_res_to_modify_list, - ue_context_modification_response.drbs_setup_mod_list, + ue_context_modification_response.drbs_setup_list, next_config.pdu_sessions_to_modify_list); #if 0 @@ -718,11 +718,10 @@ bool srsran::srs_cu_cp::update_modify_list( return ue_context_modification_response.success; } -bool srsran::srs_cu_cp::update_setup_list( - e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const slotted_id_vector& drb_setup_mod_list, - const up_config_update& next_config, - const srslog::basic_logger& logger) +bool srsran::srs_cu_cp::update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const slotted_id_vector& drb_setup_mod_list, + const up_config_update& next_config, + const srslog::basic_logger& logger) { // Start with empty message. e1ap_ng_ran_bearer_context_mod_request& e1ap_bearer_context_mod = diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index 1344a8c46d..c590bf387a 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -30,7 +30,7 @@ void fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_item& e1ap_qos_i const qos_flow_setup_request_item& request_item); void fill_e1ap_bearer_context_list( slotted_id_vector& e1ap_list, - const slotted_id_vector& drb_setup_items, + const slotted_id_vector& drb_setup_items, const std::map& pdu_sessions_update_list); void fill_e1ap_pdu_session_res_to_setup_list( slotted_id_vector& pdu_session_res_to_setup_list, @@ -94,10 +94,10 @@ bool update_setup_list(slotted_id_vector& drb_setup_mod_list, - const up_config_update& next_config, - const srslog::basic_logger& logger); +bool update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const slotted_id_vector& drb_setup_mod_list, + const up_config_update& next_config, + const srslog::basic_logger& logger); void update_failed_list( slotted_id_vector& ngap_failed_list, diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index dd132b2ade..ee73baec29 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -264,9 +264,8 @@ bool reestablishment_context_modification_routine::generate_bearer_context_modif bool reestablish_pdcp) { // Fail procedure if (single) DRB couldn't be setup - if (!ue_context_modification_resp.drbs_failed_to_be_setup_mod_list.empty()) { - logger.warning("Couldn't setup {} DRBs at DU", - ue_context_modification_resp.drbs_failed_to_be_setup_mod_list.size()); + if (!ue_context_modification_resp.drbs_failed_to_be_setup_list.empty()) { + logger.warning("Couldn't setup {} DRBs at DU", ue_context_modification_resp.drbs_failed_to_be_setup_list.size()); return false; } @@ -299,7 +298,7 @@ bool reestablishment_context_modification_routine::generate_bearer_context_modif e1ap_pdu_session_res_to_modify_item e1ap_mod_item; e1ap_mod_item.pdu_session_id = pdu_session.pdu_session_id; - for (const auto& drb_item : ue_context_modification_resp.drbs_setup_mod_list) { + for (const auto& drb_item : ue_context_modification_resp.drbs_setup_list) { // Only include the DRB if it belongs to the this session. if (pdu_session.drb_modified_list_ng_ran.contains(drb_item.drb_id)) { // DRB belongs to this PDU session diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index b0c76c6d0f..1b63dfe3e7 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -135,7 +135,7 @@ void ue_configuration_procedure::update_ue_context() } // > Create new DU UE DRB objects. - for (const f1ap_drb_config_request& drbtoadd : request.drbs_to_setup) { + for (const f1ap_drb_setup_request& drbtoadd : request.drbs_to_setup) { if (drbtoadd.uluptnl_info_list.empty()) { proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtoadd.drb_id); continue; @@ -246,7 +246,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo resp.result = true; // > Handle DRBs that were setup or failed to be setup. - for (const f1ap_drb_config_request& drb_req : request.drbs_to_setup) { + for (const f1ap_drb_setup_request& drb_req : request.drbs_to_setup) { if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { resp.failed_drbs_setups.push_back({drb_req.drb_id, f1ap_cause_radio_network_t::no_radio_res_available}); continue; @@ -260,7 +260,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo } // > Handle DRBs that were modified or failed to be modified. - for (const f1ap_drb_config_request& drb_req : request.drbs_to_mod) { + for (const f1ap_drb_to_modify& drb_req : request.drbs_to_mod) { if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { resp.failed_drb_mods.push_back({drb_req.drb_id, f1ap_cause_radio_network_t::unknown_drb_id}); continue; diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index 9d919a04f9..cbdd2f6f6d 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -97,10 +97,22 @@ ue_ran_resource_configurator du_ran_resource_manager_impl::create_ue_resource_co return ue_ran_resource_configurator{std::make_unique(&mcg, *this, ue_index)}; } -static expected -validate_drb_config_request(const f1ap_drb_config_request& drb, - span rlc_bearers, - const std::map& qos_config) +static error_type validate_drb_modification_request(const f1ap_drb_to_modify& drb, + span rlc_bearers) +{ + // Search for established DRB with matching DRB-Id. + auto prev_drb_it = std::find_if(rlc_bearers.begin(), rlc_bearers.end(), [&drb](const rlc_bearer_config& item) { + return item.drb_id.has_value() and item.drb_id.value() == drb.drb_id; + }); + if (prev_drb_it == rlc_bearers.end()) { + return make_unexpected(fmt::format("Failed to modify {}. Cause: DRB not found", drb.drb_id)); + } + return {}; +} + +static error_type validate_drb_setup_request(const f1ap_drb_setup_request& drb, + span rlc_bearers, + const std::map& qos_config) { // Validate QOS config. auto qos_it = qos_config.find(drb.five_qi); @@ -108,7 +120,7 @@ validate_drb_config_request(const f1ap_drb_config_request& drb, return make_unexpected(fmt::format("Failed to allocate {}. Cause: No {} 5QI configured", drb.drb_id, drb.five_qi)); } const du_qos_config& qos = qos_it->second; - if (drb.mode.has_value() and qos.rlc.mode != *drb.mode) { + if (qos.rlc.mode != drb.mode) { return make_unexpected( fmt::format("RLC mode mismatch for {}. QoS config for {} configures {} but CU-CP requested {}", drb.drb_id, @@ -121,35 +133,8 @@ validate_drb_config_request(const f1ap_drb_config_request& drb, auto prev_drb_it = std::find_if(rlc_bearers.begin(), rlc_bearers.end(), [&drb](const rlc_bearer_config& item) { return item.drb_id.has_value() and item.drb_id.value() == drb.drb_id; }); - bool new_drb = prev_drb_it == rlc_bearers.end(); - - if (new_drb) { - if (not drb.mode.has_value()) { - // RLC mode needs to be specified. - return make_unexpected(fmt::format("Failed to allocate {}. Cause: RLC mode not specified", drb.drb_id)); - } - - // CU-assigned LCID. - if (drb.lcid.has_value()) { - if (std::any_of( - rlc_bearers.begin(), rlc_bearers.end(), [&drb](const auto& item) { return *drb.lcid == item.lcid; })) { - return make_unexpected(fmt::format( - "Failed to allocate {}. Cause: Specified lcid={} already exists", drb.drb_id, drb.lcid.value())); - } - } - } else { - // Modified DRB - if (drb.mode.has_value() and drb.mode.value() != prev_drb_it->rlc_cfg.mode) { - // RLC mode cannot be changed. - return make_unexpected( - fmt::format("Failed to configure {}. Cause: RLC mode cannot be changed for an existing DRB", drb.drb_id)); - } - - if (drb.lcid.has_value() and drb.lcid.value() != prev_drb_it->lcid) { - // LCID cannot be changed. - return make_unexpected( - fmt::format("Failed to configure {}. Cause: LCID cannot be changed for an existing DRB", drb.drb_id)); - } + if (prev_drb_it != rlc_bearers.end()) { + return make_unexpected(fmt::format("Failed to allocate {}. Cause: DRB already exists", drb.drb_id)); } return {}; @@ -212,33 +197,22 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } - // > Allocate new DRBs. - for (const f1ap_drb_config_request& drb : upd_req.drbs_to_setup) { - auto res = validate_drb_config_request(drb, ue_mcg.rlc_bearers, qos_config); + // > Create new DRBs. + for (const f1ap_drb_setup_request& drb : upd_req.drbs_to_setup) { + auto res = validate_drb_setup_request(drb, ue_mcg.rlc_bearers, qos_config); if (not res.has_value()) { resp.failed_drbs.push_back(drb.drb_id); continue; } - bool new_drb = res.value() == nullptr; - if (not new_drb) { + + // > Allocate LCID. + lcid_t lcid = find_empty_lcid(ue_mcg.rlc_bearers); + if (lcid > LCID_MAX_DRB) { + logger.warning("Failed to allocate {}. Cause: No available LCIDs", drb.drb_id); resp.failed_drbs.push_back(drb.drb_id); continue; } - lcid_t lcid; - if (drb.lcid.has_value()) { - // >> CU-assigned LCID. - lcid = *drb.lcid; - } else { - // >> Allocate LCID if not specified by F1AP. - lcid = find_empty_lcid(ue_mcg.rlc_bearers); - if (lcid > LCID_MAX_DRB) { - logger.warning("Failed to allocate {}. Cause: No available LCIDs", drb.drb_id); - resp.failed_drbs.push_back(drb.drb_id); - continue; - } - } - // >> Get RLC config from 5QI const du_qos_config& qos = qos_config.at(drb.five_qi); ue_mcg.rlc_bearers.emplace_back(); @@ -262,17 +236,12 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } // > Modify existing DRBs. - for (const f1ap_drb_config_request& drb : upd_req.drbs_to_mod) { - auto res = validate_drb_config_request(drb, ue_mcg.rlc_bearers, qos_config); + for (const f1ap_drb_to_modify& drb : upd_req.drbs_to_mod) { + auto res = validate_drb_modification_request(drb, ue_mcg.rlc_bearers); if (not res.has_value()) { resp.failed_drbs.push_back(drb.drb_id); continue; } - bool new_drb = res.value() == nullptr; - if (new_drb) { - resp.failed_drbs.push_back(drb.drb_id); - continue; - } // TODO: Support DRB modification. } // >> Sort by LCID. diff --git a/lib/f1ap/common/asn1_helpers.cpp b/lib/f1ap/common/asn1_helpers.cpp index ca8956f7a7..ffdddd3ca0 100644 --- a/lib/f1ap/common/asn1_helpers.cpp +++ b/lib/f1ap/common/asn1_helpers.cpp @@ -9,7 +9,8 @@ */ #include "asn1_helpers.h" -#include "srsran/ran/bcd_helper.h" +#include "../cu_cp/f1ap_asn1_converters.h" +#include "srsran/asn1/f1ap/common.h" using namespace srsran; @@ -49,3 +50,111 @@ asn1::f1ap::pdcp_sn_len_e srsran::pdcp_sn_size_to_f1ap_asn1(pdcp_sn_size sn_size return asn1::f1ap::pdcp_sn_len_opts::nulltype; } } + +// helper function to fill asn1 DRBs-SetupMod and DRBs-Modified types. +template +static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_setupmod& drb) +{ + asn1obj.drb_id = drb_id_to_uint(drb.drb_id); + asn1obj.lcid_present = drb.lcid.has_value(); + if (asn1obj.lcid_present) { + asn1obj.lcid = drb.lcid.value(); + } + asn1obj.dl_up_tnl_info_to_be_setup_list.resize(drb.dluptnl_info_list.size()); + for (unsigned j = 0; j != drb.dluptnl_info_list.size(); ++j) { + up_transport_layer_info_to_asn1(asn1obj.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, + drb.dluptnl_info_list[j]); + } +} + +std::vector +srsran::make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l& asn1_list) +{ + std::vector uluptnl_info_list; + uluptnl_info_list.reserve(asn1_list.size()); + for (const auto& tnl_info : asn1_list) { + uluptnl_info_list.push_back(asn1_to_up_transport_layer_info(tnl_info.ul_up_tnl_info)); + } + return uluptnl_info_list; +} + +f1ap_drb_to_modify srsran::make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item) +{ + f1ap_drb_to_modify drb_obj; + drb_obj.drb_id = static_cast(drb_item.drb_id); + drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(drb_item.ul_up_tnl_info_to_be_setup_list); + return drb_obj; +} + +asn1::f1ap::drbs_setup_list_l srsran::make_drbs_setup_list(span drbs) +{ + asn1::f1ap::drbs_setup_list_l list(drbs.size()); + for (unsigned i = 0; i != drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_ITEM); + fill_drb_setup_mod_common(list[i]->drbs_setup_item(), drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_setup_mod_list_l srsran::make_drbs_setup_mod_list(span drbs) +{ + asn1::f1ap::drbs_setup_mod_list_l list(drbs.size()); + for (unsigned i = 0; i != drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); + fill_drb_setup_mod_common(list[i]->drbs_setup_mod_item(), drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_modified_list_l srsran::make_drbs_modified_list(span drbs) +{ + asn1::f1ap::drbs_modified_list_l list(drbs.size()); + for (unsigned i = 0; i != drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); + fill_drb_setup_mod_common(list[i]->drbs_modified_item(), drbs[i]); + } + return list; +} + +template +void fill_drb_failed_item(ASN1Type& asn1obj, const f1ap_drb_failed_to_setupmod& drb_obj) +{ + asn1obj.drb_id = drb_id_to_uint(drb_obj.drb_id); + asn1obj.cause_present = drb_obj.cause.has_value(); + if (asn1obj.cause_present) { + asn1obj.cause = srs_cu_cp::cause_to_asn1(drb_obj.cause.value()); + } +} + +asn1::f1ap::drbs_failed_to_be_setup_list_l +srsran::make_drbs_failed_to_be_setup_list(span failed_drbs) +{ + asn1::f1ap::drbs_failed_to_be_setup_list_l list(failed_drbs.size()); + for (unsigned i = 0; i != failed_drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_ITEM); + fill_drb_failed_item(list[i]->drbs_failed_to_be_setup_item(), failed_drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_failed_to_be_setup_mod_list_l +srsran::make_drbs_failed_to_be_setup_mod_list(span failed_drbs) +{ + asn1::f1ap::drbs_failed_to_be_setup_mod_list_l list(failed_drbs.size()); + for (unsigned i = 0; i != failed_drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); + fill_drb_failed_item(list[i]->drbs_failed_to_be_setup_mod_item(), failed_drbs[i]); + } + return list; +} + +asn1::f1ap::drbs_failed_to_be_modified_list_l +srsran::make_drbs_failed_to_be_modified_list(span failed_drbs) +{ + asn1::f1ap::drbs_failed_to_be_modified_list_l list(failed_drbs.size()); + for (unsigned i = 0; i != failed_drbs.size(); ++i) { + list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_MODIFIED_ITEM); + fill_drb_failed_item(list[i]->drbs_failed_to_be_modified_item(), failed_drbs[i]); + } + return list; +} diff --git a/lib/f1ap/common/asn1_helpers.h b/lib/f1ap/common/asn1_helpers.h index ed7f833f60..392d73249c 100644 --- a/lib/f1ap/common/asn1_helpers.h +++ b/lib/f1ap/common/asn1_helpers.h @@ -10,12 +10,22 @@ #pragma once -#include "srsran/asn1/f1ap/f1ap_ies.h" +#include "srsran/asn1/f1ap/f1ap_pdu_items.h" +#include "srsran/f1ap/common/ue_context_config.h" #include "srsran/pdcp/pdcp_sn_size.h" #include "srsran/ran/nr_cgi.h" namespace srsran { +/// \brief Extracts a \c drb_id_t from ASN.1 DRB Setup/Modified/Remove type. +/// \param drb_item ASN.1 item with DRB-Id. +/// \return drb_id_t object. +template +drb_id_t get_drb_id(const Asn1Type& drb_item) +{ + return static_cast(drb_item.drb_id); +} + /// \brief Converts ASN.1 CGI typo into internal struct. It also performs the byte to MCC/MNC conversion. /// \param[in] asn1_cgi The ASN.1 encoded NR-CGI. /// \return The CGI converted to flat internal struct. @@ -24,4 +34,23 @@ expected cgi_from_asn1(const asn1::f1ap::nr_cgi_s& asn1_cgi pdcp_sn_size pdcp_sn_size_from_f1ap_asn1(const asn1::f1ap::pdcp_sn_len_e& asn1_pdcp_sn_size); asn1::f1ap::pdcp_sn_len_e pdcp_sn_size_to_f1ap_asn1(pdcp_sn_size sn_size); +std::vector +make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l& asn1_list); + +/// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_to_modify. +f1ap_drb_to_modify make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); + +/// Convert F1AP setup/modified types to respective ASN.1 TS 48.473 types. +asn1::f1ap::drbs_setup_list_l make_drbs_setup_list(span drbs); +asn1::f1ap::drbs_setup_mod_list_l make_drbs_setup_mod_list(span drbs); +asn1::f1ap::drbs_modified_list_l make_drbs_modified_list(span drbs); + +/// Convert F1AP failed to setup/modify types to respective ASN.1 TS 48.473 types. +asn1::f1ap::drbs_failed_to_be_setup_list_l +make_drbs_failed_to_be_setup_list(span failed_drbs); +asn1::f1ap::drbs_failed_to_be_setup_mod_list_l +make_drbs_failed_to_be_setup_mod_list(span failed_drbs); +asn1::f1ap::drbs_failed_to_be_modified_list_l +make_drbs_failed_to_be_modified_list(span failed_drbs); + } // namespace srsran diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index b82217c144..d42148782d 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -716,9 +716,9 @@ inline nr_cell_global_id_t f1ap_asn1_to_nr_cgi(const asn1::f1ap::nr_cgi_s& asn1_ /// \param[in] asn1_drbs_to_be_setup_mod_item The ASN.1 drbs setup/setup mod item struct. /// \return The drbs setup/setup item mod common type struct. template -inline f1ap_drbs_setup_mod_item asn1_to_f1ap_drbs_setup_mod_item(const template_asn1_item& asn1_drbs_setup_mod_item) +inline f1ap_drb_setupmod asn1_to_f1ap_drbs_setup_mod_item(const template_asn1_item& asn1_drbs_setup_mod_item) { - f1ap_drbs_setup_mod_item drb_setup_mod_item; + f1ap_drb_setupmod drb_setup_mod_item; // drb id drb_setup_mod_item.drb_id = uint_to_drb_id(asn1_drbs_setup_mod_item.drb_id); @@ -740,36 +740,36 @@ inline f1ap_drbs_setup_mod_item asn1_to_f1ap_drbs_setup_mod_item(const template_ /// \param[in] asn1_srbs_failed_to_be_setup_mod_item The ASN.1 srbs failed to be setup/setup mod item struct. /// \return The srbs failed to be setup/setup item mod common type struct. template -inline f1ap_srbs_failed_to_be_setup_mod_item +inline f1ap_srb_failed_to_setup asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(const template_asn1_item& asn1_srbs_failed_to_be_setup_mod_item) { - f1ap_srbs_failed_to_be_setup_mod_item srbs_failed_to_be_setup_mod_item; + f1ap_srb_failed_to_setup item; // srb id - srbs_failed_to_be_setup_mod_item.srb_id = int_to_srb_id(asn1_srbs_failed_to_be_setup_mod_item.srb_id); + item.srb_id = int_to_srb_id(asn1_srbs_failed_to_be_setup_mod_item.srb_id); if (asn1_srbs_failed_to_be_setup_mod_item.cause_present) { - srbs_failed_to_be_setup_mod_item.cause = asn1_to_cause(asn1_srbs_failed_to_be_setup_mod_item.cause); + item.cause = asn1_to_cause(asn1_srbs_failed_to_be_setup_mod_item.cause); } - return srbs_failed_to_be_setup_mod_item; + return item; } -// \brief Convert F1AP ASN.1 drbs failed to be setup/setup mod item to common type. +/// \brief Convert F1AP ASN.1 drbs failed to be setup/setup mod item to common type. /// \param[in] asn1_drbs_failed_to_be_setup_mod_item The ASN.1 drbs failed to be setup/setup mod item struct. /// \return The drbs failed to be setup/setup item mod common type struct. template -inline f1ap_drbs_failed_to_be_setup_mod_item +inline f1ap_drb_failed_to_setupmod asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(const template_asn1_item& asn1_drbs_failed_to_be_setup_mod_item) { - f1ap_drbs_failed_to_be_setup_mod_item drbs_failed_to_be_setup_mod_item; + f1ap_drb_failed_to_setupmod item; // drb id - drbs_failed_to_be_setup_mod_item.drb_id = uint_to_drb_id(asn1_drbs_failed_to_be_setup_mod_item.drb_id); + item.drb_id = uint_to_drb_id(asn1_drbs_failed_to_be_setup_mod_item.drb_id); if (asn1_drbs_failed_to_be_setup_mod_item.cause_present) { - drbs_failed_to_be_setup_mod_item.cause = asn1_to_cause(asn1_drbs_failed_to_be_setup_mod_item.cause); + item.cause = asn1_to_cause(asn1_drbs_failed_to_be_setup_mod_item.cause); } - return drbs_failed_to_be_setup_mod_item; + return item; } /// \brief Convert F1AP ASN.1 srbs setup/setup mod item to common type. diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index b325625551..5bee3fa783 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -176,12 +176,6 @@ inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod auto& asn1_drb_to_be_modified_item = asn1_drb_to_be_modified_item_container.value().drbs_to_be_modified_item(); asn1_drb_to_be_modified_item.drb_id = drb_id_to_uint(drb_to_be_modified_item.drb_id); - // qos info - if (drb_to_be_modified_item.qos_info.has_value()) { - asn1_drb_to_be_modified_item.qos_info_present = true; - asn1_drb_to_be_modified_item.qos_info = f1ap_qos_info_to_asn1(drb_to_be_modified_item.qos_info.value()); - } - // ul up tnl info to be setup list for (const auto& ul_up_tnl_info_item : drb_to_be_modified_item.uluptnl_info_list) { asn1::f1ap::ul_up_tnl_info_to_be_setup_item_s item; @@ -189,14 +183,6 @@ inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod asn1_drb_to_be_modified_item.ul_up_tnl_info_to_be_setup_list.push_back(item); } - // ul cfg - if (drb_to_be_modified_item.ul_cfg.has_value()) { - asn1_drb_to_be_modified_item.ul_cfg_present = true; - - asn1_drb_to_be_modified_item.ul_cfg.ul_ue_cfg = - f1ap_ul_ue_cfg_to_asn1(drb_to_be_modified_item.ul_cfg.value().ul_ue_cfg); - } - asn1_request->drbs_to_be_modified_list.push_back(asn1_drb_to_be_modified_item_container); } } @@ -332,9 +318,8 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat for (auto asn1_drb_setup_mod_list_item : asn1_response->drbs_setup_mod_list) { auto& asn1_drb_mod_item = asn1_drb_setup_mod_list_item.value().drbs_setup_mod_item(); - f1ap_drbs_setup_mod_item drb_setup_mod_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); - - res.drbs_setup_mod_list.emplace(drb_setup_mod_item.drb_id, drb_setup_mod_item); + f1ap_drb_setupmod mod_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); + res.drbs_setup_list.emplace(mod_item.drb_id, mod_item); } } @@ -343,9 +328,9 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat for (auto asn1_drbs_modified_list_item : asn1_response->drbs_modified_list) { auto& asn1_drb_mod_item = asn1_drbs_modified_list_item.value().drbs_modified_item(); - f1ap_drbs_setup_mod_item drb_setup_mod_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); + f1ap_drb_setupmod mod_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); - res.drbs_modified_list.emplace(drb_setup_mod_item.drb_id, drb_setup_mod_item); + res.drbs_modified_list.emplace(mod_item.drb_id, mod_item); } } @@ -354,10 +339,8 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat for (auto asn1_srbs_failed_setup_mod_list_item : asn1_response->srbs_failed_to_be_setup_mod_list) { auto& asn1_srb_failed_item = asn1_srbs_failed_setup_mod_list_item.value().srbs_failed_to_be_setup_mod_item(); - f1ap_srbs_failed_to_be_setup_mod_item srb_failed_item = - asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item); - - res.srbs_failed_to_be_setup_mod_list.emplace(srb_failed_item.srb_id, srb_failed_item); + f1ap_srb_failed_to_setup srb_item = asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item); + res.srbs_failed_to_be_setup_list.emplace(srb_item.srb_id, srb_item); } } @@ -366,10 +349,8 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat for (auto asn1_drbs_failed_setup_mod_list_item : asn1_response->drbs_failed_to_be_setup_mod_list) { auto& asn1_drb_failed_item = asn1_drbs_failed_setup_mod_list_item.value().drbs_failed_to_be_setup_mod_item(); - f1ap_drbs_failed_to_be_setup_mod_item drb_failed_item = - asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - - res.drbs_failed_to_be_setup_mod_list.emplace(drb_failed_item.drb_id, drb_failed_item); + f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); + res.drbs_failed_to_be_setup_list.emplace(drb_item.drb_id, drb_item); } } @@ -383,7 +364,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_scell_failed_item.cause_present) { scell_failed_item.cause = asn1_to_cause(asn1_scell_failed_item.cause); } - res.scell_failed_to_setup_mod_list.push_back(scell_failed_item); + res.scell_failed_to_be_setup_list.push_back(scell_failed_item); } } @@ -392,10 +373,8 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat for (auto asn1_drbs_failed_modified_list_item : asn1_response->drbs_failed_to_be_modified_list) { auto& asn1_drb_failed_item = asn1_drbs_failed_modified_list_item.value().drbs_failed_to_be_modified_item(); - f1ap_drbs_failed_to_be_setup_mod_item drb_failed_item = - asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - - res.drbs_failed_to_be_modified_list.emplace(drb_failed_item.drb_id, drb_failed_item); + f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); + res.drbs_failed_to_be_modified_list.emplace(drb_item.drb_id, drb_item); } } diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index 49fc4146d7..632d4b2f52 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -437,9 +437,8 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& for (auto asn1_drbs_setup_list_item : asn1_response->drbs_setup_list) { auto& asn1_drb_mod_item = asn1_drbs_setup_list_item.value().drbs_setup_item(); - f1ap_drbs_setup_mod_item drb_setup_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); - - response.drbs_setup_list.emplace(drb_setup_item.drb_id, drb_setup_item); + f1ap_drb_setupmod drb_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); + response.drbs_setup_list.emplace(drb_item.drb_id, drb_item); } } @@ -448,10 +447,8 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& for (auto asn1_srbs_failed_setup_list_item : asn1_response->srbs_failed_to_be_setup_list) { auto& asn1_srb_failed_item = asn1_srbs_failed_setup_list_item.value().srbs_failed_to_be_setup_item(); - f1ap_srbs_failed_to_be_setup_mod_item srb_failed_item = - asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item); - - response.srbs_failed_to_be_setup_list.emplace(srb_failed_item.srb_id, srb_failed_item); + f1ap_srb_failed_to_setup srb_item = asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item); + response.srbs_failed_to_be_setup_list.emplace(srb_item.srb_id, srb_item); } } @@ -460,10 +457,8 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& for (auto asn1_drbs_failed_setup_list_item : asn1_response->drbs_failed_to_be_setup_list) { auto& asn1_drb_failed_item = asn1_drbs_failed_setup_list_item.value().drbs_failed_to_be_setup_item(); - f1ap_drbs_failed_to_be_setup_mod_item drb_failed_item = - asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - - response.drbs_failed_to_be_setup_list.emplace(drb_failed_item.drb_id, drb_failed_item); + f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); + response.drbs_failed_to_be_setup_list.emplace(drb_item.drb_id, drb_item); } } diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp index 959c433de2..391e2f9cd0 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -9,7 +9,6 @@ */ #include "f1ap_du_ue_context_common.h" -#include "../../cu_cp/f1ap_asn1_converters.h" #include "srsran/asn1/f1ap/common.h" using namespace srsran; @@ -33,14 +32,10 @@ static rlc_mode get_rlc_mode(const asn1::f1ap::rlc_mode_e& asn1type) } template -static void fill_common_drb_config_request_fields(f1ap_drb_config_request& drb_obj, const ASN1Type& drb_item) +static void fill_common_drb_config_request_fields(f1ap_drb_setup_request& drb_obj, const ASN1Type& drb_item) { - drb_obj.drb_id = static_cast(drb_item.drb_id); - - drb_obj.uluptnl_info_list.reserve(drb_item.ul_up_tnl_info_to_be_setup_list.size()); - for (const auto& tnl_info : drb_item.ul_up_tnl_info_to_be_setup_list) { - drb_obj.uluptnl_info_list.push_back(asn1_to_up_transport_layer_info(tnl_info.ul_up_tnl_info)); - } + drb_obj.drb_id = static_cast(drb_item.drb_id); + drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(drb_item.ul_up_tnl_info_to_be_setup_list); // TODO: Handle Dynamic 5QI. const auto& asn1_drbinfo = drb_item.qos_info.choice_ext().value().drb_info(); @@ -67,9 +62,9 @@ static void fill_common_drb_config_request_fields(f1ap_drb_config_request& drb_o } } -f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) +f1ap_drb_setup_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) { - f1ap_drb_config_request drb_obj; + f1ap_drb_setup_request drb_obj; fill_common_drb_config_request_fields(drb_obj, drb_item); drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); @@ -81,9 +76,9 @@ f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap return drb_obj; } -f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) +f1ap_drb_setup_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) { - f1ap_drb_config_request drb_obj; + f1ap_drb_setup_request drb_obj; fill_common_drb_config_request_fields(drb_obj, drb_item); drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); @@ -96,106 +91,3 @@ f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap return drb_obj; } - -f1ap_drb_config_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item) -{ - f1ap_drb_config_request drb_obj; - fill_common_drb_config_request_fields(drb_obj, drb_item); - - if (drb_item.ie_exts_present) { - if (drb_item.ie_exts.dl_pdcp_sn_len_present) { - drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); - } - } - - return drb_obj; -} - -// helper function to fill asn1 DRBs-SetupMod and DRBs-Modified types. -template -static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_setupmod& drb) -{ - asn1obj.drb_id = drb_id_to_uint(drb.drb_id); - asn1obj.lcid_present = drb.lcid.has_value(); - if (asn1obj.lcid_present) { - asn1obj.lcid = drb.lcid.value(); - } - asn1obj.dl_up_tnl_info_to_be_setup_list.resize(drb.dluptnl_info_list.size()); - for (unsigned j = 0; j != drb.dluptnl_info_list.size(); ++j) { - up_transport_layer_info_to_asn1(asn1obj.dl_up_tnl_info_to_be_setup_list[j].dl_up_tnl_info, - drb.dluptnl_info_list[j]); - } -} - -template -void fill_drb_failed_item(ASN1Type& asn1obj, const f1ap_drb_failed_to_setupmod& drb_obj) -{ - asn1obj.drb_id = drb_id_to_uint(drb_obj.drb_id); - asn1obj.cause_present = drb_obj.cause.has_value(); - if (asn1obj.cause_present) { - asn1obj.cause = srs_cu_cp::cause_to_asn1(drb_obj.cause.value()); - } -} - -asn1::f1ap::drbs_setup_list_l srsran::srs_du::make_drbs_setup_list(span drbs) -{ - asn1::f1ap::drbs_setup_list_l list(drbs.size()); - for (unsigned i = 0; i != drbs.size(); ++i) { - list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_ITEM); - fill_drb_setup_mod_common(list[i]->drbs_setup_item(), drbs[i]); - } - return list; -} - -asn1::f1ap::drbs_setup_mod_list_l srsran::srs_du::make_drbs_setup_mod_list(span drbs) -{ - asn1::f1ap::drbs_setup_mod_list_l list(drbs.size()); - for (unsigned i = 0; i != drbs.size(); ++i) { - list[i].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); - fill_drb_setup_mod_common(list[i]->drbs_setup_mod_item(), drbs[i]); - } - return list; -} - -asn1::f1ap::drbs_modified_list_l srsran::srs_du::make_drbs_modified_list(span drbs) -{ - asn1::f1ap::drbs_modified_list_l list(drbs.size()); - for (unsigned i = 0; i != drbs.size(); ++i) { - list[i].load_info_obj(ASN1_F1AP_ID_DRBS_MODIFIED_ITEM); - fill_drb_setup_mod_common(list[i]->drbs_modified_item(), drbs[i]); - } - return list; -} - -asn1::f1ap::drbs_failed_to_be_setup_list_l -srsran::srs_du::make_drbs_failed_to_be_setup_list(span failed_drbs) -{ - asn1::f1ap::drbs_failed_to_be_setup_list_l list(failed_drbs.size()); - for (unsigned i = 0; i != failed_drbs.size(); ++i) { - list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_ITEM); - fill_drb_failed_item(list[i]->drbs_failed_to_be_setup_item(), failed_drbs[i]); - } - return list; -} - -asn1::f1ap::drbs_failed_to_be_setup_mod_list_l -srsran::srs_du::make_drbs_failed_to_be_setup_mod_list(span failed_drbs) -{ - asn1::f1ap::drbs_failed_to_be_setup_mod_list_l list(failed_drbs.size()); - for (unsigned i = 0; i != failed_drbs.size(); ++i) { - list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_SETUP_MOD_ITEM); - fill_drb_failed_item(list[i]->drbs_failed_to_be_setup_mod_item(), failed_drbs[i]); - } - return list; -} - -asn1::f1ap::drbs_failed_to_be_modified_list_l -srsran::srs_du::make_drbs_failed_to_be_modified_list(span failed_drbs) -{ - asn1::f1ap::drbs_failed_to_be_modified_list_l list(failed_drbs.size()); - for (unsigned i = 0; i != failed_drbs.size(); ++i) { - list[i].load_info_obj(ASN1_F1AP_ID_DRBS_FAILED_TO_BE_MODIFIED_ITEM); - fill_drb_failed_item(list[i]->drbs_failed_to_be_modified_item(), failed_drbs[i]); - } - return list; -} diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h index 9bd8966a5a..a3399bdba6 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h @@ -33,38 +33,10 @@ srb_id_t make_srb_id(const Asn1Type& srb_item) } /// Convert 3GPP TS 38.473, DRBs-ToBeSetup-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); +f1ap_drb_setup_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); /// Convert 3GPP TS 38.473, DRBs-ToBeSetupMod-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); - -/// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_config_request make_drb_config_request(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); - -asn1::f1ap::drbs_setup_list_l make_drbs_setup_list(span drbs); -asn1::f1ap::drbs_setup_mod_list_l make_drbs_setup_mod_list(span drbs); -asn1::f1ap::drbs_modified_list_l make_drbs_modified_list(span drbs); - -/// Convert F1AP failed to setup/modify types to respective ASN.1 TS 48.473 types. -asn1::f1ap::drbs_failed_to_be_setup_list_l -make_drbs_failed_to_be_setup_list(span failed_drbs); -asn1::f1ap::drbs_failed_to_be_setup_mod_list_l -make_drbs_failed_to_be_setup_mod_list(span failed_drbs); -asn1::f1ap::drbs_failed_to_be_modified_list_l -make_drbs_failed_to_be_modified_list(span failed_drbs); - -/// \brief Creates a \c drb_id_t from ASN.1 type. -/// -/// This function is used by the following procedures: -/// - f1ap_du_ue_context_modification_procedure -/// -/// \param drb_item ASN.1 item with DRB-specific parameters to be removed. -/// \return drb_id_t object. -template -drb_id_t make_drb_id(const Asn1Type& drb_item) -{ - return static_cast(drb_item.drb_id); -} +f1ap_drb_setup_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); } // namespace srs_du } // namespace srsran diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index 62fca88da6..18fc2b677c 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -79,12 +79,12 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 // >> Pass DRBs to modify. // Note: This field is used during RRC Reestablishment. for (const auto& drb : msg->drbs_to_be_modified_list) { - du_request.drbs_to_mod.push_back(make_drb_config_request(drb.value().drbs_to_be_modified_item())); + du_request.drbs_to_mod.push_back(make_drb_to_modify(drb.value().drbs_to_be_modified_item())); } // >> Pass DRBs to remove for (const auto& drb : msg->drbs_to_be_released_list) { - du_request.drbs_to_rem.push_back(make_drb_id(drb.value().drbs_to_be_released_item())); + du_request.drbs_to_rem.push_back(get_drb_id(drb.value().drbs_to_be_released_item())); } } diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index fe47eea456..24c5b457cf 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -467,9 +467,9 @@ struct dummy_f1ap_ue_context_manager : public f1ap_ue_context_manager { res.success = ue_context_modification_outcome.outcome; for (const auto& drb_id : ue_context_modification_outcome.drb_success_list) { // add only the most relevant items - f1ap_drbs_setup_mod_item drb_item; + f1ap_drb_setupmod drb_item; drb_item.drb_id = uint_to_drb_id(drb_id); // set ID - res.drbs_setup_mod_list.emplace(drb_item.drb_id, drb_item); + res.drbs_setup_list.emplace(drb_item.drb_id, drb_item); } res.du_to_cu_rrc_info.cell_group_cfg = make_byte_buffer("5800b24223c853a0120c7c080408c008").value(); // TODO: add failed list and other fields here .. diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 85b745f52c..307a464aeb 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -82,7 +82,7 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_config_request& drb : req.drbs_to_setup) { + for (const f1ap_drb_setup_request& drb : req.drbs_to_setup) { cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 127eba11ee..1cec2950ac 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -42,7 +42,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test this->cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_config_request& drb : req.drbs_to_setup) { + for (const f1ap_drb_setup_request& drb : req.drbs_to_setup) { this->cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; @@ -99,7 +99,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test ASSERT_FALSE(srb_it->reestablish_rlc_present); } } - for (const f1ap_drb_config_request& drb : req.drbs_to_setup) { + for (const f1ap_drb_setup_request& drb : req.drbs_to_setup) { auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), [&drb](const auto& b) { diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 83a3755a0b..61d596b105 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -302,47 +302,12 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi msg.drbs_to_be_setup_mod_list.emplace(uint_to_drb_id(1), drbs_to_be_setup_mod_item); // drbs to be modified list - f1ap_drbs_to_be_modified_item drbs_to_be_modified_item; - + f1ap_drb_to_modify drbs_to_be_modified_item; drbs_to_be_modified_item.drb_id = uint_to_drb_id(1); - // qos info - f1ap_drb_info qos_info; - // drb qos - // qos flow level qos params - // qos characteristics - qos_info.drb_qos.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - - // ng ran alloc retention prio - qos_info.drb_qos.alloc_and_retention_prio.prio_level_arp = 1; - qos_info.drb_qos.alloc_and_retention_prio.pre_emption_cap = "shall-not-trigger-pre-emption"; - qos_info.drb_qos.alloc_and_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; - - // gbr qos flow info - qos_info.drb_qos.gbr_qos_info = gbr_qos_info; - - // reflective qos attribute - qos_info.drb_qos.reflective_qos_attribute = true; - - // s nssai - qos_info.s_nssai.sst = 1; - qos_info.s_nssai.sd = 128; - - // notif ctrl - qos_info.notif_ctrl = f1ap_notif_ctrl::active; - - // flows mapped to drb list - qos_info.flows_mapped_to_drb_list.emplace(uint_to_qos_flow_id(1), flows_mapped_to_drb_item); - - // qos info - drbs_to_be_modified_item.qos_info = qos_info; - // ul up tnl info to be setup list drbs_to_be_modified_item.uluptnl_info_list.push_back(ul_up_tnl_info_item); - // ul cfg - drbs_to_be_modified_item.ul_cfg = ul_cfg; - msg.drbs_to_be_modified_list.emplace(uint_to_drb_id(1), drbs_to_be_modified_item); // srbs to be released list diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp index ee450d70f2..c508de7d4b 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp @@ -61,7 +61,7 @@ TEST_F(f1ap_cu_ue_context_modification_test, when_f1ap_receives_response_then_pr // The UE CONTEXT MODIFICATION procedure finished successfully. EXPECT_TRUE(t.ready()); EXPECT_TRUE(t.get().success); - EXPECT_EQ(t.get().drbs_setup_mod_list.size(), 1); + EXPECT_EQ(t.get().drbs_setup_list.size(), 1); EXPECT_EQ(t.get().srbs_setup_mod_list.size(), 0); } @@ -87,10 +87,10 @@ TEST_F(f1ap_cu_ue_context_modification_test, // The UE CONTEXT MODIFICATION procedure finished unsuccessfully. EXPECT_TRUE(t.ready()); EXPECT_TRUE(t.get().success); - EXPECT_EQ(t.get().drbs_setup_mod_list.size(), 0); + EXPECT_EQ(t.get().drbs_setup_list.size(), 0); EXPECT_EQ(t.get().srbs_setup_mod_list.size(), 0); - EXPECT_EQ(t.get().drbs_failed_to_be_setup_mod_list.size(), 1); - EXPECT_EQ(t.get().drbs_failed_to_be_setup_mod_list[drb_id_t::drb1].drb_id, drb_id_t::drb1); + EXPECT_EQ(t.get().drbs_failed_to_be_setup_list.size(), 1); + EXPECT_EQ(t.get().drbs_failed_to_be_setup_list[drb_id_t::drb1].drb_id, drb_id_t::drb1); } TEST_F(f1ap_cu_ue_context_modification_test, when_ue_modification_failure_received_then_procedure_is_unsuccessful) @@ -107,6 +107,6 @@ TEST_F(f1ap_cu_ue_context_modification_test, when_ue_modification_failure_receiv // The UE CONTEXT MODIFICATION procedure finished unsuccessfully. EXPECT_TRUE(t.ready()); EXPECT_FALSE(t.get().success); - EXPECT_EQ(t.get().drbs_setup_mod_list.size(), 0); + EXPECT_EQ(t.get().drbs_setup_list.size(), 0); EXPECT_EQ(t.get().srbs_setup_mod_list.size(), 0); } diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp index ca5a046cc5..c8258d5385 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp @@ -76,7 +76,6 @@ TEST_F(f1ap_du_ue_context_modification_test, when_f1ap_receives_request_then_f1a ASSERT_EQ(req.srbs_to_setup.size(), 0); ASSERT_EQ(req.drbs_to_setup.size(), 1); ASSERT_EQ(req.drbs_to_setup[0].drb_id, drb_id_t::drb1); - ASSERT_FALSE(req.drbs_to_setup[0].lcid.has_value()); } TEST_F(f1ap_du_ue_context_modification_test, diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index ca918fa045..6128b83693 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -111,7 +111,6 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notif ASSERT_EQ(req.srbs_to_setup[0], srb_id_t::srb2); ASSERT_EQ(req.drbs_to_setup.size(), 1); ASSERT_EQ(req.drbs_to_setup[0].drb_id, drb_id_t::drb1); - ASSERT_FALSE(req.drbs_to_setup[0].lcid.has_value()); ASSERT_EQ(req.drbs_to_setup[0].mode, rlc_mode::am); ASSERT_EQ(req.drbs_to_setup[0].pdcp_sn_len, pdcp_sn_size::size12bits); } From 2da47f65dde52a5f2284831c4d517c9b05395780 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 2 Aug 2024 19:54:55 +0200 Subject: [PATCH 101/407] f1ap: remove slotted_id_vectors from f1ap cu interface --- .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 48 +++++++++---------- .../routines/mobility/mobility_helpers.cpp | 8 ++-- .../routines/pdu_session_routine_helpers.cpp | 10 ++-- .../routines/pdu_session_routine_helpers.h | 10 ++-- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 29 +++-------- .../procedures/ue_context_setup_procedure.cpp | 19 +++----- tests/unittests/cu_cp/test_helpers.h | 2 +- ...ue_context_modification_procedure_test.cpp | 2 +- 8 files changed, 54 insertions(+), 74 deletions(-) diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index deb84380ef..5fec34e54a 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -171,16 +171,16 @@ struct f1ap_ue_context_setup_response { ue_index_t ue_index = ue_index_t::invalid; // UE Context Setup Response - f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; - std::optional c_rnti; - std::optional res_coordination_transfer_container; - std::optional full_cfg; - slotted_id_vector drbs_setup_list; - slotted_id_vector srbs_failed_to_be_setup_list; - slotted_id_vector drbs_failed_to_be_setup_list; - std::vector scell_failed_to_setup_list; - std::optional inactivity_monitoring_resp; - slotted_id_vector srbs_setup_list; // max size = 8 + f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; + std::optional c_rnti; + std::optional res_coordination_transfer_container; + std::optional full_cfg; + std::vector drbs_setup_list; + std::vector srbs_failed_to_be_setup_list; + std::vector drbs_failed_to_be_setup_list; + std::vector scell_failed_to_setup_list; + std::optional inactivity_monitoring_resp; + std::vector srbs_setup_list; // UE Context Setup Failure std::optional cause; @@ -244,20 +244,20 @@ struct f1ap_associated_scell_item { struct f1ap_ue_context_modification_response { bool success = false; // ue context modification response - byte_buffer res_coordination_transfer_container; - f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; - slotted_id_vector drbs_setup_list; - slotted_id_vector drbs_modified_list; - slotted_id_vector srbs_failed_to_be_setup_list; - slotted_id_vector drbs_failed_to_be_setup_list; - std::vector scell_failed_to_be_setup_list; - slotted_id_vector drbs_failed_to_be_modified_list; - std::optional inactivity_monitoring_resp; - std::optional c_rnti; - std::vector associated_scell_list; - slotted_id_vector srbs_setup_mod_list; - slotted_id_vector srbs_modified_list; - std::optional full_cfg; + byte_buffer res_coordination_transfer_container; + f1ap_du_to_cu_rrc_info du_to_cu_rrc_info; + std::vector drbs_setup_list; + std::vector drbs_modified_list; + std::vector srbs_failed_to_be_setup_list; + std::vector drbs_failed_to_be_setup_list; + std::vector scell_failed_to_be_setup_list; + std::vector drbs_failed_to_be_modified_list; + std::optional inactivity_monitoring_resp; + std::optional c_rnti; + std::vector associated_scell_list; + std::vector srbs_setup_mod_list; + std::vector srbs_modified_list; + std::optional full_cfg; // UE Context Modification Failure std::optional cause; diff --git a/lib/cu_cp/routines/mobility/mobility_helpers.cpp b/lib/cu_cp/routines/mobility/mobility_helpers.cpp index 69657cdcf4..81e88099c1 100644 --- a/lib/cu_cp/routines/mobility/mobility_helpers.cpp +++ b/lib/cu_cp/routines/mobility/mobility_helpers.cpp @@ -56,11 +56,13 @@ bool srsran::srs_cu_cp::handle_context_setup_response( e1ap_mod_item.pdu_session_id = pdu_session.first; for (const auto& drb_item : pdu_session.second.drb_to_add) { - srsran_assert(target_ue_context_setup_response.drbs_setup_list.contains(drb_item.first), + auto drb_it = std::find_if(target_ue_context_setup_response.drbs_setup_list.begin(), + target_ue_context_setup_response.drbs_setup_list.end(), + [&drb_item](const auto& drb) { return drb.drb_id == drb_item.first; }); + srsran_assert(drb_it != target_ue_context_setup_response.drbs_setup_list.end(), "Couldn't find {} in UE context setup response", drb_item.first); - - const auto& context_setup_drb_item = target_ue_context_setup_response.drbs_setup_list[drb_item.first]; + const auto& context_setup_drb_item = *drb_it; e1ap_drb_to_modify_item_ng_ran e1ap_drb_item; e1ap_drb_item.drb_id = drb_item.first; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index e44b6028ad..538ffad169 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -606,7 +606,7 @@ bool srsran::srs_cu_cp::update_modify_list( void srsran::srs_cu_cp::fill_e1ap_bearer_context_list( slotted_id_vector& e1ap_list, - const slotted_id_vector& drb_setup_items, + const std::vector& drb_setup_items, const std::map& pdu_sessions_update_list) { /// Iterate over all PDU sessions to be updated and match the containing DRBs. @@ -718,10 +718,10 @@ bool srsran::srs_cu_cp::update_modify_list( return ue_context_modification_response.success; } -bool srsran::srs_cu_cp::update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const slotted_id_vector& drb_setup_mod_list, - const up_config_update& next_config, - const srslog::basic_logger& logger) +bool srsran::srs_cu_cp::update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const std::vector& drb_setup_mod_list, + const up_config_update& next_config, + const srslog::basic_logger& logger) { // Start with empty message. e1ap_ng_ran_bearer_context_mod_request& e1ap_bearer_context_mod = diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index c590bf387a..10acef12ef 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -30,7 +30,7 @@ void fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_item& e1ap_qos_i const qos_flow_setup_request_item& request_item); void fill_e1ap_bearer_context_list( slotted_id_vector& e1ap_list, - const slotted_id_vector& drb_setup_items, + const std::vector& drb_setup_items, const std::map& pdu_sessions_update_list); void fill_e1ap_pdu_session_res_to_setup_list( slotted_id_vector& pdu_session_res_to_setup_list, @@ -94,10 +94,10 @@ bool update_setup_list(slotted_id_vector& drb_setup_mod_list, - const up_config_update& next_config, - const srslog::basic_logger& logger); +bool update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const std::vector& drb_setup_mod_list, + const up_config_update& next_config, + const srslog::basic_logger& logger); void update_failed_list( slotted_id_vector& ngap_failed_list, diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index 5bee3fa783..9d86fcb970 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -317,9 +317,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_response->drbs_setup_mod_list_present) { for (auto asn1_drb_setup_mod_list_item : asn1_response->drbs_setup_mod_list) { auto& asn1_drb_mod_item = asn1_drb_setup_mod_list_item.value().drbs_setup_mod_item(); - - f1ap_drb_setupmod mod_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); - res.drbs_setup_list.emplace(mod_item.drb_id, mod_item); + res.drbs_setup_list.push_back(asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item)); } } @@ -327,10 +325,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_response->drbs_modified_list_present) { for (auto asn1_drbs_modified_list_item : asn1_response->drbs_modified_list) { auto& asn1_drb_mod_item = asn1_drbs_modified_list_item.value().drbs_modified_item(); - - f1ap_drb_setupmod mod_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); - - res.drbs_modified_list.emplace(mod_item.drb_id, mod_item); + res.drbs_modified_list.push_back(asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item)); } } @@ -338,9 +333,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_response->srbs_failed_to_be_setup_mod_list_present) { for (auto asn1_srbs_failed_setup_mod_list_item : asn1_response->srbs_failed_to_be_setup_mod_list) { auto& asn1_srb_failed_item = asn1_srbs_failed_setup_mod_list_item.value().srbs_failed_to_be_setup_mod_item(); - - f1ap_srb_failed_to_setup srb_item = asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item); - res.srbs_failed_to_be_setup_list.emplace(srb_item.srb_id, srb_item); + res.srbs_failed_to_be_setup_list.push_back(asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item)); } } @@ -348,9 +341,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_response->drbs_failed_to_be_setup_mod_list_present) { for (auto asn1_drbs_failed_setup_mod_list_item : asn1_response->drbs_failed_to_be_setup_mod_list) { auto& asn1_drb_failed_item = asn1_drbs_failed_setup_mod_list_item.value().drbs_failed_to_be_setup_mod_item(); - - f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - res.drbs_failed_to_be_setup_list.emplace(drb_item.drb_id, drb_item); + res.drbs_failed_to_be_setup_list.push_back(asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item)); } } @@ -374,7 +365,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat auto& asn1_drb_failed_item = asn1_drbs_failed_modified_list_item.value().drbs_failed_to_be_modified_item(); f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - res.drbs_failed_to_be_modified_list.emplace(drb_item.drb_id, drb_item); + res.drbs_failed_to_be_modified_list.push_back(drb_item); } } @@ -404,10 +395,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_response->srbs_setup_mod_list_present) { for (auto asn1_srbs_setup_mod_list_item : asn1_response->srbs_setup_mod_list) { auto& asn1_srbs_setup_mod_item = asn1_srbs_setup_mod_list_item.value().srbs_setup_mod_item(); - - f1ap_srbs_setup_mod_item srbs_setup_mod_item = asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_setup_mod_item); - - res.srbs_setup_mod_list.emplace(srbs_setup_mod_item.srb_id, srbs_setup_mod_item); + res.srbs_setup_mod_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_setup_mod_item)); } } @@ -415,10 +403,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat if (asn1_response->srbs_modified_list_present) { for (auto asn1_srbs_modified_list_item : asn1_response->srbs_modified_list) { auto& asn1_srbs_modified_item = asn1_srbs_modified_list_item.value().srbs_modified_item(); - - f1ap_srbs_setup_mod_item srbs_modified_item = asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_modified_item); - - res.srbs_modified_list.emplace(srbs_modified_item.srb_id, srbs_modified_item); + res.srbs_modified_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_modified_item)); } } diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index 632d4b2f52..a52a5adf4b 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -436,9 +436,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->drbs_setup_list_present) { for (auto asn1_drbs_setup_list_item : asn1_response->drbs_setup_list) { auto& asn1_drb_mod_item = asn1_drbs_setup_list_item.value().drbs_setup_item(); - - f1ap_drb_setupmod drb_item = asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item); - response.drbs_setup_list.emplace(drb_item.drb_id, drb_item); + response.drbs_setup_list.push_back(asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item)); } } @@ -446,9 +444,8 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->srbs_failed_to_be_setup_list_present) { for (auto asn1_srbs_failed_setup_list_item : asn1_response->srbs_failed_to_be_setup_list) { auto& asn1_srb_failed_item = asn1_srbs_failed_setup_list_item.value().srbs_failed_to_be_setup_item(); - - f1ap_srb_failed_to_setup srb_item = asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item); - response.srbs_failed_to_be_setup_list.emplace(srb_item.srb_id, srb_item); + response.srbs_failed_to_be_setup_list.push_back( + asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item)); } } @@ -456,9 +453,8 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->drbs_failed_to_be_setup_list_present) { for (auto asn1_drbs_failed_setup_list_item : asn1_response->drbs_failed_to_be_setup_list) { auto& asn1_drb_failed_item = asn1_drbs_failed_setup_list_item.value().drbs_failed_to_be_setup_item(); - - f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - response.drbs_failed_to_be_setup_list.emplace(drb_item.drb_id, drb_item); + response.drbs_failed_to_be_setup_list.push_back( + asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item)); } } @@ -491,10 +487,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->srbs_setup_list_present) { for (auto asn1_srbs_setup_list_item : asn1_response->srbs_setup_list) { auto& asn1_srbs_setup_item = asn1_srbs_setup_list_item.value().srbs_setup_item(); - - f1ap_srbs_setup_mod_item srbs_setup_item = asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_setup_item); - - response.srbs_setup_list.emplace(srbs_setup_item.srb_id, srbs_setup_item); + response.srbs_setup_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_setup_item)); } } } diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index 24c5b457cf..887bcbcf34 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -469,7 +469,7 @@ struct dummy_f1ap_ue_context_manager : public f1ap_ue_context_manager { // add only the most relevant items f1ap_drb_setupmod drb_item; drb_item.drb_id = uint_to_drb_id(drb_id); // set ID - res.drbs_setup_list.emplace(drb_item.drb_id, drb_item); + res.drbs_setup_list.push_back(drb_item); } res.du_to_cu_rrc_info.cell_group_cfg = make_byte_buffer("5800b24223c853a0120c7c080408c008").value(); // TODO: add failed list and other fields here .. diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp index c508de7d4b..457ec2aaac 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_modification_procedure_test.cpp @@ -90,7 +90,7 @@ TEST_F(f1ap_cu_ue_context_modification_test, EXPECT_EQ(t.get().drbs_setup_list.size(), 0); EXPECT_EQ(t.get().srbs_setup_mod_list.size(), 0); EXPECT_EQ(t.get().drbs_failed_to_be_setup_list.size(), 1); - EXPECT_EQ(t.get().drbs_failed_to_be_setup_list[drb_id_t::drb1].drb_id, drb_id_t::drb1); + EXPECT_EQ(t.get().drbs_failed_to_be_setup_list[0].drb_id, drb_id_t::drb1); } TEST_F(f1ap_cu_ue_context_modification_test, when_ue_modification_failure_received_then_procedure_is_unsuccessful) From 9f622a2c81bf4d6b06e660227dd348e9cb2b6205 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 5 Aug 2024 09:39:01 +0200 Subject: [PATCH 102/407] f1ap: remove slotted_id_vectors from f1ap cu interface - part2 --- .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 104 +++++++++--------- .../mobility/inter_du_handover_routine.cpp | 4 +- .../routines/pdu_session_routine_helpers.cpp | 42 +++---- .../routines/pdu_session_routine_helpers.h | 33 +++--- ...blishment_context_modification_routine.cpp | 13 +-- .../f1ap/common/f1ap_cu_test_messages.cpp | 6 +- .../f1ap/cu_cp/f1ap_cu_test_helpers.cpp | 2 +- 7 files changed, 101 insertions(+), 103 deletions(-) diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index 5fec34e54a..220c8c0d51 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -121,28 +121,28 @@ struct f1ap_res_coordination_transfer_info { /// \brief Request from CU to F1AP-CU to start an F1AP "UE Context Setup" procedure, as per TS38.473 8.3.1. struct f1ap_ue_context_setup_request { - ue_index_t ue_index = ue_index_t::invalid; - nr_cell_global_id_t sp_cell_id; - uint8_t serv_cell_idx; - std::optional sp_cell_ul_cfg; - f1ap_cu_to_du_rrc_info cu_to_du_rrc_info; - std::vector candidate_sp_cell_list; // max size = 64 - std::optional drx_cycle; - byte_buffer res_coordination_transfer_container; - std::vector scell_to_be_setup_list; // max size = 32 - slotted_id_vector srbs_to_be_setup_list; // max size = 8 - slotted_id_vector drbs_to_be_setup_list; // max size = 64 - std::optional inactivity_monitoring_request; - std::optional rat_freq_prio_info; - byte_buffer rrc_container; - std::optional masked_imeisv; - std::optional serving_plmn; - std::optional gnb_du_ue_ambr_ul; - std::optional rrc_delivery_status_request; - std::optional res_coordination_transfer_info; - std::optional serving_cell_mo; - std::optional new_gnb_cu_ue_f1ap_id; - std::optional ran_ue_id; + ue_index_t ue_index = ue_index_t::invalid; + nr_cell_global_id_t sp_cell_id; + uint8_t serv_cell_idx; + std::optional sp_cell_ul_cfg; + f1ap_cu_to_du_rrc_info cu_to_du_rrc_info; + std::vector candidate_sp_cell_list; // max size = 64 + std::optional drx_cycle; + byte_buffer res_coordination_transfer_container; + std::vector scell_to_be_setup_list; // max size = 32 + std::vector srbs_to_be_setup_list; // max size = 8 + std::vector drbs_to_be_setup_list; // max size = 64 + std::optional inactivity_monitoring_request; + std::optional rat_freq_prio_info; + byte_buffer rrc_container; + std::optional masked_imeisv; + std::optional serving_plmn; + std::optional gnb_du_ue_ambr_ul; + std::optional rrc_delivery_status_request; + std::optional res_coordination_transfer_info; + std::optional serving_cell_mo; + std::optional new_gnb_cu_ue_f1ap_id; + std::optional ran_ue_id; }; struct f1ap_du_to_cu_rrc_info { @@ -204,36 +204,36 @@ struct f1ap_rlc_fail_ind { /// \brief Request from CU to F1AP-CU to start an F1AP "UE Context Modification" procedure, as per TS38.473 8.3.4. struct f1ap_ue_context_modification_request { - ue_index_t ue_index = ue_index_t::invalid; - std::optional sp_cell_id; - std::optional serv_cell_idx; - std::optional sp_cell_ul_cfg; - std::optional drx_cycle; - std::optional cu_to_du_rrc_info; - std::optional tx_action_ind; - byte_buffer res_coordination_transfer_container; - std::optional rrc_recfg_complete_ind; - byte_buffer rrc_container; - std::vector scell_to_be_setup_mod_list; - std::vector scell_to_be_remd_list; - slotted_id_vector srbs_to_be_setup_mod_list; - slotted_id_vector drbs_to_be_setup_mod_list; - slotted_id_vector drbs_to_be_modified_list; - std::vector srbs_to_be_released_list; - std::vector drbs_to_be_released_list; - std::optional inactivity_monitoring_request; - std::optional rat_freq_prio_info; - std::optional drx_cfg_ind; - std::optional rlc_fail_ind; - byte_buffer ul_tx_direct_current_list_info; - std::optional gnb_du_cfg_query; - std::optional gnb_du_ue_ambr_ul; - std::optional execute_dupl; - std::optional rrc_delivery_status_request; - std::optional res_coordination_transfer_info; - std::optional serving_cell_mo; - std::optional need_for_gap; - std::optional full_cfg; + ue_index_t ue_index = ue_index_t::invalid; + std::optional sp_cell_id; + std::optional serv_cell_idx; + std::optional sp_cell_ul_cfg; + std::optional drx_cycle; + std::optional cu_to_du_rrc_info; + std::optional tx_action_ind; + byte_buffer res_coordination_transfer_container; + std::optional rrc_recfg_complete_ind; + byte_buffer rrc_container; + std::vector scell_to_be_setup_mod_list; + std::vector scell_to_be_remd_list; + std::vector srbs_to_be_setup_mod_list; + std::vector drbs_to_be_setup_mod_list; + std::vector drbs_to_be_modified_list; + std::vector srbs_to_be_released_list; + std::vector drbs_to_be_released_list; + std::optional inactivity_monitoring_request; + std::optional rat_freq_prio_info; + std::optional drx_cfg_ind; + std::optional rlc_fail_ind; + byte_buffer ul_tx_direct_current_list_info; + std::optional gnb_du_cfg_query; + std::optional gnb_du_ue_ambr_ul; + std::optional execute_dupl; + std::optional rrc_delivery_status_request; + std::optional res_coordination_transfer_info; + std::optional serving_cell_mo; + std::optional need_for_gap; + std::optional full_cfg; }; struct f1ap_associated_scell_item { diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index 483bd4c698..b6c3f7ec17 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -262,7 +262,7 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex for (const auto& srb_id : srbs) { f1ap_srbs_to_be_setup_mod_item srb_item; srb_item.srb_id = srb_id; - setup_request.srbs_to_be_setup_list.emplace(srb_item.srb_id, srb_item); + setup_request.srbs_to_be_setup_list.push_back(srb_item); } for (const auto& pdu_session : next_config.pdu_sessions_to_setup_list) { @@ -284,7 +284,7 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex drb_item.mode = drb_context.rlc_mod; drb_item.pdcp_sn_len = drb_context.pdcp_cfg.tx.sn_size; - setup_request.drbs_to_be_setup_list.emplace(drb_item.drb_id, drb_item); + setup_request.drbs_to_be_setup_list.push_back(drb_item); } } diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index 538ffad169..07ede64e36 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -73,18 +73,18 @@ bool srsran::srs_cu_cp::verify_and_log_cell_group_config(const byte_buffer& } bool srsran::srs_cu_cp::fill_rrc_reconfig_args( - rrc_reconfiguration_procedure_request& rrc_reconfig_args, - const slotted_id_vector& srbs_to_be_setup_mod_list, - const std::map& pdu_sessions, - const std::vector& drb_to_remove, - const f1ap_du_to_cu_rrc_info& du_to_cu_rrc_info, - const std::vector& nas_pdus, - const std::optional rrc_meas_cfg, - bool reestablish_srbs, - bool reestablish_drbs, - bool update_keys, - byte_buffer sib1, - const srslog::basic_logger& logger) + rrc_reconfiguration_procedure_request& rrc_reconfig_args, + const std::vector& srbs_to_be_setup_mod_list, + const std::map& pdu_sessions, + const std::vector& drb_to_remove, + const f1ap_du_to_cu_rrc_info& du_to_cu_rrc_info, + const std::vector& nas_pdus, + const std::optional rrc_meas_cfg, + bool reestablish_srbs, + bool reestablish_drbs, + bool update_keys, + byte_buffer sib1, + const srslog::basic_logger& logger) { rrc_radio_bearer_config radio_bearer_config; // if default DRB is being setup, SRB2 needs to be setup as well @@ -260,8 +260,8 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ bool srsran::srs_cu_cp::update_setup_list( slotted_id_vector& ngap_response_list, - slotted_id_vector& srb_setup_mod_list, - slotted_id_vector& drb_setup_mod_list, + std::vector& srb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, @@ -274,7 +274,7 @@ bool srsran::srs_cu_cp::update_setup_list( if (up_resource_mng.get_nof_drbs() == 0) { f1ap_srbs_to_be_setup_mod_item srb2; srb2.srb_id = srb_id_t::srb2; - srb_setup_mod_list.emplace(srb2.srb_id, srb2); + srb_setup_mod_list.push_back(srb2); } for (const auto& e1ap_item : pdu_session_resource_setup_list) { @@ -375,7 +375,7 @@ bool srsran::srs_cu_cp::update_setup_list( logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); return false; } - drb_setup_mod_list.emplace(e1ap_drb_item.drb_id, drb_setup_mod_item); + drb_setup_mod_list.push_back(drb_setup_mod_item); } // Fail on any DRB that fails to be setup @@ -391,8 +391,8 @@ bool srsran::srs_cu_cp::update_setup_list( } bool srsran::srs_cu_cp::update_setup_list( - slotted_id_vector& srb_setup_mod_list, - slotted_id_vector& drb_setup_mod_list, + std::vector& srb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, @@ -405,7 +405,7 @@ bool srsran::srs_cu_cp::update_setup_list( for (unsigned srb_id = 1; srb_id < 3; ++srb_id) { f1ap_srbs_to_be_setup_mod_item srb_item; srb_item.srb_id = int_to_srb_id(srb_id); - srb_setup_mod_list.emplace(srb_item.srb_id, srb_item); + srb_setup_mod_list.push_back(srb_item); } for (const auto& e1ap_item : pdu_session_resource_setup_list) { @@ -444,7 +444,7 @@ bool srsran::srs_cu_cp::update_setup_list( logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); return false; } - drb_setup_mod_list.emplace(e1ap_drb_item.drb_id, drb_setup_mod_item); + drb_setup_mod_list.push_back(drb_setup_mod_item); } // Fail on any DRB that fails to be setup @@ -586,7 +586,7 @@ bool srsran::srs_cu_cp::update_modify_list( } // Finally add DRB to setup to UE context modification. - ue_context_mod_request.drbs_to_be_setup_mod_list.emplace(e1ap_drb_item.drb_id, drb_setup_mod_item); + ue_context_mod_request.drbs_to_be_setup_mod_list.push_back(drb_setup_mod_item); } // Add DRB to be removed to UE context modifcation. diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index 10acef12ef..e3c35d5212 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -59,24 +59,23 @@ void fill_drb_to_remove_list(std::vector& e1ap_drb_to_remove_lis /// \param[in] sib1 Packed SIB1 content for direct delivery to UE (optional). /// \param[in] logger Logger reference. /// \return True on success, false otherwise. -bool fill_rrc_reconfig_args( - rrc_reconfiguration_procedure_request& rrc_reconfig_args, - const slotted_id_vector& srbs_to_be_setup_mod_list, - const std::map& pdu_sessions, - const std::vector& drb_to_remove, - const f1ap_du_to_cu_rrc_info& du_to_cu_rrc_info, - const std::vector& nas_pdus, - const std::optional rrc_meas_cfg, - bool reestablish_srbs, - bool reestablish_drbs, - bool update_keys, - byte_buffer sib1, - const srslog::basic_logger& logger); +bool fill_rrc_reconfig_args(rrc_reconfiguration_procedure_request& rrc_reconfig_args, + const std::vector& srbs_to_be_setup_mod_list, + const std::map& pdu_sessions, + const std::vector& drb_to_remove, + const f1ap_du_to_cu_rrc_info& du_to_cu_rrc_info, + const std::vector& nas_pdus, + const std::optional rrc_meas_cfg, + bool reestablish_srbs, + bool reestablish_drbs, + bool update_keys, + byte_buffer sib1, + const srslog::basic_logger& logger); bool update_setup_list( slotted_id_vector& ngap_response_list, - slotted_id_vector& srb_setup_mod_list, - slotted_id_vector& drb_setup_mod_list, + std::vector& srb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, @@ -85,8 +84,8 @@ bool update_setup_list( const security_indication_t& default_security_indication, const srslog::basic_logger& logger); -bool update_setup_list(slotted_id_vector& srb_setup_mod_list, - slotted_id_vector& drb_setup_mod_list, +bool update_setup_list(std::vector& srb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index ee73baec29..07ab555aba 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -103,11 +103,10 @@ void reestablishment_context_modification_routine::operator()(coro_context srbs_to_setup_list; - f1ap_srbs_to_be_setup_mod_item srb_to_setup = {}; - - srb_to_setup.srb_id = srb_id_t::srb2; - srbs_to_setup_list.insert(srb_id_t::srb2, srb_to_setup); + std::vector srbs_to_setup_list; + f1ap_srbs_to_be_setup_mod_item srb_to_setup = {}; + srb_to_setup.srb_id = srb_id_t::srb2; + srbs_to_setup_list.push_back(srb_to_setup); // convert pdu session context std::map pdu_sessions_to_setup_list; @@ -186,7 +185,7 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat // Set up SRB2 in DU f1ap_srbs_to_be_setup_mod_item srb2; srb2.srb_id = srb_id_t::srb2; - ue_context_mod_req.srbs_to_be_setup_mod_list.emplace(srb2.srb_id, srb2); + ue_context_mod_req.srbs_to_be_setup_mod_list.push_back(srb2); for (const auto& e1ap_item : e1ap_pdu_session_resource_modify_list) { cu_cp_pdu_session_resource_modify_response_item item; @@ -242,7 +241,7 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat mapped_flow_item.qos_flow_level_qos_params = drb_up_context.qos_params; drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.emplace(mapped_flow_item.qos_flow_id, mapped_flow_item); } - ue_context_mod_req.drbs_to_be_setup_mod_list.emplace(e1ap_drb_item.drb_id, drb_setup_mod_item); + ue_context_mod_req.drbs_to_be_setup_mod_list.push_back(drb_setup_mod_item); } } diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 61d596b105..7489898f29 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -222,7 +222,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi f1ap_srbs_to_be_setup_mod_item srbs_to_be_setup_mod_item; srbs_to_be_setup_mod_item.srb_id = int_to_srb_id(1); srbs_to_be_setup_mod_item.dupl_ind = f1ap_dupl_ind::true_value; - msg.srbs_to_be_setup_mod_list.emplace(int_to_srb_id(1), srbs_to_be_setup_mod_item); + msg.srbs_to_be_setup_mod_list.push_back(srbs_to_be_setup_mod_item); // drbs to be setup mod list f1ap_drbs_to_be_setup_mod_item drbs_to_be_setup_mod_item; @@ -299,7 +299,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // dupl activation drbs_to_be_setup_mod_item.dupl_activation = f1ap_dupl_activation::active; - msg.drbs_to_be_setup_mod_list.emplace(uint_to_drb_id(1), drbs_to_be_setup_mod_item); + msg.drbs_to_be_setup_mod_list.push_back(drbs_to_be_setup_mod_item); // drbs to be modified list f1ap_drb_to_modify drbs_to_be_modified_item; @@ -308,7 +308,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // ul up tnl info to be setup list drbs_to_be_modified_item.uluptnl_info_list.push_back(ul_up_tnl_info_item); - msg.drbs_to_be_modified_list.emplace(uint_to_drb_id(1), drbs_to_be_modified_item); + msg.drbs_to_be_modified_list.push_back(drbs_to_be_modified_item); // srbs to be released list msg.srbs_to_be_released_list.push_back(int_to_srb_id(1)); diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp index 98cba32261..b14dbf145b 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp @@ -155,7 +155,7 @@ srsran::srs_cu_cp::create_ue_context_setup_request(const std::initializer_list Date: Mon, 5 Aug 2024 10:12:32 +0200 Subject: [PATCH 103/407] f1ap: remove unused parameters from the drb setup --- .../srsran/f1ap/common/ue_context_config.h | 5 ++ .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 46 +++------- .../f1ap/du/f1ap_du_ue_context_update.h | 2 +- .../mobility/inter_du_handover_routine.cpp | 4 +- .../routines/pdu_session_routine_helpers.cpp | 14 +-- .../routines/pdu_session_routine_helpers.h | 6 +- ...blishment_context_modification_routine.cpp | 12 +-- lib/f1ap/common/asn1_helpers.cpp | 11 +++ lib/f1ap/common/asn1_helpers.h | 1 + lib/f1ap/cu_cp/f1ap_asn1_converters.h | 89 ++----------------- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 9 +- .../procedures/ue_context_setup_procedure.cpp | 2 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 17 +--- 13 files changed, 63 insertions(+), 155 deletions(-) diff --git a/include/srsran/f1ap/common/ue_context_config.h b/include/srsran/f1ap/common/ue_context_config.h index e89846bc32..f107adb5ff 100644 --- a/include/srsran/f1ap/common/ue_context_config.h +++ b/include/srsran/f1ap/common/ue_context_config.h @@ -18,6 +18,11 @@ namespace srsran { +/// Parameters of a SRB to setup in the DU UE context. +struct f1ap_srb_to_setup { + srb_id_t srb_id = srb_id_t::nulltype; +}; + /// Parameters of a failed SRB setup in the DU UE context. struct f1ap_srb_failed_to_setup { srb_id_t srb_id = srb_id_t::nulltype; diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index 220c8c0d51..560b5d43f1 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -67,20 +67,8 @@ struct f1ap_scell_to_be_setup_mod_item { std::optional scell_ul_cfg; }; -enum class f1ap_dupl_ind { true_value = 0, false_value }; - -struct f1ap_srbs_to_be_setup_mod_item { - srb_id_t srb_id = srb_id_t::nulltype; - std::optional dupl_ind; -}; - -struct f1ap_eutran_qos { - uint16_t qci; - cu_cp_alloc_and_retention_prio alloc_and_retention_prio; - std::optional gbr_qos_info; -}; - -enum class f1ap_notif_ctrl { active = 0, not_active }; +/// \brief Used to activate notification control for a given DRB. +enum class drb_notification_control { active = 0, not_active }; struct f1ap_flows_mapped_to_drb_item { qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; @@ -88,24 +76,19 @@ struct f1ap_flows_mapped_to_drb_item { }; struct f1ap_drb_info { - cu_cp_qos_flow_level_qos_params drb_qos; - s_nssai_t s_nssai; - std::optional notif_ctrl; - slotted_id_vector flows_mapped_to_drb_list; + cu_cp_qos_flow_level_qos_params drb_qos; + s_nssai_t s_nssai; + /// \brief Sets whether notification control is active. + /// [TS 38.473 8.3.1.2] If the Notification Control IE is included in the DRB to Be Setup List IE and it is set to + /// active, the gNB-DU shall, if supported, monitor the QoS of the DRB and notify the gNB-CU if the QoS cannot be + /// fulfilled any longer or if the QoS can be fulfilled again. The Notification Control IE can only be applied to GBR + /// bearers. + std::optional notif_ctrl; + std::vector flows_mapped_to_drb_list; }; -enum class f1ap_ul_ue_cfg { no_data = 0, shared, only }; - -struct f1ap_ul_cfg { - f1ap_ul_ue_cfg ul_ue_cfg; -}; - -enum class f1ap_dupl_activation { active = 0, inactive }; - struct f1ap_drbs_to_be_setup_mod_item : public f1ap_drb_to_setup { - f1ap_drb_info qos_info; - std::optional ul_cfg; - std::optional dupl_activation; + f1ap_drb_info qos_info; }; struct f1ap_rat_freq_prio_info { @@ -116,7 +99,6 @@ struct f1ap_rat_freq_prio_info { struct f1ap_res_coordination_transfer_info { nr_cell_identity m_enb_cell_id; - // ResourceCoordinationEUTRACellInfo (optional) }; /// \brief Request from CU to F1AP-CU to start an F1AP "UE Context Setup" procedure, as per TS38.473 8.3.1. @@ -130,7 +112,7 @@ struct f1ap_ue_context_setup_request { std::optional drx_cycle; byte_buffer res_coordination_transfer_container; std::vector scell_to_be_setup_list; // max size = 32 - std::vector srbs_to_be_setup_list; // max size = 8 + std::vector srbs_to_be_setup_list; // max size = 8 std::vector drbs_to_be_setup_list; // max size = 64 std::optional inactivity_monitoring_request; std::optional rat_freq_prio_info; @@ -216,7 +198,7 @@ struct f1ap_ue_context_modification_request { byte_buffer rrc_container; std::vector scell_to_be_setup_mod_list; std::vector scell_to_be_remd_list; - std::vector srbs_to_be_setup_mod_list; + std::vector srbs_to_be_setup_mod_list; std::vector drbs_to_be_setup_mod_list; std::vector drbs_to_be_modified_list; std::vector srbs_to_be_released_list; diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 7a27fc00fd..837d12c696 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -37,7 +37,7 @@ struct f1ap_ue_context_creation_response { rnti_t crnti; }; -/// \brief DRB to be setup or modify in the UE context. +/// \brief DRB to be setup or modified in the UE context. struct f1ap_drb_setup_request : public f1ap_drb_to_setup { five_qi_t five_qi; uint8_t arp_priority_level; diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index b6c3f7ec17..eb1ec15f5b 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -260,7 +260,7 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex setup_request.cu_to_du_rrc_info.ue_cap_rat_container_list = transfer_context.ue_cap_rat_container_list.copy(); for (const auto& srb_id : srbs) { - f1ap_srbs_to_be_setup_mod_item srb_item; + f1ap_srb_to_setup srb_item; srb_item.srb_id = srb_id; setup_request.srbs_to_be_setup_list.push_back(srb_item); } @@ -278,7 +278,7 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex f1ap_flows_mapped_to_drb_item flow_item; flow_item.qos_flow_id = flow.first; flow_item.qos_flow_level_qos_params = flow.second.qos_params; - drb_item.qos_info.flows_mapped_to_drb_list.emplace(flow_item.qos_flow_id, flow_item); + drb_item.qos_info.flows_mapped_to_drb_list.push_back(flow_item); } drb_item.uluptnl_info_list = drb_context.ul_up_tnl_info_to_be_setup_list; drb_item.mode = drb_context.rlc_mod; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index 07ede64e36..d56cc462a5 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -74,7 +74,7 @@ bool srsran::srs_cu_cp::verify_and_log_cell_group_config(const byte_buffer& bool srsran::srs_cu_cp::fill_rrc_reconfig_args( rrc_reconfiguration_procedure_request& rrc_reconfig_args, - const std::vector& srbs_to_be_setup_mod_list, + const std::vector& srbs_to_be_setup_mod_list, const std::map& pdu_sessions, const std::vector& drb_to_remove, const f1ap_du_to_cu_rrc_info& du_to_cu_rrc_info, @@ -89,7 +89,7 @@ bool srsran::srs_cu_cp::fill_rrc_reconfig_args( rrc_radio_bearer_config radio_bearer_config; // if default DRB is being setup, SRB2 needs to be setup as well if (!srbs_to_be_setup_mod_list.empty()) { - for (const f1ap_srbs_to_be_setup_mod_item& srb_to_add_mod : srbs_to_be_setup_mod_list) { + for (const f1ap_srb_to_setup& srb_to_add_mod : srbs_to_be_setup_mod_list) { rrc_srb_to_add_mod srb = {}; srb.srb_id = srb_to_add_mod.srb_id; if (reestablish_srbs) { @@ -248,7 +248,7 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ flow_mapped_to_drb.qos_flow_id = e1ap_flow.qos_flow_id; flow_mapped_to_drb.qos_flow_level_qos_params = ngap_qos_flow.qos_flow_level_qos_params; - drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.emplace(flow_mapped_to_drb.qos_flow_id, flow_mapped_to_drb); + drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(flow_mapped_to_drb); // Store flow QoS params in UP config. auto& next_config_flow_cfg = next_drb_config.qos_flows.at(e1ap_flow.qos_flow_id); @@ -260,7 +260,7 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ bool srsran::srs_cu_cp::update_setup_list( slotted_id_vector& ngap_response_list, - std::vector& srb_setup_mod_list, + std::vector& srb_setup_mod_list, std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& @@ -272,7 +272,7 @@ bool srsran::srs_cu_cp::update_setup_list( { // Set up SRB2 if this is the first DRB to be setup if (up_resource_mng.get_nof_drbs() == 0) { - f1ap_srbs_to_be_setup_mod_item srb2; + f1ap_srb_to_setup srb2; srb2.srb_id = srb_id_t::srb2; srb_setup_mod_list.push_back(srb2); } @@ -391,7 +391,7 @@ bool srsran::srs_cu_cp::update_setup_list( } bool srsran::srs_cu_cp::update_setup_list( - std::vector& srb_setup_mod_list, + std::vector& srb_setup_mod_list, std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& @@ -403,7 +403,7 @@ bool srsran::srs_cu_cp::update_setup_list( // Set up SRB1 and SRB2 (this is for inter CU handover, so no SRBs are setup yet) // TODO: Do we need to setup SRB0 here as well? for (unsigned srb_id = 1; srb_id < 3; ++srb_id) { - f1ap_srbs_to_be_setup_mod_item srb_item; + f1ap_srb_to_setup srb_item; srb_item.srb_id = int_to_srb_id(srb_id); srb_setup_mod_list.push_back(srb_item); } diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index e3c35d5212..ac48889204 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -60,7 +60,7 @@ void fill_drb_to_remove_list(std::vector& e1ap_drb_to_remove_lis /// \param[in] logger Logger reference. /// \return True on success, false otherwise. bool fill_rrc_reconfig_args(rrc_reconfiguration_procedure_request& rrc_reconfig_args, - const std::vector& srbs_to_be_setup_mod_list, + const std::vector& srbs_to_be_setup_mod_list, const std::map& pdu_sessions, const std::vector& drb_to_remove, const f1ap_du_to_cu_rrc_info& du_to_cu_rrc_info, @@ -74,7 +74,7 @@ bool fill_rrc_reconfig_args(rrc_reconfiguration_procedure_request& bool update_setup_list( slotted_id_vector& ngap_response_list, - std::vector& srb_setup_mod_list, + std::vector& srb_setup_mod_list, std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& @@ -84,7 +84,7 @@ bool update_setup_list( const security_indication_t& default_security_indication, const srslog::basic_logger& logger); -bool update_setup_list(std::vector& srb_setup_mod_list, +bool update_setup_list(std::vector& srb_setup_mod_list, std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 07ab555aba..66ca2ac659 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -103,9 +103,9 @@ void reestablishment_context_modification_routine::operator()(coro_context srbs_to_setup_list; - f1ap_srbs_to_be_setup_mod_item srb_to_setup = {}; - srb_to_setup.srb_id = srb_id_t::srb2; + std::vector srbs_to_setup_list; + f1ap_srb_to_setup srb_to_setup = {}; + srb_to_setup.srb_id = srb_id_t::srb2; srbs_to_setup_list.push_back(srb_to_setup); // convert pdu session context @@ -183,7 +183,7 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat e1ap_pdu_session_resource_modify_list) { // Set up SRB2 in DU - f1ap_srbs_to_be_setup_mod_item srb2; + f1ap_srb_to_setup srb2; srb2.srb_id = srb_id_t::srb2; ue_context_mod_req.srbs_to_be_setup_mod_list.push_back(srb2); @@ -232,14 +232,14 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat // fill QoS info drb_setup_mod_item.qos_info.drb_qos = drb_up_context.qos_params; drb_setup_mod_item.qos_info.s_nssai = drb_up_context.s_nssai; - drb_setup_mod_item.qos_info.notif_ctrl = f1ap_notif_ctrl::active; + drb_setup_mod_item.qos_info.notif_ctrl = drb_notification_control::active; // Fill QoS flows for UE context modification. for (const auto& flow : drb_up_context.qos_flows) { // Add mapped flows and extract required QoS info from original NGAP request f1ap_flows_mapped_to_drb_item mapped_flow_item; mapped_flow_item.qos_flow_id = flow.first; mapped_flow_item.qos_flow_level_qos_params = drb_up_context.qos_params; - drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.emplace(mapped_flow_item.qos_flow_id, mapped_flow_item); + drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(mapped_flow_item); } ue_context_mod_req.drbs_to_be_setup_mod_list.push_back(drb_setup_mod_item); } diff --git a/lib/f1ap/common/asn1_helpers.cpp b/lib/f1ap/common/asn1_helpers.cpp index ffdddd3ca0..1ba358b48e 100644 --- a/lib/f1ap/common/asn1_helpers.cpp +++ b/lib/f1ap/common/asn1_helpers.cpp @@ -78,6 +78,17 @@ srsran::make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_li return uluptnl_info_list; } +asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l +srsran::make_asn1_ul_up_tnl_info_list(span list) +{ + asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l ret; + ret.resize(list.size()); + for (unsigned i = 0; i != list.size(); ++i) { + up_transport_layer_info_to_asn1(ret[i].ul_up_tnl_info, list[i]); + } + return ret; +} + f1ap_drb_to_modify srsran::make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item) { f1ap_drb_to_modify drb_obj; diff --git a/lib/f1ap/common/asn1_helpers.h b/lib/f1ap/common/asn1_helpers.h index 392d73249c..36de37fc88 100644 --- a/lib/f1ap/common/asn1_helpers.h +++ b/lib/f1ap/common/asn1_helpers.h @@ -36,6 +36,7 @@ asn1::f1ap::pdcp_sn_len_e pdcp_sn_size_to_f1ap_asn1(pdcp_sn_size sn_size); std::vector make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l& asn1_list); +asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l make_asn1_ul_up_tnl_info_list(span list); /// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_to_modify. f1ap_drb_to_modify make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index d42148782d..fe8f30f318 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -182,15 +182,15 @@ qos_characteristics_to_f1ap_asn1(const qos_characteristics_t& qos_characteristic /// \brief Convert \c f1ap_notif_ctrl to F1AP ASN.1. /// \param[in] notif_ctrl The common type notif ctrl. /// \return The ASN.1 notif ctrl. -inline asn1::f1ap::notif_ctrl_e f1ap_notif_ctrl_to_asn1(const f1ap_notif_ctrl& notif_ctrl) +inline asn1::f1ap::notif_ctrl_e f1ap_notif_ctrl_to_asn1(const drb_notification_control& notif_ctrl) { asn1::f1ap::notif_ctrl_e asn1_notif_ctrl; switch (notif_ctrl) { - case f1ap_notif_ctrl::active: + case drb_notification_control::active: asn1_notif_ctrl = asn1::f1ap::notif_ctrl_opts::options::active; break; - case f1ap_notif_ctrl::not_active: + case drb_notification_control::not_active: asn1_notif_ctrl = asn1::f1ap::notif_ctrl_opts::options::not_active; break; } @@ -375,80 +375,15 @@ inline void f1ap_scell_to_be_setup_mod_item_to_asn1(template_asn1_item& asn1_sce } } -/// \brief Convert \c f1ap_dupl_ind to F1AP ASN.1. -/// \param[in] dupl_ind The common type dupl ind. -/// \return The ASN.1 dupl ind. -inline asn1::f1ap::dupl_ind_e f1ap_dupl_ind_to_asn1(const f1ap_dupl_ind& dupl_ind) -{ - asn1::f1ap::dupl_ind_e asn1_dupl_ind; - - switch (dupl_ind) { - case f1ap_dupl_ind::true_value: - asn1_dupl_ind = asn1::f1ap::dupl_ind_opts::options::true_value; - break; - case f1ap_dupl_ind::false_value: - asn1_dupl_ind = asn1::f1ap::dupl_ind_opts::options::false_value; - break; - } - - return asn1_dupl_ind; -} - /// \brief Convert srbs to be setup/setup mod item to F1AP ASN.1. /// \param[out] asn1_srbs_to_be_setup_mod_item The ASN.1 struct to store the result. /// \param[in] srbs_to_be_setup_mod_item The srbs to be setup/setup item mod common type struct. template -inline void f1ap_srbs_to_be_setup_mod_item_to_asn1(template_asn1_item& asn1_srbs_to_be_setup_mod_item, - const f1ap_srbs_to_be_setup_mod_item& srbs_to_be_setup_mod_item) +inline void f1ap_srb_to_setup_to_asn1(template_asn1_item& asn1_srbs_to_be_setup_mod_item, + const f1ap_srb_to_setup& srbs_to_be_setup_mod_item) { // srb id asn1_srbs_to_be_setup_mod_item.srb_id = srb_id_to_uint(srbs_to_be_setup_mod_item.srb_id); - - // dupl ind - if (srbs_to_be_setup_mod_item.dupl_ind.has_value()) { - asn1_srbs_to_be_setup_mod_item.dupl_ind = f1ap_dupl_ind_to_asn1(srbs_to_be_setup_mod_item.dupl_ind.value()); - } -} - -/// \brief Convert \c f1ap_ul_ue_cfg to F1AP ASN.1. -/// \param[in] ul_ue_cfg The common type ul ue cfg. -/// \return The ASN.1 ul ue cfg. -inline asn1::f1ap::ul_ue_cfg_e f1ap_ul_ue_cfg_to_asn1(const f1ap_ul_ue_cfg& ul_ue_cfg) -{ - asn1::f1ap::ul_ue_cfg_e asn1_ul_ue_cfg; - - switch (ul_ue_cfg) { - case f1ap_ul_ue_cfg::no_data: - asn1_ul_ue_cfg = asn1::f1ap::ul_ue_cfg_opts::options::no_data; - break; - case f1ap_ul_ue_cfg::shared: - asn1_ul_ue_cfg = asn1::f1ap::ul_ue_cfg_opts::options::shared; - break; - case f1ap_ul_ue_cfg::only: - asn1_ul_ue_cfg = asn1::f1ap::ul_ue_cfg_opts::options::only; - break; - } - - return asn1_ul_ue_cfg; -} - -/// \brief Convert \c f1ap_dupl_activation to F1AP ASN.1. -/// \param[in] dupl_activation The common type dupl activation. -/// \return The ASN.1 dupl activation. -inline asn1::f1ap::dupl_activation_e f1ap_dupl_activation_to_asn1(const f1ap_dupl_activation& dupl_activation) -{ - asn1::f1ap::dupl_activation_e asn1_dupl_activation; - - switch (dupl_activation) { - case f1ap_dupl_activation::active: - asn1_dupl_activation = asn1::f1ap::dupl_activation_e::dupl_activation_opts::options::active; - break; - case f1ap_dupl_activation::inactive: - asn1_dupl_activation = asn1::f1ap::dupl_activation_e::dupl_activation_opts::options::inactive; - break; - } - - return asn1_dupl_activation; } /// \brief Convert extension fields of drb to be setup item to F1AP ASN.1. @@ -502,20 +437,6 @@ inline void f1ap_drbs_to_be_setup_mod_item_to_asn1(template_asn1_item& // pdcp sn size f1ap_drbs_to_be_setup_mod_item_ext_ies_to_asn1(asn1_drb_to_be_setup_mod_item.ie_exts, drb_to_be_setup_mod_item); asn1_drb_to_be_setup_mod_item.ie_exts_present = true; - - // ul cfg - if (drb_to_be_setup_mod_item.ul_cfg.has_value()) { - asn1_drb_to_be_setup_mod_item.ul_cfg_present = true; - asn1_drb_to_be_setup_mod_item.ul_cfg.ul_ue_cfg = - f1ap_ul_ue_cfg_to_asn1(drb_to_be_setup_mod_item.ul_cfg.value().ul_ue_cfg); - } - - // dupl activation - if (drb_to_be_setup_mod_item.dupl_activation.has_value()) { - asn1_drb_to_be_setup_mod_item.dupl_activation_present = true; - asn1_drb_to_be_setup_mod_item.dupl_activation = - f1ap_dupl_activation_to_asn1(drb_to_be_setup_mod_item.dupl_activation.value()); - } } /// \brief Convert \c f1ap_tx_action_ind to F1AP ASN.1. diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index 9d86fcb970..160ee67c10 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -144,7 +144,7 @@ inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod auto& asn1_srbs_to_be_setup_mod_item = asn1_srbs_to_be_setup_mod_item_container.value().srbs_to_be_setup_mod_item(); - f1ap_srbs_to_be_setup_mod_item_to_asn1(asn1_srbs_to_be_setup_mod_item, srbs_to_be_setup_mod_item); + f1ap_srb_to_setup_to_asn1(asn1_srbs_to_be_setup_mod_item, srbs_to_be_setup_mod_item); asn1_request->srbs_to_be_setup_mod_list.push_back(asn1_srbs_to_be_setup_mod_item_container); } } @@ -177,11 +177,8 @@ inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod asn1_drb_to_be_modified_item.drb_id = drb_id_to_uint(drb_to_be_modified_item.drb_id); // ul up tnl info to be setup list - for (const auto& ul_up_tnl_info_item : drb_to_be_modified_item.uluptnl_info_list) { - asn1::f1ap::ul_up_tnl_info_to_be_setup_item_s item; - up_transport_layer_info_to_asn1(item.ul_up_tnl_info, ul_up_tnl_info_item); - asn1_drb_to_be_modified_item.ul_up_tnl_info_to_be_setup_list.push_back(item); - } + asn1_drb_to_be_modified_item.ul_up_tnl_info_to_be_setup_list = + make_asn1_ul_up_tnl_info_list(drb_to_be_modified_item.uluptnl_info_list); asn1_request->drbs_to_be_modified_list.push_back(asn1_drb_to_be_modified_item_container); } diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index a52a5adf4b..58a960af60 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -292,7 +292,7 @@ static void fill_asn1_ue_context_setup_request(asn1::f1ap::ue_context_setup_requ asn1_srbs_to_be_setup_item_container.set_item(ASN1_F1AP_ID_SRBS_TO_BE_SETUP_ITEM); auto& asn1_srbs_to_be_setup_item = asn1_srbs_to_be_setup_item_container.value().srbs_to_be_setup_item(); - f1ap_srbs_to_be_setup_mod_item_to_asn1(asn1_srbs_to_be_setup_item, srbs_to_be_setup_item); + f1ap_srb_to_setup_to_asn1(asn1_srbs_to_be_setup_item, srbs_to_be_setup_item); asn1_request->srbs_to_be_setup_list.push_back(asn1_srbs_to_be_setup_item_container); } diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 7489898f29..43cdb97f10 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -219,9 +219,8 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi msg.scell_to_be_remd_list.push_back(scell_to_be_remd_item); // srbs to be setup mod list - f1ap_srbs_to_be_setup_mod_item srbs_to_be_setup_mod_item; - srbs_to_be_setup_mod_item.srb_id = int_to_srb_id(1); - srbs_to_be_setup_mod_item.dupl_ind = f1ap_dupl_ind::true_value; + f1ap_srb_to_setup srbs_to_be_setup_mod_item; + srbs_to_be_setup_mod_item.srb_id = int_to_srb_id(1); msg.srbs_to_be_setup_mod_list.push_back(srbs_to_be_setup_mod_item); // drbs to be setup mod list @@ -262,7 +261,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_setup_mod_item.qos_info.s_nssai.sd = 128; // notif ctrl - drbs_to_be_setup_mod_item.qos_info.notif_ctrl = f1ap_notif_ctrl::active; + drbs_to_be_setup_mod_item.qos_info.notif_ctrl = drb_notification_control::active; // flows mapped to drb list f1ap_flows_mapped_to_drb_item flows_mapped_to_drb_item; @@ -280,7 +279,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // reflective qos attribute flows_mapped_to_drb_item.qos_flow_level_qos_params.reflective_qos_attribute = true; - drbs_to_be_setup_mod_item.qos_info.flows_mapped_to_drb_list.emplace(uint_to_qos_flow_id(1), flows_mapped_to_drb_item); + drbs_to_be_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(flows_mapped_to_drb_item); // ul up tnl info to be setup list up_transport_layer_info ul_up_tnl_info_item = {transport_layer_address::create_from_string("127.0.0.1"), @@ -291,14 +290,6 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_setup_mod_item.mode = rlc_mode::am; drbs_to_be_setup_mod_item.pdcp_sn_len = pdcp_sn_size::size12bits; - // ul cfg - f1ap_ul_cfg ul_cfg; - ul_cfg.ul_ue_cfg = f1ap_ul_ue_cfg::no_data; - drbs_to_be_setup_mod_item.ul_cfg = ul_cfg; - - // dupl activation - drbs_to_be_setup_mod_item.dupl_activation = f1ap_dupl_activation::active; - msg.drbs_to_be_setup_mod_list.push_back(drbs_to_be_setup_mod_item); // drbs to be modified list From 36210bd1c0ca8e8af9050467275859a8e6f17c32 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 5 Aug 2024 10:42:03 +0200 Subject: [PATCH 104/407] f1ap: use same drb qos representation for CU-CP and DU --- apps/units/cu_cp/cu_cp_unit_config.h | 2 +- apps/units/cu_up/cu_up_unit_config.h | 2 +- .../flexible_du/du_high/du_high_config.h | 2 +- .../du_high/du_high_config_translators.h | 2 +- include/srsran/cu_cp/cu_cp_types.h | 30 +---- include/srsran/cu_cp/up_context.h | 6 +- .../cu_up/cu_up_configuration_helpers.h | 2 +- include/srsran/du/du_cell_config_helpers.h | 2 +- include/srsran/e1ap/common/e1ap_types.h | 8 +- .../srsran/f1ap/common/ue_context_config.h | 25 +++++ .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 28 +---- .../f1ap/du/f1ap_du_ue_context_update.h | 15 +-- include/srsran/ran/cu_types.h | 90 +-------------- include/srsran/ran/{ => qos}/five_qi.h | 0 include/srsran/ran/qos/five_qi_qos_mapping.h | 2 +- include/srsran/ran/qos/qos_flow_id.h | 61 +++++++++++ include/srsran/ran/qos/qos_info.h | 33 ------ include/srsran/ran/qos/qos_parameters.h | 103 ++++++++++++++++++ include/srsran/ran/{ => qos}/qos_prio_level.h | 0 .../srsran/scheduler/scheduler_configurator.h | 4 +- .../mobility/inter_du_handover_routine.cpp | 4 +- .../routines/pdu_session_routine_helpers.cpp | 33 +++--- .../routines/pdu_session_routine_helpers.h | 4 +- ...blishment_context_modification_routine.cpp | 4 +- .../up_resource_manager_helpers.cpp | 8 +- lib/du_manager/du_ue/du_bearer.h | 32 +++--- .../procedures/ue_configuration_procedure.cpp | 38 +++---- .../du_ran_resource_manager_impl.cpp | 14 ++- .../du_ran_resource_manager_impl.h | 2 +- lib/e1ap/common/e1ap_asn1_converters.h | 25 +++-- lib/e1ap/common/e1ap_asn1_helpers.h | 2 +- lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h | 27 +++-- lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h | 4 +- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 61 +++++------ lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 4 +- .../procedures/ue_context_setup_procedure.cpp | 4 +- .../procedures/f1ap_du_ue_context_common.cpp | 35 +++--- .../du/procedures/f1ap_du_ue_context_common.h | 4 +- lib/ngap/ngap_asn1_helpers.h | 27 +++-- lib/ngap/ngap_validators/ngap_validators.cpp | 4 +- tests/unittests/cu_cp/cu_cp_test_messages.cpp | 12 +- .../cu_up/pdu_session_manager_test.h | 17 +-- .../du_manager/du_manager_test_helpers.cpp | 6 +- .../du_manager_procedure_test_helpers.cpp | 2 +- .../procedures/ue_configuration_test.cpp | 4 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 10 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 37 +++---- .../f1ap/cu_cp/f1ap_cu_test_helpers.cpp | 16 ++- 48 files changed, 434 insertions(+), 423 deletions(-) rename include/srsran/ran/{ => qos}/five_qi.h (100%) create mode 100644 include/srsran/ran/qos/qos_flow_id.h delete mode 100644 include/srsran/ran/qos/qos_info.h create mode 100644 include/srsran/ran/qos/qos_parameters.h rename include/srsran/ran/{ => qos}/qos_prio_level.h (100%) diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index 79b4e6e30d..333cbca084 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -12,10 +12,10 @@ #include "apps/units/cu_cp/cu_cp_unit_pcap_config.h" #include "cu_cp_unit_logger_config.h" -#include "srsran/ran/five_qi.h" #include "srsran/ran/nr_band.h" #include "srsran/ran/nr_cell_identity.h" #include "srsran/ran/pci.h" +#include "srsran/ran/qos/five_qi.h" #include "srsran/ran/s_nssai.h" #include diff --git a/apps/units/cu_up/cu_up_unit_config.h b/apps/units/cu_up/cu_up_unit_config.h index 9721e23c33..beeae79db8 100644 --- a/apps/units/cu_up/cu_up_unit_config.h +++ b/apps/units/cu_up/cu_up_unit_config.h @@ -12,7 +12,7 @@ #include "apps/units/cu_up/cu_up_unit_pcap_config.h" #include "cu_up_unit_logger_config.h" -#include "srsran/ran/five_qi.h" +#include "srsran/ran/qos/five_qi.h" namespace srsran { 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 37057a6339..b21460878e 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -15,7 +15,6 @@ #include "srsran/ran/band_helper.h" #include "srsran/ran/bs_channel_bandwidth.h" #include "srsran/ran/direct_current_offset.h" -#include "srsran/ran/five_qi.h" #include "srsran/ran/gnb_du_id.h" #include "srsran/ran/gnb_id.h" #include "srsran/ran/lcid.h" @@ -26,6 +25,7 @@ #include "srsran/ran/pdsch/pdsch_mcs.h" #include "srsran/ran/pucch/pucch_configuration.h" #include "srsran/ran/pusch/pusch_mcs.h" +#include "srsran/ran/qos/five_qi.h" #include "srsran/ran/rnti.h" #include "srsran/ran/s_nssai.h" #include "srsran/ran/sib/system_info_config.h" diff --git a/apps/units/flexible_du/du_high/du_high_config_translators.h b/apps/units/flexible_du/du_high/du_high_config_translators.h index b7670f871e..c9606f10e6 100644 --- a/apps/units/flexible_du/du_high/du_high_config_translators.h +++ b/apps/units/flexible_du/du_high/du_high_config_translators.h @@ -16,8 +16,8 @@ #include "srsran/du/du_srb_config.h" #include "srsran/e2/e2ap_configuration.h" #include "srsran/mac/mac_config.h" -#include "srsran/ran/five_qi.h" #include "srsran/ran/lcid.h" +#include "srsran/ran/qos/five_qi.h" #include diff --git a/include/srsran/cu_cp/cu_cp_types.h b/include/srsran/cu_cp/cu_cp_types.h index af7f69daf1..18b5d6bd40 100644 --- a/include/srsran/cu_cp/cu_cp_types.h +++ b/include/srsran/cu_cp/cu_cp_types.h @@ -284,34 +284,10 @@ struct cu_cp_du_served_cells_item { std::optional gnb_du_sys_info; // not optional for NG-RAN }; -struct cu_cp_alloc_and_retention_prio { - uint8_t prio_level_arp; - std::string pre_emption_cap; - std::string pre_emption_vulnerability; -}; - -struct cu_cp_gbr_qos_info { - uint64_t max_flow_bit_rate_dl; - uint64_t max_flow_bit_rate_ul; - uint64_t guaranteed_flow_bit_rate_dl; - uint64_t guaranteed_flow_bit_rate_ul; - std::optional notif_ctrl; - std::optional max_packet_loss_rate_dl; - std::optional max_packet_loss_rate_ul; -}; - -struct cu_cp_qos_flow_level_qos_params { - qos_characteristics_t qos_characteristics; - cu_cp_alloc_and_retention_prio alloc_and_retention_prio; - std::optional gbr_qos_info; - std::optional add_qos_flow_info; - std::optional reflective_qos_attribute; -}; - struct qos_flow_setup_request_item { - qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; - cu_cp_qos_flow_level_qos_params qos_flow_level_qos_params; - std::optional erab_id; + qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; + qos_flow_level_qos_parameters qos_flow_level_qos_params; + std::optional erab_id; }; struct cu_cp_pdu_session_res_setup_item { diff --git a/include/srsran/cu_cp/up_context.h b/include/srsran/cu_cp/up_context.h index 1eac7db0b7..7a31f5ff75 100644 --- a/include/srsran/cu_cp/up_context.h +++ b/include/srsran/cu_cp/up_context.h @@ -24,8 +24,8 @@ struct up_resource_manager_cfg { }; struct up_qos_flow_context { - qos_flow_id_t qfi = qos_flow_id_t::invalid; - cu_cp_qos_flow_level_qos_params qos_params; + qos_flow_id_t qfi = qos_flow_id_t::invalid; + qos_flow_level_qos_parameters qos_params; }; struct up_drb_context { @@ -34,7 +34,7 @@ struct up_drb_context { s_nssai_t s_nssai = {}; bool default_drb = false; srsran::rlc_mode rlc_mod; - cu_cp_qos_flow_level_qos_params qos_params; // DRB QoS params. + qos_flow_level_qos_parameters qos_params; // DRB QoS params. std::map qos_flows; // QoS flow IDs of all QoS flows mapped to this DRB. std::vector ul_up_tnl_info_to_be_setup_list; // Allocated by CU-UP. diff --git a/include/srsran/cu_up/cu_up_configuration_helpers.h b/include/srsran/cu_up/cu_up_configuration_helpers.h index 8cbb9abd81..811c079972 100644 --- a/include/srsran/cu_up/cu_up_configuration_helpers.h +++ b/include/srsran/cu_up/cu_up_configuration_helpers.h @@ -11,7 +11,7 @@ #pragma once #include "srsran/cu_up/cu_up_types.h" -#include "srsran/ran/five_qi.h" +#include "srsran/ran/qos/five_qi.h" #include namespace srsran { diff --git a/include/srsran/du/du_cell_config_helpers.h b/include/srsran/du/du_cell_config_helpers.h index d5fefb1bed..63a3b9fc90 100644 --- a/include/srsran/du/du_cell_config_helpers.h +++ b/include/srsran/du/du_cell_config_helpers.h @@ -14,8 +14,8 @@ #include "srsran/du/du_qos_config.h" #include "srsran/mac/config/mac_config_helpers.h" #include "srsran/ran/band_helper.h" -#include "srsran/ran/five_qi.h" #include "srsran/ran/pdcch/pdcch_type0_css_coreset_config.h" +#include "srsran/ran/qos/five_qi.h" #include "srsran/ran/tdd/tdd_ul_dl_config.h" #include "srsran/scheduler/config/cell_config_builder_params.h" #include "srsran/scheduler/config/scheduler_expert_config.h" diff --git a/include/srsran/e1ap/common/e1ap_types.h b/include/srsran/e1ap/common/e1ap_types.h index 1e1afc2687..759d9b1d56 100644 --- a/include/srsran/e1ap/common/e1ap_types.h +++ b/include/srsran/e1ap/common/e1ap_types.h @@ -64,12 +64,6 @@ struct e1ap_cell_group_info_item { std::optional rat_type; }; -struct e1ap_ng_ran_alloc_and_retention_prio { - uint8_t prio_level; - std::string pre_emption_cap; - std::string pre_emption_vulnerability; -}; - struct e1ap_gbr_qos_flow_info { uint64_t max_flow_bit_rate_dl; uint64_t max_flow_bit_rate_ul; @@ -81,7 +75,7 @@ struct e1ap_gbr_qos_flow_info { struct e1ap_qos_flow_level_qos_params { qos_characteristics_t qos_characteristics; - e1ap_ng_ran_alloc_and_retention_prio ng_ran_alloc_retention_prio; + alloc_and_retention_priority ng_ran_alloc_retention; std::optional gbr_qos_flow_info; std::optional reflective_qos_attribute; std::optional add_qos_info; diff --git a/include/srsran/f1ap/common/ue_context_config.h b/include/srsran/f1ap/common/ue_context_config.h index f107adb5ff..4d4af6b42a 100644 --- a/include/srsran/f1ap/common/ue_context_config.h +++ b/include/srsran/f1ap/common/ue_context_config.h @@ -13,6 +13,9 @@ #include "srsran/pdcp/pdcp_sn_size.h" #include "srsran/ran/cause/f1ap_cause.h" #include "srsran/ran/lcid.h" +#include "srsran/ran/qos/qos_flow_id.h" +#include "srsran/ran/qos/qos_parameters.h" +#include "srsran/ran/s_nssai.h" #include "srsran/ran/up_transport_layer_info.h" #include "srsran/rlc/rlc_mode.h" @@ -30,6 +33,26 @@ struct f1ap_srb_failed_to_setup { std::optional cause; }; +/// \brief Used to activate notification control for a given DRB. +enum class drb_notification_control { active = 0, not_active }; + +struct flow_mapped_to_drb { + qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; + qos_flow_level_qos_parameters qos_flow_level_qos_params; +}; + +struct f1ap_drb_info { + qos_flow_level_qos_parameters drb_qos; + s_nssai_t s_nssai; + /// \brief Sets whether notification control is active. + /// [TS 38.473 8.3.1.2] If the Notification Control IE is included in the DRB to Be Setup List IE and it is set to + /// active, the gNB-DU shall, if supported, monitor the QoS of the DRB and notify the gNB-CU if the QoS cannot be + /// fulfilled any longer or if the QoS can be fulfilled again. The Notification Control IE can only be applied to GBR + /// bearers. + std::optional notif_ctrl; + std::vector flows_mapped_to_drb_list; +}; + /// Parameters of a new DRB to be setup in the DU UE context. struct f1ap_drb_to_setup { /// DRB-Id of the new DRB. @@ -41,6 +64,8 @@ struct f1ap_drb_to_setup { /// \brief PDCP SN length of the DRB. /// \remark (Implementation-defined) We use the same length for DL and UL. pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; + /// QoS Information of the DRB. + f1ap_drb_info qos_info; }; /// New parameters to set for an existing DRB in the DU UE context. diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index 560b5d43f1..294233990a 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -67,30 +67,6 @@ struct f1ap_scell_to_be_setup_mod_item { std::optional scell_ul_cfg; }; -/// \brief Used to activate notification control for a given DRB. -enum class drb_notification_control { active = 0, not_active }; - -struct f1ap_flows_mapped_to_drb_item { - qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; - cu_cp_qos_flow_level_qos_params qos_flow_level_qos_params; -}; - -struct f1ap_drb_info { - cu_cp_qos_flow_level_qos_params drb_qos; - s_nssai_t s_nssai; - /// \brief Sets whether notification control is active. - /// [TS 38.473 8.3.1.2] If the Notification Control IE is included in the DRB to Be Setup List IE and it is set to - /// active, the gNB-DU shall, if supported, monitor the QoS of the DRB and notify the gNB-CU if the QoS cannot be - /// fulfilled any longer or if the QoS can be fulfilled again. The Notification Control IE can only be applied to GBR - /// bearers. - std::optional notif_ctrl; - std::vector flows_mapped_to_drb_list; -}; - -struct f1ap_drbs_to_be_setup_mod_item : public f1ap_drb_to_setup { - f1ap_drb_info qos_info; -}; - struct f1ap_rat_freq_prio_info { // choice std::optional endc; @@ -113,7 +89,7 @@ struct f1ap_ue_context_setup_request { byte_buffer res_coordination_transfer_container; std::vector scell_to_be_setup_list; // max size = 32 std::vector srbs_to_be_setup_list; // max size = 8 - std::vector drbs_to_be_setup_list; // max size = 64 + std::vector drbs_to_be_setup_list; // max size = 64 std::optional inactivity_monitoring_request; std::optional rat_freq_prio_info; byte_buffer rrc_container; @@ -199,7 +175,7 @@ struct f1ap_ue_context_modification_request { std::vector scell_to_be_setup_mod_list; std::vector scell_to_be_remd_list; std::vector srbs_to_be_setup_mod_list; - std::vector drbs_to_be_setup_mod_list; + std::vector drbs_to_be_setup_mod_list; std::vector drbs_to_be_modified_list; std::vector srbs_to_be_released_list; std::vector drbs_to_be_released_list; diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index 837d12c696..c6d817fecb 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -15,8 +15,8 @@ #include "srsran/f1ap/common/ue_context_config.h" #include "srsran/pdcp/pdcp_sn_size.h" #include "srsran/ran/du_types.h" -#include "srsran/ran/five_qi.h" -#include "srsran/ran/qos/qos_info.h" +#include "srsran/ran/qos/five_qi.h" +#include "srsran/ran/qos/qos_parameters.h" #include "srsran/ran/rnti.h" #include "srsran/ran/s_nssai.h" @@ -37,15 +37,6 @@ struct f1ap_ue_context_creation_response { rnti_t crnti; }; -/// \brief DRB to be setup or modified in the UE context. -struct f1ap_drb_setup_request : public f1ap_drb_to_setup { - five_qi_t five_qi; - uint8_t arp_priority_level; - s_nssai_t s_nssai; - /// GBR flow information is present only for GBR QoS flows. See TS 38.473, clause 9.3.1.45. - std::optional gbr_flow_info; -}; - /// \brief SCell to be setup in the UE context. struct f1ap_scell_to_setup { serv_cell_index_t serv_cell_index; @@ -57,7 +48,7 @@ struct f1ap_ue_context_update_request { du_ue_index_t ue_index; std::vector srbs_to_setup; /// List of new DRBs to setup. - std::vector drbs_to_setup; + std::vector drbs_to_setup; /// List of DRBs to modify. std::vector drbs_to_mod; /// List of DRBs to remove. diff --git a/include/srsran/ran/cu_types.h b/include/srsran/ran/cu_types.h index 33e8b4a213..ea68e8b69f 100644 --- a/include/srsran/ran/cu_types.h +++ b/include/srsran/ran/cu_types.h @@ -10,11 +10,13 @@ #pragma once -#include "five_qi.h" -#include "nr_cgi.h" -#include "qos_prio_level.h" -#include "s_nssai.h" #include "srsran/adt/optional.h" +#include "srsran/ran/nr_cgi.h" +#include "srsran/ran/qos/five_qi.h" +#include "srsran/ran/qos/qos_flow_id.h" +#include "srsran/ran/qos/qos_parameters.h" +#include "srsran/ran/qos/qos_prio_level.h" +#include "srsran/ran/s_nssai.h" #include "srsran/sdap/sdap_config.h" #include "fmt/format.h" @@ -39,25 +41,6 @@ constexpr inline pdu_session_id_t uint_to_pdu_session_id(uint16_t idx) return static_cast(idx); } -// See TS 38.463 Section 9.3.1.24: QoS Flow ID valid values: (0..63) -constexpr static uint8_t MAX_NOF_QOS_FLOWS = 64; - -/// \brief QoS Flow ID. -/// \remark See TS 38.463 Section 9.3.1.21: QoS Flow ID valid values: (0..63) -enum class qos_flow_id_t : uint8_t { min = 0, max = MAX_NOF_QOS_FLOWS - 1, invalid = MAX_NOF_QOS_FLOWS }; - -/// Convert QoS Flow ID type to integer. -constexpr inline uint8_t qos_flow_id_to_uint(qos_flow_id_t id) -{ - return static_cast(id); -} - -/// Convert integer to QoS Flow ID type. -constexpr inline qos_flow_id_t uint_to_qos_flow_id(uint8_t idx) -{ - return static_cast(idx); -} - /// \brief RAN_UE_ID (non ASN1 type of RAN_UE_NGAP_ID). /// \remark See TS 38.413 Section 9.3.3.2: RAN_UE_NGAP_ID valid values: (0..2^32-1) constexpr static uint64_t MAX_NOF_RAN_UES = ((uint64_t)1 << 32); @@ -83,47 +66,6 @@ struct nr_cgi_support_item_t { nr_cell_global_id_t nr_cgi; }; -struct packet_error_rate_t { - uint8_t per_scalar; - uint8_t per_exponent; -}; - -struct dyn_5qi_descriptor_t { - qos_prio_level_t qos_prio_level; - uint16_t packet_delay_budget; - packet_error_rate_t packet_error_rate; - std::optional five_qi; - std::optional delay_crit; - std::optional averaging_win; - std::optional max_data_burst_volume; -}; - -struct non_dyn_5qi_descriptor_t { - five_qi_t five_qi; - std::optional qos_prio_level; - std::optional averaging_win; - std::optional max_data_burst_volume; -}; - -struct qos_characteristics_t { - five_qi_t get_five_qi() const - { - if (non_dyn_5qi.has_value()) { - return non_dyn_5qi.value().five_qi; - } else if (dyn_5qi.has_value()) { - if (dyn_5qi.value().five_qi.has_value()) { - return dyn_5qi.value().five_qi.value(); - } - } else { - srsran_assertion_failure("Invalid QoS characteristics. Either dynamic or non-dynamic 5QI must be set"); - } - return five_qi_t::invalid; - } - - std::optional dyn_5qi; - std::optional non_dyn_5qi; -}; - struct ng_ran_qos_support_item_t { non_dyn_5qi_descriptor_t non_dyn_5qi_descriptor; }; @@ -229,26 +171,6 @@ struct formatter { } }; -template <> -struct formatter { - template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) - { - return ctx.begin(); - } - - template - auto format(const srsran::qos_flow_id_t& qfi, FormatContext& ctx) -> decltype(std::declval().out()) - { - switch (qfi) { - case srsran::qos_flow_id_t::invalid: - return format_to(ctx.out(), "invalid QFI"); - default: - return format_to(ctx.out(), "QFI={:#}", qos_flow_id_to_uint(qfi)); - } - } -}; - template <> struct formatter { template diff --git a/include/srsran/ran/five_qi.h b/include/srsran/ran/qos/five_qi.h similarity index 100% rename from include/srsran/ran/five_qi.h rename to include/srsran/ran/qos/five_qi.h diff --git a/include/srsran/ran/qos/five_qi_qos_mapping.h b/include/srsran/ran/qos/five_qi_qos_mapping.h index 1965672fa9..b10b050faf 100644 --- a/include/srsran/ran/qos/five_qi_qos_mapping.h +++ b/include/srsran/ran/qos/five_qi_qos_mapping.h @@ -10,8 +10,8 @@ #pragma once +#include "five_qi.h" #include "srsran/adt/optional.h" -#include "srsran/ran/five_qi.h" namespace srsran { diff --git a/include/srsran/ran/qos/qos_flow_id.h b/include/srsran/ran/qos/qos_flow_id.h new file mode 100644 index 0000000000..532d21110a --- /dev/null +++ b/include/srsran/ran/qos/qos_flow_id.h @@ -0,0 +1,61 @@ +/* + * + * 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 "fmt/format.h" +#include + +namespace srsran { + +// See TS 38.463 Section 9.3.1.24: QoS Flow ID valid values: (0..63) +constexpr static uint8_t MAX_NOF_QOS_FLOWS = 64; + +/// \brief QoS Flow ID. +/// \remark See TS 38.463 Section 9.3.1.21: QoS Flow ID valid values: (0..63) +enum class qos_flow_id_t : uint8_t { min = 0, max = MAX_NOF_QOS_FLOWS - 1, invalid = MAX_NOF_QOS_FLOWS }; + +/// Convert QoS Flow ID type to integer. +constexpr inline uint8_t qos_flow_id_to_uint(qos_flow_id_t id) +{ + return static_cast(id); +} + +/// Convert integer to QoS Flow ID type. +constexpr inline qos_flow_id_t uint_to_qos_flow_id(uint8_t idx) +{ + return static_cast(idx); +} + +} // namespace srsran + +namespace fmt { + +template <> +struct formatter { + template + auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template + auto format(const srsran::qos_flow_id_t& qfi, FormatContext& ctx) + { + switch (qfi) { + case srsran::qos_flow_id_t::invalid: + return format_to(ctx.out(), "invalid QFI"); + default: + return format_to(ctx.out(), "QFI={:#}", qos_flow_id_to_uint(qfi)); + } + } +}; + +} // namespace fmt \ No newline at end of file diff --git a/include/srsran/ran/qos/qos_info.h b/include/srsran/ran/qos/qos_info.h deleted file mode 100644 index 793eac1fc5..0000000000 --- a/include/srsran/ran/qos/qos_info.h +++ /dev/null @@ -1,33 +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 - -namespace srsran { - -/// \brief QoS parameters for a GBR QoS flow or GBR bearer for downlink and uplink. See TS 38.473, clause 9.3.1.46. -struct gbr_qos_info_t { - /// Maximum Bit Rate in DL. - uint64_t max_flow_dl_bitrate; - /// Maximum Bit Rate in UL. - uint64_t max_flow_ul_bitrate; - /// Guaranteed Bit Rate (provided there is data to deliver) in DL. - uint64_t guaranteed_flow_dl_bitrate; - /// Guaranteed Bit Rate (provided there is data to deliver) in UL. - uint64_t guaranteed_flow_ul_bitrate; - /// Indicates the maximum rate for lost packets that can be tolerated in the DL. Expressed in ratio of lost packets - /// per number of packets sent, expressed in tenth of percent.Values {0,...,1000}. - std::optional max_packet_loss_rate_dl; - /// Indicates the maximum rate for lost packets that can be tolerated in the UL. Expressed in ratio of lost packets - /// per number of packets sent, expressed in tenth of percent.Values {0,...,1000}. - std::optional max_packet_loss_rate_ul; -}; - -} // namespace srsran diff --git a/include/srsran/ran/qos/qos_parameters.h b/include/srsran/ran/qos/qos_parameters.h new file mode 100644 index 0000000000..0c5b25184b --- /dev/null +++ b/include/srsran/ran/qos/qos_parameters.h @@ -0,0 +1,103 @@ +/* + * + * 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/qos/five_qi.h" +#include "srsran/ran/qos/qos_prio_level.h" +#include +#include +#include + +namespace srsran { + +/// \brief Representation of the Packet Error Rate (PER) as defined in TS 38.473. +struct packet_error_rate_t { + uint8_t scalar = 0; + uint8_t exponent = 0; + + double to_double() const { return scalar * std::pow(10, exponent); } +}; + +struct dyn_5qi_descriptor_t { + qos_prio_level_t qos_prio_level; + uint16_t packet_delay_budget; + packet_error_rate_t per; + std::optional five_qi; + std::optional is_delay_critical; + /// This parameter should be present if the GBR QoS Flow information is set. + std::optional averaging_win; + /// This parameter should be present if the GBR QoS Flow information is set. + std::optional max_data_burst_volume; +}; + +struct non_dyn_5qi_descriptor_t { + five_qi_t five_qi; + std::optional qos_prio_level; + std::optional averaging_win; + std::optional max_data_burst_volume; +}; + +struct qos_characteristics_t { + std::optional dyn_5qi; + std::optional non_dyn_5qi; + + five_qi_t get_five_qi() const + { + if (non_dyn_5qi.has_value()) { + return non_dyn_5qi.value().five_qi; + } + if (dyn_5qi.has_value()) { + if (dyn_5qi.value().five_qi.has_value()) { + return dyn_5qi.value().five_qi.value(); + } + } else { + report_fatal_error("Invalid QoS characteristics. Either dynamic or non-dynamic 5QI must be set"); + } + return five_qi_t::invalid; + } +}; + +/// \brief QoS parameters for a GBR QoS flow or GBR bearer for downlink and uplink. See TS 38.473, clause 9.3.1.46. +struct gbr_qos_flow_information { + /// Maximum Bit Rate in DL. + uint64_t max_br_dl; + /// Maximum Bit Rate in UL. + uint64_t max_br_ul; + /// Guaranteed Flow Bit Rate (provided there is data to deliver) in DL. + uint64_t gbr_dl; + /// Guaranteed Flow Bit Rate (provided there is data to deliver) in UL. + uint64_t gbr_ul; + /// Indicates the maximum rate for lost packets that can be tolerated in the DL. Expressed in ratio of lost packets + /// per number of packets sent, expressed in tenth of percent.Values {0,...,1000}. + std::optional max_packet_loss_rate_dl; + /// Indicates the maximum rate for lost packets that can be tolerated in the UL. Expressed in ratio of lost packets + /// per number of packets sent, expressed in tenth of percent.Values {0,...,1000}. + std::optional max_packet_loss_rate_ul; +}; + +struct alloc_and_retention_priority { + /// Priority level, where highest is 1, lowest is 14, no-priority is 15. The value 0 is reserved. + uint8_t prio_level_arp = 15; + bool may_trigger_preemption = false; + bool is_preemptable = false; +}; + +struct qos_flow_level_qos_parameters { + qos_characteristics_t qos_characteristics; + alloc_and_retention_priority alloc_retention_prio; + /// This parameter applies to GBR flows only. See TS 38.473, clause 9.3.1.45. + std::optional gbr_qos_info; + bool add_qos_flow_info = false; + /// This parameter applies to non-GBR flows only. See TS 23.501. + bool reflective_qos_attribute_subject_to = false; +}; + +} // namespace srsran \ No newline at end of file diff --git a/include/srsran/ran/qos_prio_level.h b/include/srsran/ran/qos/qos_prio_level.h similarity index 100% rename from include/srsran/ran/qos_prio_level.h rename to include/srsran/ran/qos/qos_prio_level.h diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index b4b3be3814..2f50d289a5 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -19,7 +19,7 @@ #include "srsran/ran/phy_time_unit.h" #include "srsran/ran/prach/prach_constants.h" #include "srsran/ran/qos/five_qi_qos_mapping.h" -#include "srsran/ran/qos/qos_info.h" +#include "srsran/ran/qos/qos_parameters.h" #include "srsran/ran/rnti.h" #include "srsran/ran/rrm.h" #include "srsran/ran/s_nssai.h" @@ -125,7 +125,7 @@ struct sched_drb_info { /// QoS characteristics associated with the logical channel. qos_characteristics qos_info; /// QoS information present only for GBR QoS flows. - std::optional gbr_qos_info; + std::optional gbr_qos_info; }; /// Request for a new UE configuration provided to the scheduler during UE creation or reconfiguration. diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index eb1ec15f5b..c3338eacb2 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -269,13 +269,13 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex for (const auto& drb : pdu_session.second.drb_to_add) { const up_drb_context& drb_context = drb.second; - f1ap_drbs_to_be_setup_mod_item drb_item; + f1ap_drb_to_setup drb_item; drb_item.drb_id = drb_context.drb_id; drb_item.qos_info.drb_qos = drb_context.qos_params; // Add each QoS flow including QoS. for (const auto& flow : drb_context.qos_flows) { - f1ap_flows_mapped_to_drb_item flow_item; + flow_mapped_to_drb flow_item; flow_item.qos_flow_id = flow.first; flow_item.qos_flow_level_qos_params = flow.second.qos_params; drb_item.qos_info.flows_mapped_to_drb_list.push_back(flow_item); diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index d56cc462a5..2887608ce8 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -44,12 +44,8 @@ void srsran::srs_cu_cp::fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_it // TODO: Add dynamic 5qi } - e1ap_qos_item.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.prio_level = - request_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp; - e1ap_qos_item.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_cap = - request_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap; - e1ap_qos_item.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_vulnerability = - request_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability; + e1ap_qos_item.qos_flow_level_qos_params.ng_ran_alloc_retention = + request_item.qos_flow_level_qos_params.alloc_retention_prio; } bool srsran::srs_cu_cp::verify_and_log_cell_group_config(const byte_buffer& packed_config, @@ -177,7 +173,7 @@ bool srsran::srs_cu_cp::fill_rrc_reconfig_args( return true; } -bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_item, // Request to setup DRB at DU. +bool fill_f1ap_drb_setup_mod_item(f1ap_drb_to_setup& drb_setup_mod_item, // Request to setup DRB at DU. slotted_id_vector* response_flow_list, pdu_session_id_t psi, drb_id_t drb_id, @@ -203,8 +199,8 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ drb_setup_mod_item.drb_id = drb_id; // QoS config. - drb_setup_mod_item.qos_info.drb_qos.qos_characteristics = next_drb_config.qos_params.qos_characteristics; - drb_setup_mod_item.qos_info.drb_qos.alloc_and_retention_prio = next_drb_config.qos_params.alloc_and_retention_prio; + drb_setup_mod_item.qos_info.drb_qos.qos_characteristics = next_drb_config.qos_params.qos_characteristics; + drb_setup_mod_item.qos_info.drb_qos.alloc_retention_prio = next_drb_config.qos_params.alloc_retention_prio; // S-NSSAI drb_setup_mod_item.qos_info.s_nssai = next_drb_config.s_nssai; @@ -244,11 +240,10 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ const auto& ngap_qos_flow = ngap_qos_flow_setup_items[e1ap_flow.qos_flow_id]; // Add flow to F1AP DRB item - f1ap_flows_mapped_to_drb_item flow_mapped_to_drb; - flow_mapped_to_drb.qos_flow_id = e1ap_flow.qos_flow_id; - flow_mapped_to_drb.qos_flow_level_qos_params = ngap_qos_flow.qos_flow_level_qos_params; - - drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(flow_mapped_to_drb); + flow_mapped_to_drb flow_map_item; + flow_map_item.qos_flow_id = e1ap_flow.qos_flow_id; + flow_map_item.qos_flow_level_qos_params = ngap_qos_flow.qos_flow_level_qos_params; + drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(flow_map_item); // Store flow QoS params in UP config. auto& next_config_flow_cfg = next_drb_config.qos_flows.at(e1ap_flow.qos_flow_id); @@ -261,7 +256,7 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drbs_to_be_setup_mod_item& drb_setup_mod_ bool srsran::srs_cu_cp::update_setup_list( slotted_id_vector& ngap_response_list, std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, @@ -363,7 +358,7 @@ bool srsran::srs_cu_cp::update_setup_list( next_cfg_pdu_session.drb_to_add.find(drb_id)->second.pdcp_cfg.ciphering_required = ciphering_enabled; // Prepare DRB item for DU. - f1ap_drbs_to_be_setup_mod_item drb_setup_mod_item; + f1ap_drb_to_setup drb_setup_mod_item; if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, &transfer.dlqos_flow_per_tnl_info.associated_qos_flow_list, item.pdu_session_id, @@ -392,7 +387,7 @@ bool srsran::srs_cu_cp::update_setup_list( bool srsran::srs_cu_cp::update_setup_list( std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, @@ -432,7 +427,7 @@ bool srsran::srs_cu_cp::update_setup_list( } // Prepare DRB item for DU. - f1ap_drbs_to_be_setup_mod_item drb_setup_mod_item; + f1ap_drb_to_setup drb_setup_mod_item; if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, {}, e1ap_item.pdu_session_id, @@ -559,7 +554,7 @@ bool srsran::srs_cu_cp::update_modify_list( const auto& request_transfer = ngap_modify_list[psi].transfer; // Prepare DRB creation at DU. - f1ap_drbs_to_be_setup_mod_item drb_setup_mod_item; + f1ap_drb_to_setup drb_setup_mod_item; if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, nullptr, psi, diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index ac48889204..40c8100b73 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -75,7 +75,7 @@ bool fill_rrc_reconfig_args(rrc_reconfiguration_procedure_request& bool update_setup_list( slotted_id_vector& ngap_response_list, std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, @@ -85,7 +85,7 @@ bool update_setup_list( const srslog::basic_logger& logger); bool update_setup_list(std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, + std::vector& drb_setup_mod_list, const slotted_id_vector& ngap_setup_list, const slotted_id_vector& pdu_session_resource_setup_list, diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 66ca2ac659..224b5ac125 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -217,7 +217,7 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat // Fill UE context modification for DU { - f1ap_drbs_to_be_setup_mod_item drb_setup_mod_item; + f1ap_drb_to_setup drb_setup_mod_item; drb_setup_mod_item.drb_id = e1ap_drb_item.drb_id; // Add up tnl info @@ -236,7 +236,7 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat // Fill QoS flows for UE context modification. for (const auto& flow : drb_up_context.qos_flows) { // Add mapped flows and extract required QoS info from original NGAP request - f1ap_flows_mapped_to_drb_item mapped_flow_item; + flow_mapped_to_drb mapped_flow_item; mapped_flow_item.qos_flow_id = flow.first; mapped_flow_item.qos_flow_level_qos_params = drb_up_context.qos_params; drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(mapped_flow_item); diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp index 8de8e3d15a..263a77a15c 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp @@ -223,10 +223,10 @@ drb_id_t allocate_qos_flow(up_pdu_session_context_update& new_session_contex // Fill QoS (TODO: derive QoS params correctly) auto& qos_params = drb_ctx.qos_params; qos_params.qos_characteristics.non_dyn_5qi.emplace(); - qos_params.qos_characteristics.non_dyn_5qi.value().five_qi = five_qi; - qos_params.alloc_and_retention_prio.prio_level_arp = 8; - qos_params.alloc_and_retention_prio.pre_emption_cap = "shall-not-trigger-pre-emption"; - qos_params.alloc_and_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + qos_params.qos_characteristics.non_dyn_5qi.value().five_qi = five_qi; + qos_params.alloc_retention_prio.prio_level_arp = 8; + qos_params.alloc_retention_prio.may_trigger_preemption = false; + qos_params.alloc_retention_prio.is_preemptable = false; // Add flow up_qos_flow_context flow_ctx; diff --git a/lib/du_manager/du_ue/du_bearer.h b/lib/du_manager/du_ue/du_bearer.h index 239e3a25e5..1ecff5fd97 100644 --- a/lib/du_manager/du_ue/du_bearer.h +++ b/lib/du_manager/du_ue/du_bearer.h @@ -17,7 +17,7 @@ #include "srsran/mac/mac_lc_config.h" #include "srsran/ran/lcid.h" #include "srsran/ran/qos/five_qi_qos_mapping.h" -#include "srsran/ran/qos/qos_info.h" +#include "srsran/ran/qos/qos_parameters.h" #include "srsran/ran/s_nssai.h" #include "srsran/ran/up_transport_layer_info.h" #include "srsran/rlc/rlc_config.h" @@ -109,7 +109,7 @@ struct du_ue_drb { /// QoS characteristics to be met by the DRB. qos_characteristics qos_info; /// QoS information present only for GBR QoS flows. - std::optional gbr_qos_info; + std::optional gbr_qos_info; /// \brief Stops DRB by disconnecting MAC, RLC and F1-U notifiers and stopping the RLC timers. void stop(); @@ -117,20 +117,20 @@ struct du_ue_drb { /// Holds information needed to create a DRB in the DU. struct drb_creation_info { - du_ue_index_t ue_index; - du_cell_index_t pcell_index; - drb_id_t drb_id; - lcid_t lcid; - const rlc_config& rlc_cfg; - const mac_lc_config& mac_cfg; - const f1u_config& f1u_cfg; - span uluptnl_info_list; - gtpu_teid_pool& teid_pool; - const du_manager_params& du_params; - rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier; - const qos_characteristics& qos_info; - std::optional gbr_qos_info; - s_nssai_t s_nssai; + du_ue_index_t ue_index; + du_cell_index_t pcell_index; + drb_id_t drb_id; + lcid_t lcid; + const rlc_config& rlc_cfg; + const mac_lc_config& mac_cfg; + const f1u_config& f1u_cfg; + span uluptnl_info_list; + gtpu_teid_pool& teid_pool; + const du_manager_params& du_params; + rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier; + const qos_characteristics& qos_info; + std::optional gbr_qos_info; + s_nssai_t s_nssai; }; /// \brief Creates a DRB instance for the whole DU. diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 1b63dfe3e7..ea4d094687 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -135,7 +135,7 @@ void ue_configuration_procedure::update_ue_context() } // > Create new DU UE DRB objects. - for (const f1ap_drb_setup_request& drbtoadd : request.drbs_to_setup) { + for (const f1ap_drb_to_setup& drbtoadd : request.drbs_to_setup) { if (drbtoadd.uluptnl_info_list.empty()) { proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtoadd.drb_id); continue; @@ -153,28 +153,28 @@ void ue_configuration_procedure::update_ue_context() srsran_assert(it != ue->resources->rlc_bearers.end(), "The bearer config should be created at this point"); // Find the F1-U configuration for this DRB. - auto f1u_cfg_it = du_params.ran.qos.find(drbtoadd.five_qi); - srsran_assert(f1u_cfg_it != du_params.ran.qos.end(), "Undefined F1-U bearer config for {}", drbtoadd.five_qi); + five_qi_t fiveqi = drbtoadd.qos_info.drb_qos.qos_characteristics.get_five_qi(); + auto f1u_cfg_it = du_params.ran.qos.find(fiveqi); + srsran_assert(f1u_cfg_it != du_params.ran.qos.end(), "Undefined F1-U bearer config for {}", fiveqi); // TODO: Adjust QoS characteristics passed while creating a DRB since one DRB can contain multiple QoS flow of // varying 5QI. // Create DU DRB instance. - std::unique_ptr drb = - create_drb(drb_creation_info{ue->ue_index, - ue->pcell_index, - drbtoadd.drb_id, - it->lcid, - it->rlc_cfg, - it->mac_cfg, - f1u_cfg_it->second.f1u, - drbtoadd.uluptnl_info_list, - ue_mng.get_f1u_teid_pool(), - du_params, - ue->get_rlc_rlf_notifier(), - get_5qi_to_qos_characteristics_mapping(drbtoadd.five_qi), - drbtoadd.gbr_flow_info, - drbtoadd.s_nssai}); + std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, + ue->pcell_index, + drbtoadd.drb_id, + it->lcid, + it->rlc_cfg, + it->mac_cfg, + f1u_cfg_it->second.f1u, + drbtoadd.uluptnl_info_list, + ue_mng.get_f1u_teid_pool(), + du_params, + ue->get_rlc_rlf_notifier(), + get_5qi_to_qos_characteristics_mapping(fiveqi), + drbtoadd.qos_info.drb_qos.gbr_qos_info, + drbtoadd.qos_info.s_nssai}); if (drb == nullptr) { proc_logger.log_proc_warning("Failed to create {}. Cause: Failed to allocate DU UE resources.", drbtoadd.drb_id); continue; @@ -246,7 +246,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo resp.result = true; // > Handle DRBs that were setup or failed to be setup. - for (const f1ap_drb_setup_request& drb_req : request.drbs_to_setup) { + for (const f1ap_drb_to_setup& drb_req : request.drbs_to_setup) { if (ue->bearers.drbs().count(drb_req.drb_id) == 0) { resp.failed_drbs_setups.push_back({drb_req.drb_id, f1ap_cause_radio_network_t::no_radio_res_available}); continue; diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index cbdd2f6f6d..85739131f2 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -110,21 +110,22 @@ static error_type validate_drb_modification_request(const f1ap_drb_ return {}; } -static error_type validate_drb_setup_request(const f1ap_drb_setup_request& drb, +static error_type validate_drb_setup_request(const f1ap_drb_to_setup& drb, span rlc_bearers, const std::map& qos_config) { // Validate QOS config. - auto qos_it = qos_config.find(drb.five_qi); + five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); + auto qos_it = qos_config.find(fiveqi); if (qos_it == qos_config.end()) { - return make_unexpected(fmt::format("Failed to allocate {}. Cause: No {} 5QI configured", drb.drb_id, drb.five_qi)); + return make_unexpected(fmt::format("Failed to allocate {}. Cause: No {} 5QI configured", drb.drb_id, fiveqi)); } const du_qos_config& qos = qos_it->second; if (qos.rlc.mode != drb.mode) { return make_unexpected( fmt::format("RLC mode mismatch for {}. QoS config for {} configures {} but CU-CP requested {}", drb.drb_id, - drb.five_qi, + fiveqi, qos.rlc.mode, drb.mode)); } @@ -198,7 +199,7 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } // > Create new DRBs. - for (const f1ap_drb_setup_request& drb : upd_req.drbs_to_setup) { + for (const f1ap_drb_to_setup& drb : upd_req.drbs_to_setup) { auto res = validate_drb_setup_request(drb, ue_mcg.rlc_bearers, qos_config); if (not res.has_value()) { resp.failed_drbs.push_back(drb.drb_id); @@ -214,7 +215,8 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } // >> Get RLC config from 5QI - const du_qos_config& qos = qos_config.at(drb.five_qi); + five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); + const du_qos_config& qos = qos_config.at(fiveqi); ue_mcg.rlc_bearers.emplace_back(); ue_mcg.rlc_bearers.back().lcid = lcid; ue_mcg.rlc_bearers.back().drb_id = drb.drb_id; diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h index ad41283309..54ddb45c14 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h @@ -12,7 +12,7 @@ #include "du_pucch_resource_manager.h" #include "du_ran_resource_manager.h" -#include "srsran/ran/five_qi.h" +#include "srsran/ran/qos/five_qi.h" namespace srsran { namespace srs_du { diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index 79936ac0fc..9b6fce5e4c 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -18,7 +18,7 @@ #include "srsran/ran/cause/e1ap_cause.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/nr_cgi.h" -#include "srsran/ran/qos_prio_level.h" +#include "srsran/ran/qos/qos_prio_level.h" #include "srsran/ran/s_nssai.h" #include "srsran/sdap/sdap_config.h" #include "srsran/security/security.h" @@ -1100,16 +1100,17 @@ inline void e1ap_asn1_to_flow_map_info(slotted_id_vector -inline void f1ap_drbs_to_be_setup_mod_item_to_asn1(template_asn1_item& asn1_drb_to_be_setup_mod_item, - const f1ap_drbs_to_be_setup_mod_item& drb_to_be_setup_mod_item) +inline void f1ap_drb_to_setup_to_asn1(template_asn1_item& asn1_drb_to_be_setup_mod_item, + const f1ap_drb_to_setup& drb_to_be_setup_mod_item) { // drb id asn1_drb_to_be_setup_mod_item.drb_id = drb_id_to_uint(drb_to_be_setup_mod_item.drb_id); @@ -435,7 +434,7 @@ inline void f1ap_drbs_to_be_setup_mod_item_to_asn1(template_asn1_item& asn1_drb_to_be_setup_mod_item.rlc_mode = rlc_mode_to_f1ap_asn1(drb_to_be_setup_mod_item.mode); // pdcp sn size - f1ap_drbs_to_be_setup_mod_item_ext_ies_to_asn1(asn1_drb_to_be_setup_mod_item.ie_exts, drb_to_be_setup_mod_item); + f1ap_drb_to_setup_ext_ies_to_asn1(asn1_drb_to_be_setup_mod_item.ie_exts, drb_to_be_setup_mod_item); asn1_drb_to_be_setup_mod_item.ie_exts_present = true; } diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index 160ee67c10..7dc3b5cab2 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -157,8 +157,8 @@ inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod asn1_drb_to_be_setup_mod_item_container; asn1_drb_to_be_setup_mod_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_SETUP_MOD_ITEM); - f1ap_drbs_to_be_setup_mod_item_to_asn1( - asn1_drb_to_be_setup_mod_item_container.value().drbs_to_be_setup_mod_item(), drb_to_be_setup_mod_item); + f1ap_drb_to_setup_to_asn1(asn1_drb_to_be_setup_mod_item_container.value().drbs_to_be_setup_mod_item(), + drb_to_be_setup_mod_item); asn1_request->drbs_to_be_setup_mod_list.push_back(asn1_drb_to_be_setup_mod_item_container); } diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index 58a960af60..01efcbc3e9 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -306,8 +306,8 @@ static void fill_asn1_ue_context_setup_request(asn1::f1ap::ue_context_setup_requ asn1::protocol_ie_single_container_s asn1_drb_to_be_setup_item_container; asn1_drb_to_be_setup_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_SETUP_ITEM); - f1ap_drbs_to_be_setup_mod_item_to_asn1(asn1_drb_to_be_setup_item_container.value().drbs_to_be_setup_item(), - drb_to_be_setup_item); + f1ap_drb_to_setup_to_asn1(asn1_drb_to_be_setup_item_container.value().drbs_to_be_setup_item(), + drb_to_be_setup_item); asn1_request->drbs_to_be_setup_list.push_back(asn1_drb_to_be_setup_item_container); } diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp index 391e2f9cd0..4dbe66fbc2 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -32,27 +32,30 @@ static rlc_mode get_rlc_mode(const asn1::f1ap::rlc_mode_e& asn1type) } template -static void fill_common_drb_config_request_fields(f1ap_drb_setup_request& drb_obj, const ASN1Type& drb_item) +static void fill_common_drb_config_request_fields(f1ap_drb_to_setup& drb_obj, const ASN1Type& drb_item) { drb_obj.drb_id = static_cast(drb_item.drb_id); drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(drb_item.ul_up_tnl_info_to_be_setup_list); // TODO: Handle Dynamic 5QI. - const auto& asn1_drbinfo = drb_item.qos_info.choice_ext().value().drb_info(); - drb_obj.five_qi = uint_to_five_qi(asn1_drbinfo.drb_qos.qos_characteristics.non_dyn_5qi().five_qi); - drb_obj.arp_priority_level = asn1_drbinfo.drb_qos.ngra_nalloc_retention_prio.prio_level; - drb_obj.s_nssai.sst = asn1_drbinfo.snssai.sst.to_number(); + const auto& asn1_drbinfo = drb_item.qos_info.choice_ext().value().drb_info(); + drb_obj.qos_info.drb_qos.qos_characteristics.non_dyn_5qi.emplace(); + auto& nondyn_5qi = drb_obj.qos_info.drb_qos.qos_characteristics.non_dyn_5qi.value(); + nondyn_5qi.five_qi = uint_to_five_qi(asn1_drbinfo.drb_qos.qos_characteristics.non_dyn_5qi().five_qi); + drb_obj.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = + asn1_drbinfo.drb_qos.ngra_nalloc_retention_prio.prio_level; + drb_obj.qos_info.s_nssai.sst = asn1_drbinfo.snssai.sst.to_number(); if (asn1_drbinfo.snssai.sd_present) { - drb_obj.s_nssai.sd = drb_item.qos_info.choice_ext().value().drb_info().snssai.sd.to_number(); + drb_obj.qos_info.s_nssai.sd = drb_item.qos_info.choice_ext().value().drb_info().snssai.sd.to_number(); } // TODO: Do not populate gbr_flow_info for non-GBR flows. if (asn1_drbinfo.drb_qos.gbr_qos_flow_info_present) { - drb_obj.gbr_flow_info.emplace(); - auto& gbr = drb_obj.gbr_flow_info.value(); - gbr.max_flow_dl_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; - gbr.max_flow_ul_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; - gbr.guaranteed_flow_dl_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; - gbr.guaranteed_flow_ul_bitrate = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; + drb_obj.qos_info.drb_qos.gbr_qos_info.emplace(); + auto& gbr = drb_obj.qos_info.drb_qos.gbr_qos_info.value(); + gbr.max_br_dl = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; + gbr.max_br_ul = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; + gbr.gbr_dl = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; + gbr.gbr_ul = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; if (asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { gbr.max_packet_loss_rate_dl.emplace(asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); } @@ -62,9 +65,9 @@ static void fill_common_drb_config_request_fields(f1ap_drb_setup_request& drb_ob } } -f1ap_drb_setup_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) +f1ap_drb_to_setup srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) { - f1ap_drb_setup_request drb_obj; + f1ap_drb_to_setup drb_obj; fill_common_drb_config_request_fields(drb_obj, drb_item); drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); @@ -76,9 +79,9 @@ f1ap_drb_setup_request srsran::srs_du::make_drb_config_request(const asn1::f1ap: return drb_obj; } -f1ap_drb_setup_request srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) +f1ap_drb_to_setup srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) { - f1ap_drb_setup_request drb_obj; + f1ap_drb_to_setup drb_obj; fill_common_drb_config_request_fields(drb_obj, drb_item); drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h index a3399bdba6..6ced687c09 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h @@ -33,10 +33,10 @@ srb_id_t make_srb_id(const Asn1Type& srb_item) } /// Convert 3GPP TS 38.473, DRBs-ToBeSetup-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_setup_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); +f1ap_drb_to_setup make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); /// Convert 3GPP TS 38.473, DRBs-ToBeSetupMod-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_setup_request make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); +f1ap_drb_to_setup make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); } // namespace srs_du } // namespace srsran diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index a93f4d62fc..f25aae8a4c 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -310,12 +310,14 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re } // allocationAndRetentionPriority - qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp; - qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = - asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap.to_string(); - qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = - asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability.to_string(); + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_retention_prio.may_trigger_preemption = + asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap == + asn1::ngap::pre_emption_cap_opts::may_trigger_pre_emption; + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_retention_prio.is_preemptable = + asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability == + asn1::ngap::pre_emption_vulnerability_opts::pre_emptable; // Optional Parameters if (asn1_flow_item.qos_flow_level_qos_params.add_qos_flow_info_present) { @@ -328,8 +330,7 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re } if (asn1_flow_item.qos_flow_level_qos_params.reflective_qos_attribute_present) { - qos_flow_setup_req_item.qos_flow_level_qos_params.reflective_qos_attribute = - asn1::enum_to_bool(asn1_flow_item.qos_flow_level_qos_params.reflective_qos_attribute); + qos_flow_setup_req_item.qos_flow_level_qos_params.reflective_qos_attribute_subject_to = true; } if (asn1_flow_item.erab_id_present) { @@ -611,12 +612,14 @@ inline bool fill_cu_cp_pdu_session_resource_modify_item_base( } // allocationAndRetentionPriority - qos_flow_add_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = + qos_flow_add_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp; - qos_flow_add_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = - asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap.to_string(); - qos_flow_add_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = - asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability.to_string(); + qos_flow_add_item.qos_flow_level_qos_params.alloc_retention_prio.may_trigger_preemption = + asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap.value == + asn1::ngap::pre_emption_cap_opts::may_trigger_pre_emption; + qos_flow_add_item.qos_flow_level_qos_params.alloc_retention_prio.is_preemptable = + asn1_flow_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability.value == + asn1::ngap::pre_emption_vulnerability_opts::pre_emptable; } modify_item.transfer.qos_flow_add_or_modify_request_list.emplace(qos_flow_add_item.qos_flow_id, diff --git a/lib/ngap/ngap_validators/ngap_validators.cpp b/lib/ngap/ngap_validators/ngap_validators.cpp index 615a4a7a4a..1773b749bd 100644 --- a/lib/ngap/ngap_validators/ngap_validators.cpp +++ b/lib/ngap/ngap_validators/ngap_validators.cpp @@ -52,8 +52,8 @@ pdu_session_resource_setup_validation_outcome srsran::srs_cu_cp::verify_pdu_sess // If Non-GBR QoS flow present then PDU Session Aggregate Maximum Bit Rate must be present for (auto& psi : psis) { for (const auto& qos_flow_item : request.pdu_session_res_setup_items[psi].qos_flow_setup_request_items) { - if (qos_flow_item.qos_flow_level_qos_params.reflective_qos_attribute.has_value() || - qos_flow_item.qos_flow_level_qos_params.add_qos_flow_info.has_value()) { + if (qos_flow_item.qos_flow_level_qos_params.reflective_qos_attribute_subject_to || + qos_flow_item.qos_flow_level_qos_params.add_qos_flow_info) { if (!asn1_request->ue_aggr_max_bit_rate_present) { ue_logger.log_warning("Non-GBR QoS flow for {} present but PduSessionAggregateMaximumBitRate not set", psi); failed_psis.emplace(psi); diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.cpp b/tests/unittests/cu_cp/cu_cp_test_messages.cpp index 4ed1a581bf..55e9cc4869 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_messages.cpp @@ -63,9 +63,7 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(ue_index_t ue_index, non_dyn_5qi.five_qi = uint_to_five_qi(9); // all with same FiveQI qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - qos_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = 8; - qos_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = "not-pre-emptable"; - qos_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + qos_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 8; item.qos_flow_setup_request_items.emplace(qos_item.qos_flow_id, qos_item); } @@ -106,11 +104,9 @@ srsran::srs_cu_cp::generate_pdu_session_resource_modification(ue_index_t ue_inde qos_item.qos_flow_id = uint_to_qos_flow_id(qfi); { non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = uint_to_five_qi(7); - qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - qos_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = 8; - qos_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = "not-pre-emptable"; - qos_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + non_dyn_5qi.five_qi = uint_to_five_qi(7); + qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 8; } cu_cp_pdu_session_res_modify_request_transfer transfer; diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 910c72f4c5..154182c6a1 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -157,11 +157,9 @@ generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qo e1ap_qos_flow_qos_param_item qos_flow_info; qos_flow_info.qos_flow_id = qfi; non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = five_qi; - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.prio_level = 1; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_cap = "shall-not-trigger-pre-emption"; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + non_dyn_5qi.five_qi = five_qi; + qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); pdu_session_setup_item.drb_to_setup_list_ng_ran.emplace(drb_to_setup_item.drb_id, drb_to_setup_item); @@ -223,12 +221,9 @@ generate_pdu_session_res_to_modify_item_to_setup_drb(pdu_session_id_t e1ap_qos_flow_qos_param_item qos_flow_info; qos_flow_info.qos_flow_id = qfi; non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = five_qi; - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.prio_level = 1; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_cap = - "shall-not-trigger-pre-emption"; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + non_dyn_5qi.five_qi = five_qi; + qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index e5c1460bd2..658685e419 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -86,9 +86,9 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t for (drb_id_t drb_id : drbs_to_addmod) { req.drbs_to_setup.emplace_back(); - req.drbs_to_setup.back().drb_id = drb_id; - req.drbs_to_setup.back().mode = rlc_mode::am; - req.drbs_to_setup.back().five_qi = uint_to_five_qi(9); + req.drbs_to_setup.back().drb_id = drb_id; + req.drbs_to_setup.back().mode = rlc_mode::am; + req.drbs_to_setup.back().qos_info.drb_qos.qos_characteristics.non_dyn_5qi.emplace().five_qi = uint_to_five_qi(9); req.drbs_to_setup.back().uluptnl_info_list.resize(1); req.drbs_to_setup.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 307a464aeb..677b3eb73b 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -82,7 +82,7 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_setup_request& drb : req.drbs_to_setup) { + for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 1cec2950ac..99da349be2 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -42,7 +42,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test this->cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } - for (const f1ap_drb_setup_request& drb : req.drbs_to_setup) { + for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { this->cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); this->cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; @@ -99,7 +99,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test ASSERT_FALSE(srb_it->reestablish_rlc_present); } } - for (const f1ap_drb_setup_request& drb : req.drbs_to_setup) { + for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), [&drb](const auto& b) { diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 91614b05e7..37e935aa52 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -114,11 +114,11 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set e1ap_qos_flow_qos_param_item qos_flow_info; qos_flow_info.qos_flow_id = uint_to_qos_flow_id(8); non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = uint_to_five_qi(8); - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.prio_level = 1; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_cap = "shall-not-trigger-pre-emption"; - qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + non_dyn_5qi.five_qi = uint_to_five_qi(8); + qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; + qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.may_trigger_preemption = false; + qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.is_preemptable = false; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); res_to_setup_item.drb_to_setup_list_ng_ran.emplace(drb_to_setup_item.drb_id, drb_to_setup_item); diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 43cdb97f10..f9f588374e 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -224,7 +224,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi msg.srbs_to_be_setup_mod_list.push_back(srbs_to_be_setup_mod_item); // drbs to be setup mod list - f1ap_drbs_to_be_setup_mod_item drbs_to_be_setup_mod_item; + f1ap_drb_to_setup drbs_to_be_setup_mod_item; drbs_to_be_setup_mod_item.drb_id = uint_to_drb_id(1); // qos info @@ -239,22 +239,21 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_setup_mod_item.qos_info.drb_qos.qos_characteristics.non_dyn_5qi = non_dyn_5qi; // ng ran alloc retention prio - drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_and_retention_prio.prio_level_arp = 1; - drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_and_retention_prio.pre_emption_cap = "shall-not-trigger-pre-emption"; - drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_and_retention_prio.pre_emption_vulnerability = "not-pre-emptable"; + drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = 1; + drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_retention_prio.may_trigger_preemption = false; + drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_retention_prio.is_preemptable = false; // gbr qos flow info - cu_cp_gbr_qos_info gbr_qos_info; - gbr_qos_info.max_flow_bit_rate_dl = 100000; - gbr_qos_info.max_flow_bit_rate_ul = 100000; - gbr_qos_info.guaranteed_flow_bit_rate_dl = 100000; - gbr_qos_info.guaranteed_flow_bit_rate_ul = 100000; - gbr_qos_info.max_packet_loss_rate_dl = 30; - gbr_qos_info.max_packet_loss_rate_ul = 30; - drbs_to_be_setup_mod_item.qos_info.drb_qos.gbr_qos_info = gbr_qos_info; + auto& gbr_qos_info = drbs_to_be_setup_mod_item.qos_info.drb_qos.gbr_qos_info.emplace(); + gbr_qos_info.max_br_dl = 100000; + gbr_qos_info.max_br_ul = 100000; + gbr_qos_info.gbr_dl = 100000; + gbr_qos_info.gbr_ul = 100000; + gbr_qos_info.max_packet_loss_rate_dl = 30; + gbr_qos_info.max_packet_loss_rate_ul = 30; // reflective qos attribute - drbs_to_be_setup_mod_item.qos_info.drb_qos.reflective_qos_attribute = true; + drbs_to_be_setup_mod_item.qos_info.drb_qos.reflective_qos_attribute_subject_to = true; // s nssai drbs_to_be_setup_mod_item.qos_info.s_nssai.sst = 1; @@ -264,20 +263,18 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_setup_mod_item.qos_info.notif_ctrl = drb_notification_control::active; // flows mapped to drb list - f1ap_flows_mapped_to_drb_item flows_mapped_to_drb_item; + flow_mapped_to_drb flows_mapped_to_drb_item; flows_mapped_to_drb_item.qos_flow_id = uint_to_qos_flow_id(1); // qos characteristics flows_mapped_to_drb_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; // ng ran alloc retention prio - flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = 1; - flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = - "shall-not-trigger-pre-emption"; - flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = - "not-pre-emptable"; + flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 1; + flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.may_trigger_preemption = false; + flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.is_preemptable = false; // gbr qos flow info flows_mapped_to_drb_item.qos_flow_level_qos_params.gbr_qos_info = gbr_qos_info; // reflective qos attribute - flows_mapped_to_drb_item.qos_flow_level_qos_params.reflective_qos_attribute = true; + flows_mapped_to_drb_item.qos_flow_level_qos_params.reflective_qos_attribute_subject_to = true; drbs_to_be_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(flows_mapped_to_drb_item); diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp index b14dbf145b..ac049e3745 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp @@ -14,8 +14,8 @@ #include "srsran/asn1/rrc_nr/dl_ccch_msg_ies.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/cu_cp/f1ap_cu_factory.h" -#include "srsran/ran/five_qi.h" #include "srsran/ran/nr_cgi.h" +#include "srsran/ran/qos/five_qi.h" #include "srsran/support/async/async_test_utils.h" #include "srsran/support/test_utils.h" @@ -144,16 +144,14 @@ srsran::srs_cu_cp::create_ue_context_setup_request(const std::initializer_list Date: Tue, 6 Aug 2024 10:02:17 +0000 Subject: [PATCH 105/407] re-apply "srsvec,compression: improve simd in bf16 conversion, optimize AVX"; and change it to work with viavi --- include/srsran/srsvec/conversion.h | 7 + include/srsran/srsvec/prod.h | 1 + include/srsran/srsvec/sc_prod.h | 1 + .../compression/iq_compression_bfp_avx2.cpp | 34 ++-- .../compression/iq_compression_bfp_avx512.cpp | 34 ++-- .../compression/iq_compression_bfp_neon.cpp | 1 + .../compression/iq_compression_none_avx2.cpp | 24 +-- .../iq_compression_none_avx512.cpp | 23 +-- .../compression/iq_compression_none_neon.cpp | 17 +- lib/srsvec/conversion.cpp | 159 +++++++++++++++++- lib/srsvec/prod.cpp | 39 +++++ lib/srsvec/sc_prod.cpp | 37 ++++ lib/srsvec/simd.h | 34 +++- .../unittests/srsvec/srsvec_convert_test.cpp | 26 +++ 14 files changed, 375 insertions(+), 62 deletions(-) diff --git a/include/srsran/srsvec/conversion.h b/include/srsran/srsvec/conversion.h index c3810860a6..34c6bb8218 100644 --- a/include/srsran/srsvec/conversion.h +++ b/include/srsran/srsvec/conversion.h @@ -85,6 +85,13 @@ void convert(span z, span x, float scale); /// \param [in] scale Input data scaling after conversion. void convert(span z, span x, float scale); +/// \brief Converts from int16 to complex brain float applying the given scaling per input element. +/// +/// \param [out] z Resultant data. +/// \param [in] x Data to convert. +/// \param [in] scale Vector of scaling factors to be applied after conversion. +void convert(span z, span x, span scale); + /// \brief Converts a sequence of numbers from brain float to int16 applying the given scaling and rounding the result /// to the nearest integer. /// diff --git a/include/srsran/srsvec/prod.h b/include/srsran/srsvec/prod.h index 1f69b2b7d8..15691be6bd 100644 --- a/include/srsran/srsvec/prod.h +++ b/include/srsran/srsvec/prod.h @@ -19,6 +19,7 @@ void prod(span x, span y, span z); void prod(span x, span y, span z); void prod(span x, span y, span z); void prod(span x, span y, span z); +void prod(span x, span y, span z); void prod_conj(span x, span y, span z); diff --git a/include/srsran/srsvec/sc_prod.h b/include/srsran/srsvec/sc_prod.h index 4c0f26dd19..18c675d0db 100644 --- a/include/srsran/srsvec/sc_prod.h +++ b/include/srsran/srsvec/sc_prod.h @@ -19,6 +19,7 @@ void sc_prod(span x, cf_t h, span z); void sc_prod(span x, cf_t h, span z); void sc_prod(span x, float h, span z); void sc_prod(span x, float h, span z); +void sc_prod(span x, int16_t h, span z); } // namespace srsvec } // namespace srsran diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.cpp b/lib/ofh/compression/iq_compression_bfp_avx2.cpp index de4a2de91d..b711f91c31 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx2.cpp @@ -12,6 +12,7 @@ #include "avx2_helpers.h" #include "packing_utils_avx2.h" #include "quantizer.h" +#include "srsran/srsvec/prod.h" using namespace srsran; using namespace ofh; @@ -91,26 +92,33 @@ void iq_compression_bfp_avx2::decompress(span output, return; } - quantizer q_out(Q_BIT_WIDTH); + const float fixp_gain = (1 << (Q_BIT_WIDTH - 1)) - 1.0f; - unsigned out_idx = 0; + // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. + constexpr size_t avx2_size_iqs = 16; + constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; + + alignas(64) std::array unpacked_iq_data; + alignas(64) std::array unpacked_iq_scaling; + + unsigned idx = 0; for (const auto& c_prb : input) { // Compute scaling factor. uint8_t exponent = c_prb.get_compression_param(); - int16_t scaler = 1 << exponent; + float scaler = 1 << exponent; - // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. - constexpr size_t avx2_size_iqs = 16; - constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; - alignas(64) std::array unpacked_iq_data; // Unpack resource block. - mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); + mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); + // Save scaling factor. + std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler / fixp_gain); - // Convert to complex samples. - q_out.to_brain_float(output_span, unpacked_span, scaler); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); + + // Scale unpacked IQ samples using saved exponents and convert to complex samples. + srsvec::convert(output, unpacked_iq_int16_span, unpacked_iq_scaling_span); } diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.cpp b/lib/ofh/compression/iq_compression_bfp_avx512.cpp index 98b4ed782d..8d8561272c 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx512.cpp @@ -12,6 +12,7 @@ #include "avx512_helpers.h" #include "packing_utils_avx512.h" #include "quantizer.h" +#include "srsran/srsvec/prod.h" using namespace srsran; using namespace ofh; @@ -133,26 +134,33 @@ void iq_compression_bfp_avx512::decompress(span output, return; } - quantizer q_out(Q_BIT_WIDTH); + const float fixp_gain = (1 << (Q_BIT_WIDTH - 1)) - 1.0f; - unsigned out_idx = 0; + // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. + constexpr size_t avx512_size_iqs = 32; + constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx512_size_iqs) * avx512_size_iqs; + + alignas(64) std::array unpacked_iq_data; + alignas(64) std::array unpacked_iq_scaling; + + unsigned idx = 0; for (const auto& c_prb : input) { // Compute scaling factor. uint8_t exponent = c_prb.get_compression_param(); - int16_t scaler = 1 << exponent; + float scaler = 1 << exponent; - // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. - constexpr size_t avx512_size_iqs = 32; - constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx512_size_iqs) * avx512_size_iqs; - alignas(64) std::array unpacked_iq_data; // Unpack resource block. - mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); + mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); + // Save scaling factor. + std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler / fixp_gain); - // Convert to complex samples. - q_out.to_brain_float(output_span, unpacked_span, scaler); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); + + // Scale unpacked IQ samples using saved exponents and convert to complex samples. + srsvec::convert(output, unpacked_iq_int16_span, unpacked_iq_scaling_span); } diff --git a/lib/ofh/compression/iq_compression_bfp_neon.cpp b/lib/ofh/compression/iq_compression_bfp_neon.cpp index 004ae68a17..35533c9a33 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.cpp +++ b/lib/ofh/compression/iq_compression_bfp_neon.cpp @@ -209,6 +209,7 @@ void iq_compression_bfp_neon::decompress(span output, constexpr size_t neon_size_iqs = 8; constexpr size_t arr_size = divide_ceil(NOF_SAMPLES_PER_PRB, neon_size_iqs) * neon_size_iqs; alignas(64) std::array unpacked_iq_data; + // Unpack resource block. neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); diff --git a/lib/ofh/compression/iq_compression_none_avx2.cpp b/lib/ofh/compression/iq_compression_none_avx2.cpp index 8abec79574..f818d6685b 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.cpp +++ b/lib/ofh/compression/iq_compression_none_avx2.cpp @@ -86,20 +86,20 @@ void iq_compression_none_avx2::decompress(span output, // Quantizer object. quantizer q(params.data_width); - unsigned out_idx = 0; - for (const auto& c_prb : input) { - constexpr size_t avx2_size_iqs = 16; - constexpr size_t arr_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; - alignas(64) std::array unpacked_iq_data; + constexpr size_t avx2_size_iqs = 16; + constexpr size_t prb_size = divide_ceil(NOF_SUBCARRIERS_PER_RB * 2, avx2_size_iqs) * avx2_size_iqs; + alignas(64) std::array unpacked_iq_data; + unsigned idx = 0; + for (const auto& c_prb : input) { // Unpack resource block. - mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); + mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); - - // Convert to complex samples. - q.to_brain_float(output_span, unpacked_span, 1); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + // Convert to complex brain float samples. + q.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_avx512.cpp b/lib/ofh/compression/iq_compression_none_avx512.cpp index 00bdd83246..dac64caa52 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.cpp +++ b/lib/ofh/compression/iq_compression_none_avx512.cpp @@ -70,19 +70,20 @@ void iq_compression_none_avx512::decompress(span output, } // Quantizer object. - quantizer q(params.data_width); + quantizer q_out(params.data_width); - unsigned out_idx = 0; - for (const auto& c_prb : input) { - std::array unpacked_iq_data; - // Unpack resource block. - mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + std::array unpacked_iq_data; - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); + unsigned idx = 0; + for (const compressed_prb& c_prb : input) { + // Unpack resource block. + span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); + mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - // Convert to complex samples. - q.to_brain_float(output_span, unpacked_span, 1); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + // Convert to complex brain float samples. + q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_neon.cpp b/lib/ofh/compression/iq_compression_none_neon.cpp index d2925ab929..38182270c1 100644 --- a/lib/ofh/compression/iq_compression_none_neon.cpp +++ b/lib/ofh/compression/iq_compression_none_neon.cpp @@ -107,15 +107,18 @@ void iq_compression_none_neon::decompress(span output, quantizer q_out(params.data_width); - unsigned out_idx = 0; + std::array unpacked_iq_data; + + unsigned idx = 0; for (const compressed_prb& c_prb : input) { // Unpack resource block. - std::array unpacked_iq_data; - neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); + neon::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); - // Convert to complex samples. - q_out.to_brain_float(output_span, unpacked_iq_data, 1); - out_idx += NOF_SUBCARRIERS_PER_RB; + idx += (NOF_SUBCARRIERS_PER_RB * 2); } + + span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + // Convert to complex brain float samples. + q_out.to_brain_float(output, unpacked_iq_int16_span, 1); } diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index d1897e8493..c9faec2b5d 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -107,7 +107,7 @@ static void convert_if_simd(float* z, const int16_t* x, float scale, unsigned le __m256 float_vec = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(input_vec)); float_vec = _mm256_mul_ps(float_vec, scale256); - // Store the result back to memory + // Store the result back to memory. _mm256_storeu_ps(z + i, float_vec); } #endif // defined(__AVX__) && defined(__AVX2__) @@ -136,6 +136,17 @@ static void convert_bf16_to_f_simd(float* out, const bf16_t* in, unsigned len) { unsigned i = 0; +#if defined(__ARM_NEON) && defined(__ARM_FEATURE_BF16_VECTOR_ARITHMETIC) + for (unsigned i_end = (len / 4) * 4; i != i_end; i += 4) { + // Load 4 bf16 elements into a 64-bit vector register. + bfloat16x4_t input_vec = vld1_bf16(reinterpret_cast(in + i)); + // Convert bf16 to single-precision floating point. + float32x4_t output_vec = vcvt_f32_bf16(input_vec); + // Store the result back to memory. + srsran_simd_f_storeu(out + i, output_vec); + } +#else // __ARM_FEATURE_BF16 + #if SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE for (unsigned end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != end; i += SRSRAN_SIMD_S_SIZE) { simd_f_t even, odd; @@ -145,6 +156,7 @@ static void convert_bf16_to_f_simd(float* out, const bf16_t* in, unsigned len) srsran_simd_f_storeu_interleaved(out + i, even, odd); } #endif // SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE +#endif // __ARM_FEATURE_BF16 for (; i != len; ++i) { out[i] = to_float(in[i]); @@ -303,11 +315,148 @@ static void convert_int16_to_bf16_simd(bf16_t* out, const int16_t* in, float sca #endif // defined(__AVX__) && defined(__AVX2__) #endif // defined(__AVX__) && defined(__AVX512F__) +#if defined(__ARM_NEON) + // Load the scale factor into a vector register. + float32x4_t scale_f32 = vdupq_n_f32(gain); + + // Process 8 elements at a time (128 bits / 16 bits per brain float = 8 floats). + for (unsigned i_end = (len / 8) * 8; i != i_end; i += 8) { + // Load 8 int16_t elements into a 128-bit vector register. + int16x8_t input_vec = vld1q_s16(in + i); + + // Convert the int16_t elements to float and scale them. + float32x4_t float_vec_1 = vcvtq_f32_s32(vmovl_s16(vget_low_s16(input_vec))); + float32x4_t float_vec_2 = vcvtq_f32_s32(vmovl_high_s16(input_vec)); + float_vec_1 = vmulq_f32(float_vec_1, scale_f32); + float_vec_2 = vmulq_f32(float_vec_2, scale_f32); + + // Convert float to brain float and store the result back to memory. + srsran_simd_bf16_storeu(out + i, float_vec_1, float_vec_2); + } +#endif // defined(__ARM_NEON) for (; i != len; ++i) { out[i] = to_bf16(static_cast(in[i]) * gain); } } +static void convert_scaled_int16_to_bf16_simd(bf16_t* out, const int16_t* in, const float* in_gain, unsigned len) +{ + unsigned i = 0; + +#if defined(__AVX__) && defined(__AVX512F__) + // Process 32 elements at a time (512 bits / 16 bits per brain float = 32 floats). + for (unsigned i_end = (len / 32) * 32; i != i_end; i += 32) { + // Load 32 int16_t elements into a 256-bit vector register. + __m256i input_vec_1 = _mm256_loadu_si256(reinterpret_cast(in + i)); + __m256i input_vec_2 = _mm256_loadu_si256(reinterpret_cast(in + i + 16)); + + // Load the scale factor into a vector register. + __m512 scale_vec_1 = _mm512_load_ps(in_gain + i); + __m512 scale_vec_2 = _mm512_load_ps(in_gain + i + 16); + + // Convert the int16_t elements to float and scale them. + __m512 float_vec_1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(input_vec_1)); + __m512 float_vec_2 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(input_vec_2)); + float_vec_1 = _mm512_mul_ps(float_vec_1, scale_vec_1); + float_vec_2 = _mm512_mul_ps(float_vec_2, scale_vec_2); + + // Convert float to brain float and store the result back to memory. + srsran_simd_bf16_storeu(out + i, float_vec_1, float_vec_2); + } + + // Process 16 elements at a time. + for (unsigned i_end = (len / 16) * 16; i < i_end; i += 16) { + // Load 16 int16_t elements into a 256-bit vector register. + __m256i input_vec = _mm256_loadu_si256(reinterpret_cast(in + i)); + + // Load the scale factor into a vector register. + __m512 scale_vec = _mm512_load_ps(in_gain + i); + + // Convert the int16_t elements to float and scale them. + __m512 float_vec = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(input_vec)); + float_vec = _mm512_mul_ps(float_vec, scale_vec); + + // Convert float to brain float, the second half of the resulting vector is empty. + __m512i bf16_vec = srsran_simd_convert_1f_bf16(float_vec); + + // Store first half of the resulting bf16 vector to memory. + _mm512_mask_storeu_epi32(out + i, 0x00ff, bf16_vec); + } +#if defined(__AVX512VL__) && defined(__AVX512BW__) + { + unsigned remainder = len % 16; + + // Select the LSB values. + __mmask16 mask = (1 << remainder) - 1; + + // Load remaining int16_t elements into a 256-bit vector register. + __m256i input_vec = _mm256_maskz_loadu_epi16(mask, reinterpret_cast(in + i)); + + // Load remaining scale factors into a 512-bit vector register. + __m512 scale_vec = _mm512_maskz_loadu_ps(mask, in_gain + i); + + // Convert the int16_t elements to float and scale them. + __m512 float_vec = _mm512_maskz_cvtepi32_ps(mask, _mm512_maskz_cvtepi16_epi32(mask, input_vec)); + float_vec = _mm512_mul_ps(float_vec, scale_vec); + + // Convert float to brain float, the second half of the resulting vector is empty. + __m512i bf16_vec = srsran_simd_convert_1f_bf16(float_vec); + + // Store the result back to memory. + _mm512_mask_storeu_epi16(out + i, static_cast<__mmask32>(mask), bf16_vec); + return; + } +#endif // defined(__AVX512VL__) +#else // defined(__AVX__) && defined(__AVX512F__) + +#if defined(__AVX__) && defined(__AVX2__) + // Process 16 elements at a time (256 bits /16 bits per float = 16 floats). + for (unsigned i_end = (len / 16) * 16; i != i_end; i += 16) { + // Load 8 int16_t elements into two 128-bit vector registers. + __m128i input_vec_1 = _mm_loadu_si128(reinterpret_cast(in + i)); + __m128i input_vec_2 = _mm_loadu_si128(reinterpret_cast(in + i + 8)); + + // Load the scale factor into a vector register. + __m256 scale_vec_1 = _mm256_load_ps(in_gain + i); + __m256 scale_vec_2 = _mm256_load_ps(in_gain + i + 8); + + // Convert the int16_t elements to float and scale them + __m256 float_vec_1 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(input_vec_1)); + __m256 float_vec_2 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(input_vec_2)); + float_vec_1 = _mm256_mul_ps(float_vec_1, scale_vec_1); + float_vec_2 = _mm256_mul_ps(float_vec_2, scale_vec_2); + + // Convert float to brain float and store the result back to memory. + srsran_simd_bf16_storeu(out + i, float_vec_1, float_vec_2); + } +#endif // defined(__AVX__) && defined(__AVX2__) +#endif // defined(__AVX__) && defined(__AVX512F__) + +#if defined(__ARM_NEON) + // Process 8 elements at a time (128 bits / 16 bits per brain float = 8 floats). + for (unsigned i_end = (len / 8) * 8; i != i_end; i += 8) { + // Load 8 int16_t elements into a 128-bit vector register. + int16x8_t input_vec = vld1q_s16(in + i); + + // Load the scale factor into a vector register. + float32x4_t scale_f32_1 = vld1q_f32(in_gain + i); + float32x4_t scale_f32_2 = vld1q_f32(in_gain + i + 4); + + // Convert the int16_t elements to float and scale them. + float32x4_t float_vec_1 = vcvtq_f32_s32(vmovl_s16(vget_low_s16(input_vec))); + float32x4_t float_vec_2 = vcvtq_f32_s32(vmovl_high_s16(input_vec)); + float_vec_1 = vmulq_f32(float_vec_1, scale_f32_1); + float_vec_2 = vmulq_f32(float_vec_2, scale_f32_2); + + // Convert float to brain float and store the result back to memory. + srsran_simd_bf16_storeu(out + i, float_vec_1, float_vec_2); + } +#endif // defined(__ARM_NEON) + for (; i != len; ++i) { + out[i] = to_bf16(static_cast(in[i]) * in_gain[i]); + } +} + void srsran::srsvec::convert(span x, float scale, span z) { srsran_assert(2 * x.size() == z.size(), "Invalid input or output span sizes"); @@ -374,6 +523,14 @@ void srsran::srsvec::convert(span z, span x, float scale convert_int16_to_bf16_simd(reinterpret_cast(z.data()), x.data(), scale, x.size()); } +void srsran::srsvec::convert(span z, span x, span scale) +{ + srsran_assert(x.size() == 2 * z.size(), "Invalid input or output span sizes"); + srsran_assert(x.size() == scale.size(), "Invalid input data or input scaling span sizes"); + + convert_scaled_int16_to_bf16_simd(reinterpret_cast(z.data()), x.data(), scale.data(), x.size()); +} + void srsran::srsvec::convert(span z, span x, float scale) { srsran_assert(x.size() == z.size(), "Invalid input or output span sizes"); diff --git a/lib/srsvec/prod.cpp b/lib/srsvec/prod.cpp index 54ac141cb8..b3527552b6 100644 --- a/lib/srsvec/prod.cpp +++ b/lib/srsvec/prod.cpp @@ -46,6 +46,37 @@ static void prod_fff_simd(const float* x, const float* y, float* z, std::size_t } } +static void prod_sss_simd(const int16_t* x, const int16_t* y, int16_t* z, std::size_t len) +{ + std::size_t i = 0; + +#if SRSRAN_SIMD_S_SIZE + if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { + for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_load(x + i); + simd_s_t b = srsran_simd_s_load(y + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_store(z + i, r); + } + } else { + for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_loadu(x + i); + simd_s_t b = srsran_simd_s_loadu(y + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_storeu(z + i, r); + } + } +#endif + + for (; i != len; ++i) { + z[i] = x[i] * y[i]; + } +} + static void prod_ccc_simd(const cf_t* x, const cf_t* y, cf_t* z, std::size_t len) { std::size_t i = 0; @@ -124,6 +155,14 @@ void srsran::srsvec::prod(span x, span y, span prod_fff_simd(x.data(), y.data(), z.data(), x.size()); } +void srsran::srsvec::prod(span x, span y, span z) +{ + srsran_srsvec_assert_size(x, y); + srsran_srsvec_assert_size(x, z); + + prod_sss_simd(x.data(), y.data(), z.data(), x.size()); +} + void srsran::srsvec::prod_conj(span x, span y, span z) { srsran_srsvec_assert_size(x, y); diff --git a/lib/srsvec/sc_prod.cpp b/lib/srsvec/sc_prod.cpp index 1f0f40b50d..44ed3f72a4 100644 --- a/lib/srsvec/sc_prod.cpp +++ b/lib/srsvec/sc_prod.cpp @@ -94,6 +94,36 @@ static void sc_prod_ccc_simd(const cbf16_t* x, cf_t h, cbf16_t* z, std::size_t l } } +static void sc_prod_sss_simd(const int16_t* x, int16_t h, int16_t* z, std::size_t len) +{ + std::size_t i = 0; + +#if SRSRAN_SIMD_S_SIZE + simd_s_t b = srsran_simd_s_set1(h); + if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(z)) { + for (unsigned i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_load(x + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_store(z + i, r); + } + } else { + for (unsigned i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { + simd_s_t a = srsran_simd_s_loadu(x + i); + + simd_s_t r = srsran_simd_s_mul(a, b); + + srsran_simd_s_storeu(z + i, r); + } + } +#endif + + for (; i != len; ++i) { + z[i] = x[i] * h; + } +} + void srsran::srsvec::sc_prod(span x, cf_t h, span z) { srsran_srsvec_assert_size(x, z); @@ -121,3 +151,10 @@ void srsran::srsvec::sc_prod(span x, cf_t h, span z) sc_prod_ccc_simd(x.data(), h, z.data(), x.size()); } + +void srsran::srsvec::sc_prod(span x, int16_t h, span z) +{ + srsran_srsvec_assert_size(x, z); + + sc_prod_sss_simd(x.data(), h, z.data(), x.size()); +} diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index 600137901e..afbe05f9ab 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -1803,6 +1803,25 @@ inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) #endif /* __AVX512F__ */ } +inline simd_s_t srsran_simd_s_set1(int16_t x) +{ +#ifdef __AVX512F__ + return _mm512_set1_epi16(x); +#else /* __AVX512F__ */ +#ifdef __AVX2__ + return _mm256_set1_epi16(x); +#else /* __AVX2__ */ +#ifdef __SSE4_1__ + return _mm_set1_epi16(x); +#else /* __SSE4_1__ */ +#ifdef __ARM_NEON + return vdupq_n_s16(x); +#endif /* __ARM_NEON */ +#endif /* __SSE4_1__ */ +#endif /* __AVX2__ */ +#endif /* __AVX512F__ */ +} + #endif /* SRSRAN_SIMD_S_SIZE */ #if SRSRAN_SIMD_C16_SIZE @@ -2207,7 +2226,7 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) 0x3b0039, 0x3f003d), b_i32); -#else // __AVX512BW__ +#else // __AVX512BW__ const __m512i mask = _mm512_set1_epi32(0xffff0000); // Input: a0 xx | a1 xx | a2 xx | a3 xx | a4 xx | a5 xx | a6 xx | a7 xx | ... | a15 xx | // Transformations: @@ -2244,9 +2263,8 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) a_packed, _mm512_setr_epi32(0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e), b_packed); -#endif - -#else /* __AVX512F__ */ +#endif // __AVX512BW__ +#else /* __AVX512F__ */ #ifdef __AVX2__ const __m256i bias = _mm256_set1_epi32(0x7fff); const __m256i one = _mm256_set1_epi32(0x1); @@ -2311,6 +2329,11 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) ret = _mm_blend_epi16(a_packed, b_packed, 0xf0); #else /* __ARM_NEON */ #ifdef __ARM_NEON +#ifdef __ARM_FEATURE_BF16_VECTOR_ARITHMETIC + bfloat16x4_t tmp1 = vcvt_bf16_f32(a); + bfloat16x4_t tmp2 = vcvt_bf16_f32(b); + ret = vreinterpretq_s16_bf16(vcombine_bf16(tmp1, tmp2)); +#else // __ARM_FEATURE_BF16_VECTOR_ARITHMETIC const uint32x4_t bias = vdupq_n_u32(0x7fff); const uint32x4_t one = vdupq_n_u32(0x1); @@ -2330,7 +2353,8 @@ static inline simd_s_t srsran_simd_convert_2f_bf16(simd_f_t a, simd_f_t b) uint16x8_t tmp_b_2 = vextq_u16(tmp_b_1, tmp_b_1, 1); uint32x4_t b_packed = vreinterpretq_u32_u16(vorrq_u16(tmp_b_1, tmp_b_2)); - ret = vreinterpretq_s16_u32(vuzpq_u32(a_packed, b_packed).val[0]); + ret = vreinterpretq_s16_u32(vuzpq_u32(a_packed, b_packed).val[0]); +#endif /* __ARM_FEATURE_BF16_VECTOR_ARITHMETIC */ #endif /* __ARM_NEON */ #endif /* __SSE4_1__ */ #endif /* __AVX2__ */ diff --git a/tests/unittests/srsvec/srsvec_convert_test.cpp b/tests/unittests/srsvec/srsvec_convert_test.cpp index 5a6e620dbe..0b207c06a9 100644 --- a/tests/unittests/srsvec/srsvec_convert_test.cpp +++ b/tests/unittests/srsvec/srsvec_convert_test.cpp @@ -267,6 +267,32 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestInt16Float16Random) } } +TEST_P(SrsvecConvertFixture, SrsvecConvertTestScaledInt16ComplexFloat16Random) +{ + constexpr float int16_gain = 1.0 / ((1 << 15) - 1); + + std::uniform_int_distribution dist_i(-32768, 32767); + std::uniform_int_distribution dist_f(1, 128); + + const unsigned size_i16 = size * 2; + + srsvec::aligned_vec in(size_i16); + srsvec::aligned_vec gain(size_i16); + + std::generate(in.begin(), in.end(), [&dist_i]() { return dist_i(rgen); }); + std::generate(gain.begin(), gain.end(), [&dist_f]() { return int16_gain * float(dist_f(rgen)); }); + + // Convert from int16 to brain float. + srsvec::aligned_vec data_cbf16(size); + srsvec::convert(data_cbf16, in, gain); + + // Assert conversion to cbf16. + for (size_t i = 0; i != size; ++i) { + ASSERT_EQ(data_cbf16[i].real, to_bf16(in[i * 2], 1 / gain[i * 2])); + ASSERT_EQ(data_cbf16[i].imag, to_bf16(in[i * 2 + 1], 1 / gain[i * 2 + 1])); + } +} + INSTANTIATE_TEST_SUITE_P(SrsvecConvertTest, SrsvecConvertFixture, ::testing::Values(1, 5, 7, 19, 23, 257, 1234)); } // namespace \ No newline at end of file From 92275bc412f82b9d8a969f1cfa730b5e1e99637b Mon Sep 17 00:00:00 2001 From: faluco Date: Mon, 5 Aug 2024 14:01:38 +0200 Subject: [PATCH 106/407] OFH: Fix udCompHdr wrong value for IQs of 16 bits in CP and UP builders --- ...ssage_builder_dynamic_compression_impl.cpp | 4 +- ...ssage_builder_dynamic_compression_impl.cpp | 3 +- ..._builder_dynamic_compression_impl_test.cpp | 38 ++++++++++++++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/lib/ofh/serdes/ofh_cplane_message_builder_dynamic_compression_impl.cpp b/lib/ofh/serdes/ofh_cplane_message_builder_dynamic_compression_impl.cpp index 3dcde73401..9e19650d1e 100644 --- a/lib/ofh/serdes/ofh_cplane_message_builder_dynamic_compression_impl.cpp +++ b/lib/ofh/serdes/ofh_cplane_message_builder_dynamic_compression_impl.cpp @@ -23,12 +23,12 @@ void cplane_message_builder_dynamic_compression_impl::serialize_compression_head if (direction == data_direction::downlink) { static constexpr uint8_t reserved = 0; serializer.write(reserved); - return; } uint8_t value = 0; - value |= uint8_t(compr.data_width) << 4; + // Note that an IQ bitwidth of 16 bits translates to a value of 0. + value |= uint8_t(compr.data_width == 16 ? 0 : compr.data_width) << 4; value |= uint8_t(to_value(compr.type)); serializer.write(value); diff --git a/lib/ofh/serdes/ofh_uplane_message_builder_dynamic_compression_impl.cpp b/lib/ofh/serdes/ofh_uplane_message_builder_dynamic_compression_impl.cpp index 5ff970727d..3c96c9baf0 100644 --- a/lib/ofh/serdes/ofh_uplane_message_builder_dynamic_compression_impl.cpp +++ b/lib/ofh/serdes/ofh_uplane_message_builder_dynamic_compression_impl.cpp @@ -20,7 +20,8 @@ void ofh_uplane_message_builder_dynamic_compression_impl::serialize_compression_ { // Serialize compression header. uint8_t value = 0U; - value |= uint8_t(params.data_width) << 4U; + // Note that an IQ bitwidth of 16 bits translates to a value of 0. + value |= uint8_t(params.data_width == 16 ? 0 : params.data_width) << 4U; value |= uint8_t(to_value(params.type)); serializer.write(value); diff --git a/tests/unittests/ofh/serdes/ofh_cplane_packet_builder_dynamic_compression_impl_test.cpp b/tests/unittests/ofh/serdes/ofh_cplane_packet_builder_dynamic_compression_impl_test.cpp index 8aa5589d14..3f81c902f4 100644 --- a/tests/unittests/ofh/serdes/ofh_cplane_packet_builder_dynamic_compression_impl_test.cpp +++ b/tests/unittests/ofh/serdes/ofh_cplane_packet_builder_dynamic_compression_impl_test.cpp @@ -48,7 +48,7 @@ TEST(ofh_control_plane_packet_builder_dynamic_compression_impl_test, downlink_pa ASSERT_EQ(0, result_packet[UD_COMP_HEADER_BYTE]); } -TEST(ofh_control_plane_packet_builder_dynamic_compression_impl_test, uplink_packet_codifies_ud_comp_header) +TEST(ofh_control_plane_packet_builder_dynamic_compression_impl_test, uplink_packet_codifies_ud_comp_header_bfp9) { std::vector packet = { 0x10, 0x00, 0x00, 0x00, 0x01, 0x01, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00}; @@ -76,7 +76,41 @@ TEST(ofh_control_plane_packet_builder_dynamic_compression_impl_test, uplink_pack ASSERT_EQ(packet, result_packet); ASSERT_EQ(nof_bytes, packet.size()); - // Check that the udCompHdr is 0. + // Check that the udCompHdr is serialised. ASSERT_EQ(packet_params.compr_params.data_width, result_packet[UD_COMP_HEADER_BYTE] >> 4); ASSERT_EQ(packet_params.compr_params.type, to_compression_type(result_packet[UD_COMP_HEADER_BYTE] & 0xf)); } + +TEST(ofh_control_plane_packet_builder_dynamic_compression_impl_test, uplink_packet_codifies_ud_comp_header_nocompr16) +{ + std::vector packet = { + 0x10, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00}; + + std::vector result_packet(packet.size(), 0); + + cplane_section_type1_parameters packet_params; + cplane_radio_application_header& header = packet_params.radio_hdr; + header.direction = data_direction::uplink; + header.filter_index = filter_index_type::standard_channel_filter; + header.slot = slot_point(0, 0, 0); + header.start_symbol = 0; + + cplane_common_section_0_1_3_5_fields& section = packet_params.section_fields.common_fields; + section.section_id = 0; + section.prb_start = 0; + section.nof_prb = 0; + section.re_mask = 0xfff; + section.nof_symbols = 14; + packet_params.compr_params = {compression_type::none, 16}; + + cplane_message_builder_dynamic_compression_impl builder; + + unsigned nof_bytes = builder.build_dl_ul_radio_channel_message(result_packet, packet_params); + + ASSERT_EQ(packet, result_packet); + ASSERT_EQ(nof_bytes, packet.size()); + // Check that the udCompHdr is serialised. + // 0 is used to encode a bitwidth of 16 bits. + ASSERT_EQ(0, result_packet[UD_COMP_HEADER_BYTE] >> 4); + ASSERT_EQ(packet_params.compr_params.type, to_compression_type(result_packet[UD_COMP_HEADER_BYTE] & 0xf)); +} From cb514d25918bd148e37360d7a9894884ee6f7660 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Tue, 6 Aug 2024 11:45:15 +0200 Subject: [PATCH 107/407] ci: update retina version, enable uesim --- .gitlab/ci/e2e.yml | 34 +++++++++++++++++----------------- .gitlab/ci/e2e/.env | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 37289a8f51..31398437e2 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -444,23 +444,23 @@ cudu amari 32UE: matrix: - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] -# uesim 32UE beta: -# stage: zmq -# extends: .e2e-run -# variables: -# GROUP: uesim -# TESTBED: zmq_uesim -# MARKERS: "zmq and not smoke" -# KEYWORDS: ping -# E2E_LOG_LEVEL: "info" -# RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" -# needs: -# - job: "basic relwithdeb" -# artifacts: true -# - job: "build uesim zmq driver" -# artifacts: true -# - *retina-needs -# allow_failure: true +uesim 32UE beta: + stage: zmq + extends: .e2e-run + variables: + GROUP: uesim + TESTBED: zmq_uesim + MARKERS: "zmq and not smoke" + KEYWORDS: ping + E2E_LOG_LEVEL: "info" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + needs: + - job: "basic relwithdeb" + artifacts: true + - job: "build uesim zmq driver" + artifacts: true + - *retina-needs + allow_failure: true ################################################################################ # TEST MODE diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index dc1fd8c2f5..6167f4248c 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.1 +RETINA_VERSION=0.52.2 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From 599eb26f92c4ee7966434166d4e3a30b0704e307 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 6 Aug 2024 14:44:12 +0200 Subject: [PATCH 108/407] phy: fix compilation for SSE phy: fix compilation for AVX2 without FMA --- lib/srsvec/simd.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index afbe05f9ab..19f2f12b4c 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -417,19 +417,15 @@ inline simd_f_t srsran_simd_f_fma(simd_f_t acc, simd_f_t a, simd_f_t b) { #ifdef __AVX512F__ return _mm512_fmadd_ps(a, b, acc); -#else /* __AVX512F__ */ -#ifdef __AVX2__ +#elif defined(__FMA__) return _mm256_fmadd_ps(a, b, acc); -#else /* __AVX2__ */ -#ifdef __SSE4_1__ - return _mm_fmadd_ps(a, b, acc); -#else /* __SSE4_1__ */ -#ifdef __ARM_NEON +#elif defined(__AVX2__) + return _mm256_add_ps(_mm256_mul_ps(a, b), acc); +#elif defined(__SSE4_1__) + return _mm_add_ps(_mm_mul_ps(a, b), acc); +#elif defined(__ARM_NEON) return vmlaq_f32(acc, a, b); -#endif /* __ARM_NEON */ -#endif /* __SSE4_1__ */ -#endif /* __AVX2__ */ -#endif /* __AVX512F__ */ +#endif } inline simd_f_t srsran_simd_f_zero() From d427e75093aa54c3a565ee362db7130f57b38195 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 6 Aug 2024 15:06:35 +0200 Subject: [PATCH 109/407] phy: instanciate PUCCH detector only once in vectortest --- .../pucch_detector_test.cpp | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/tests/unittests/phy/upper/channel_processors/pucch_detector_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch_detector_test.cpp index 810f522819..e3a0070494 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch_detector_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch_detector_test.cpp @@ -47,40 +47,36 @@ class PUCCHDetectFixture : public ::testing::TestWithParam protected: static void SetUpTestSuite() { - if (!detector_factory) { + if (!detector_test) { std::shared_ptr low_papr_gen = create_low_papr_sequence_generator_sw_factory(); std::shared_ptr low_papr_col = create_low_papr_sequence_collection_sw_factory(low_papr_gen); std::shared_ptr pseudorandom = create_pseudo_random_generator_sw_factory(); std::shared_ptr equalizer = create_channel_equalizer_generic_factory(); - detector_factory = create_pucch_detector_factory_sw(low_papr_col, pseudorandom, equalizer); + std::shared_ptr detector_factory = + create_pucch_detector_factory_sw(low_papr_col, pseudorandom, equalizer); + report_fatal_error_if_not(detector_factory, "Failed to create factory."); + + detector_test = detector_factory->create(); + report_fatal_error_if_not(detector_test, "Failed to create detector."); + ASSERT_NE(detector_test, nullptr); + + channel_estimate::channel_estimate_dimensions ch_dims; + ch_dims.nof_tx_layers = 1; + ch_dims.nof_rx_ports = MAX_PORTS; + ch_dims.nof_symbols = MAX_NSYMB_PER_SLOT; + ch_dims.nof_prb = MAX_RB; + csi.resize(ch_dims); } - ASSERT_NE(detector_factory, nullptr); } - void SetUp() override - { - // Assert factories again for compatibility with GTest < 1.11. - ASSERT_NE(detector_factory, nullptr); - - detector_test = detector_factory->create(); - ASSERT_NE(detector_test, nullptr); - - channel_estimate::channel_estimate_dimensions ch_dims; - ch_dims.nof_tx_layers = 1; - ch_dims.nof_rx_ports = MAX_PORTS; - ch_dims.nof_symbols = MAX_NSYMB_PER_SLOT; - ch_dims.nof_prb = MAX_RB; - csi.resize(ch_dims); - } - - static std::shared_ptr detector_factory; - std::unique_ptr detector_test; - channel_estimate csi; + static std::unique_ptr detector_test; + static channel_estimate csi; }; -std::shared_ptr PUCCHDetectFixture::detector_factory = nullptr; +std::unique_ptr PUCCHDetectFixture::detector_test = nullptr; +channel_estimate PUCCHDetectFixture::csi; void fill_ch_estimate(channel_estimate& ch_est, const std::vector& entries) { From 228f187eb28d877e9a6d0d1491b740c5e810b9c4 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 16:51:18 +0200 Subject: [PATCH 110/407] ADT: Remove uses of ADT/detail in user code as they should be used by ADT classes --- include/srsran/adt/blocking_queue.h | 9 ++------- .../adt/{detail/operations.h => noop_functor.h} | 8 ++------ include/srsran/adt/ring_buffer.h | 3 +-- include/srsran/phy/upper/re_measurement.h | 1 - lib/scheduler/config/sched_config_manager.h | 12 ++++++------ 5 files changed, 11 insertions(+), 22 deletions(-) rename include/srsran/adt/{detail/operations.h => noop_functor.h} (61%) diff --git a/include/srsran/adt/blocking_queue.h b/include/srsran/adt/blocking_queue.h index f5a06120a0..a3947ddd0c 100644 --- a/include/srsran/adt/blocking_queue.h +++ b/include/srsran/adt/blocking_queue.h @@ -445,9 +445,7 @@ class base_blocking_queue /// \tparam T value type stored by buffer /// \tparam PushingCallback function void(const T&) called while pushing an element to the queue /// \tparam PoppingCallback function void(const T&) called while popping an element from the queue -template +template class blocking_queue : public detail::base_blocking_queue, PushingCallback, PoppingCallback> { using super_type = detail::base_blocking_queue, PushingCallback, PoppingCallback>; @@ -468,10 +466,7 @@ class blocking_queue : public detail::base_blocking_queue, /// \tparam N size of queue /// \tparam PushingCallback function void(const T&) called while pushing an element to the queue /// \tparam PoppingCallback function void(const T&) called while popping an element from the queue -template +template class static_blocking_queue : public detail::base_blocking_queue, PushingCallback, PoppingCallback> { diff --git a/include/srsran/adt/detail/operations.h b/include/srsran/adt/noop_functor.h similarity index 61% rename from include/srsran/adt/detail/operations.h rename to include/srsran/adt/noop_functor.h index b1552d67b1..14fefd626a 100644 --- a/include/srsran/adt/detail/operations.h +++ b/include/srsran/adt/noop_functor.h @@ -3,17 +3,13 @@ namespace srsran { -namespace detail { - -// Do nothing operation functor. +/// Do nothing operation functor. struct noop_operation { template void operator()(T&& t) const { - // do nothing + // Do nothing. } }; -} // namespace detail - } // namespace srsran diff --git a/include/srsran/adt/ring_buffer.h b/include/srsran/adt/ring_buffer.h index 7d927123ed..c821520080 100644 --- a/include/srsran/adt/ring_buffer.h +++ b/include/srsran/adt/ring_buffer.h @@ -10,12 +10,11 @@ #pragma once -#include "srsran/adt/detail/operations.h" #include "srsran/adt/detail/type_storage.h" #include "srsran/adt/expected.h" +#include "srsran/adt/noop_functor.h" #include "srsran/adt/span.h" #include "srsran/support/srsran_assert.h" - #include #include #include diff --git a/include/srsran/phy/upper/re_measurement.h b/include/srsran/phy/upper/re_measurement.h index 968e4c8655..9cc2f260ad 100644 --- a/include/srsran/phy/upper/re_measurement.h +++ b/include/srsran/phy/upper/re_measurement.h @@ -13,7 +13,6 @@ #pragma once -#include "srsran/adt/detail/type_storage.h" #include "srsran/adt/tensor.h" #include "srsran/srsvec/copy.h" diff --git a/lib/scheduler/config/sched_config_manager.h b/lib/scheduler/config/sched_config_manager.h index 2c7ada9166..e9015953f0 100644 --- a/lib/scheduler/config/sched_config_manager.h +++ b/lib/scheduler/config/sched_config_manager.h @@ -11,7 +11,7 @@ #pragma once #include "ue_configuration.h" -#include "srsran/adt/detail/operations.h" +#include "srsran/adt/noop_functor.h" #include "srsran/scheduler/config/scheduler_config.h" #include "srsran/srslog/logger.h" @@ -44,9 +44,9 @@ class ue_config_update_event private: du_ue_index_t ue_index = INVALID_DU_UE_INDEX; // We use a unique_ptr with no deleter to automatically set the ptr to null on move. - std::unique_ptr parent; - std::unique_ptr next_ded_cfg; - std::optional set_fallback_mode; + std::unique_ptr parent; + std::unique_ptr next_ded_cfg; + std::optional set_fallback_mode; }; /// Event to delete a UE in the scheduler. @@ -66,8 +66,8 @@ class ue_config_delete_event du_ue_index_t ue_index() const { return ue_idx; } private: - du_ue_index_t ue_idx = INVALID_DU_UE_INDEX; - std::unique_ptr parent; + du_ue_index_t ue_idx = INVALID_DU_UE_INDEX; + std::unique_ptr parent; }; /// \brief Internal scheduler interface to create/update/delete UEs. From 1e864961c92320030d77f0bdf8394146e0b8f8f9 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 5 Aug 2024 14:55:29 +0200 Subject: [PATCH 111/407] du-high: make du-high run_slot parallel across cells --- .../du_high/test_utils/du_high_env_simulator.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 23be3d0f86..52e8a80220 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -419,12 +419,14 @@ bool du_high_env_simulator::run_ue_context_setup(rnti_t rnti) void du_high_env_simulator::run_slot() { + // Dispatch a slot indication to all cells in the L2 (fork work across cells). for (unsigned i = 0; i != du_high_cfg.cells.size(); ++i) { - // Dispatch a slot indication to each cell in the L2. du_hi->get_slot_handler(to_du_cell_index(i)).handle_slot_indication(next_slot); + } - // Wait for slot indication to be processed and the l2 results to be sent back to the l1 (in this case, the test - // main thread). + // Wait for slot indication to be processed and the l2 results to be sent back to the l1 (join cell results, in this + // case, with the join point being the test main thread). + for (unsigned i = 0; i != du_high_cfg.cells.size(); ++i) { const unsigned MAX_COUNT = 100000; for (unsigned count = 0; count < MAX_COUNT and phy.cells[i].last_slot_res != next_slot; ++count) { // Process tasks dispatched to the test main thread (e.g. L2 slot result) @@ -439,7 +441,7 @@ void du_high_env_simulator::run_slot() phy.cells[i].last_slot_res); const std::optional& dl_result = phy.cells[i].last_dl_res; if (dl_result.has_value()) { - EXPECT_TRUE(dl_result->slot == next_slot); + EXPECT_EQ(dl_result->slot, next_slot); } // Process results. From 217f79a73dd58d92fa05da55a426381169771ca1 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Wed, 7 Aug 2024 09:49:07 +0200 Subject: [PATCH 112/407] ci: increase timeout --- .gitlab/ci/e2e.yml | 1 + .gitlab/ci/e2e/.env | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 31398437e2..6b6acd3782 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -447,6 +447,7 @@ cudu amari 32UE: uesim 32UE beta: stage: zmq extends: .e2e-run + timeout: 8h variables: GROUP: uesim TESTBED: zmq_uesim diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 6167f4248c..07f8b90df0 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.2 +RETINA_VERSION=0.52.3 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From d8a1ec9ce282df076ed1dfd213c09affed22f2d8 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 5 Aug 2024 15:23:52 +0200 Subject: [PATCH 113/407] du,f1ap: add nullpointer checks to prevent segfaults --- lib/du_high/adapters/f1ap_test_mode_adapter.cpp | 3 +++ lib/f1ap/gateways/f1c_local_connector_factory.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/du_high/adapters/f1ap_test_mode_adapter.cpp b/lib/du_high/adapters/f1ap_test_mode_adapter.cpp index 5b12aa4a40..321bc20652 100644 --- a/lib/du_high/adapters/f1ap_test_mode_adapter.cpp +++ b/lib/du_high/adapters/f1ap_test_mode_adapter.cpp @@ -221,6 +221,9 @@ f1ap_test_mode_adapter::handle_du_connection_request(std::unique_ptr(*this, std::move(du_rx_pdu_notifier))); + if (tx_notifier == nullptr) { + return nullptr; + } return std::make_unique(*this); } diff --git a/lib/f1ap/gateways/f1c_local_connector_factory.cpp b/lib/f1ap/gateways/f1c_local_connector_factory.cpp index e773662a22..b8b4785597 100644 --- a/lib/f1ap/gateways/f1c_local_connector_factory.cpp +++ b/lib/f1ap/gateways/f1c_local_connector_factory.cpp @@ -75,6 +75,9 @@ class f1c_local_connector_impl final : public f1c_local_connector // Create direct connection between CU-CP and DU notifier. auto cu_notifier = cu_cp_du_mng->handle_new_du_connection(std::move(du_notifier)); + if (cu_notifier == nullptr) { + return nullptr; + } // Decorate CU-CP RX notifier with pcap writing. if (pcap_writer.is_write_enabled()) { From 823b923419eb9f68ea261b1a83d3db2015f3e3f0 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:02:33 +0200 Subject: [PATCH 114/407] cu_cp: refactor ue context release test --- .../cu_cp/cu_cp_ue_context_release_test.cpp | 158 +++++++++++------- 1 file changed, 94 insertions(+), 64 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp b/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp index ad41b6a6da..25c1fcb4e7 100644 --- a/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_ue_context_release_test.cpp @@ -47,118 +47,148 @@ class cu_cp_ue_context_release_test : public cu_cp_test_environment, public ::te EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); } - void attach_ue() + [[nodiscard]] bool attach_ue() { // Connect UE 0x4601. - EXPECT_TRUE(connect_new_ue(du_idx, du_ue_id, crnti)); - EXPECT_TRUE(authenticate_ue(du_idx, du_ue_id, amf_ue_id)); - EXPECT_TRUE(setup_ue_security(du_idx, du_ue_id)); + if (!connect_new_ue(du_idx, du_ue_id, crnti)) { + return false; + } + if (!authenticate_ue(du_idx, du_ue_id, amf_ue_id)) { + return false; + } + if (!setup_ue_security(du_idx, du_ue_id)) { + return false; + } ue_ctx = this->find_ue_context(du_idx, du_ue_id); - - EXPECT_TRUE(finish_ue_registration(du_idx, cu_up_idx, du_ue_id)); - - EXPECT_NE(ue_ctx, nullptr); + if (!finish_ue_registration(du_idx, cu_up_idx, du_ue_id)) { + return false; + } + return ue_ctx != nullptr; } - void setup_ue_pdu_session() + [[nodiscard]] bool setup_ue_pdu_session() { - attach_ue(); - EXPECT_TRUE(request_pdu_session_resource_setup(du_idx, cu_up_idx, du_ue_id)); - EXPECT_TRUE(setup_pdu_session(du_idx, cu_up_idx, du_ue_id, crnti, cu_up_e1ap_id)); + if (!attach_ue()) { + return false; + } + if (!request_pdu_session_resource_setup(du_idx, cu_up_idx, du_ue_id)) { + return false; + } + if (!setup_pdu_session(du_idx, cu_up_idx, du_ue_id, crnti, cu_up_e1ap_id)) { + return false; + } + return true; } - void send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command() + [[nodiscard]] bool send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject NGAP UE Context Release Command and wait for F1AP UE Context Release Command get_amf().push_tx_pdu(generate_valid_ue_context_release_command_with_amf_ue_ngap_id(ue_ctx->amf_ue_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Release Command"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), "Invalid UE Context Release Command"); + return true; } - void send_ngap_ue_context_release_command_and_await_bearer_context_release_command() + [[nodiscard]] bool send_ngap_ue_context_release_command_and_await_bearer_context_release_command() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject NGAP UE Context Release Command and wait for Bearer Context Release Command get_amf().push_tx_pdu(generate_valid_ue_context_release_command_with_amf_ue_ngap_id(ue_ctx->amf_ue_id.value())); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Release Command"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Release Command"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_release_command(e1ap_pdu), "Invalid Bearer Context Release Command"); + return true; } - void send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command() + [[nodiscard]] bool send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command() { // Inject Bearer Context Release Complete and wait for F1AP UE Context Release Command get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_release_complete(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Release Command"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), "Invalid UE Context Release Command"); + return true; } - void send_f1ap_ue_context_release_complete(gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) + [[nodiscard]] bool send_f1ap_ue_context_release_complete(gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) { // Inject F1AP UE Context Release Complete get_du(du_idx).push_ul_pdu(test_helpers::generate_ue_context_release_complete(cu_ue_id_, du_ue_id_)); + return true; } - void send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete() + [[nodiscard]] bool send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete() { // Inject F1AP UE Context Release Complete and wait for N1AP UE Context Release Command - send_f1ap_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value()); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Complete"); + if (!send_f1ap_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive UE Context Release Complete"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_complete(ngap_pdu), "Invalid UE Context Release Complete"); + return true; } - void send_pdu_session_resource_setup_request() + [[nodiscard]] bool send_pdu_session_resource_setup_request() { // Inject PDU Session Resource Setup Request get_amf().push_tx_pdu(generate_valid_pdu_session_resource_setup_request_message( ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{uint_to_pdu_session_id(1), {{uint_to_qos_flow_id(1), 9}}}})); + return true; } - void await_error_indication() + [[nodiscard]] bool await_error_indication() { - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Error Indication"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Error Indication"); report_fatal_error_if_not(test_helpers::is_valid_error_indication(ngap_pdu), "Invalid Error Indication"); + return true; } - void send_f1ap_ue_context_release_request(gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) + [[nodiscard]] bool send_f1ap_ue_context_release_request(gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) { // Inject F1AP UE Context Release Request get_du(du_idx).push_ul_pdu(test_helpers::generate_ue_context_release_request(cu_ue_id_, du_ue_id_)); + return true; } - void send_f1ap_ue_context_release_request_and_await_ngap_ue_context_release_request() + [[nodiscard]] bool send_f1ap_ue_context_release_request_and_await_ngap_ue_context_release_request() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject F1AP UE Context Release Request and wait for NGAP UE Context Release Request - send_f1ap_ue_context_release_request(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value()); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive NGAP UE Context Release Request"); + if (!send_f1ap_ue_context_release_request(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive NGAP UE Context Release Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), "Invalid NGAP UE Context Release Request"); + return true; } unsigned du_idx = 0; @@ -180,13 +210,13 @@ TEST_F(cu_cp_ue_context_release_test, when_ue_context_release_command_but_no_pdu_session_setup_received_then_release_succeeds) { // Attach UE - attach_ue(); + ASSERT_TRUE(attach_ue()); // Inject NGAP UE Context Release Command and await F1AP UE Context Release Command - send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command(); + ASSERT_TRUE(send_ngap_ue_context_release_command_and_await_f1ap_ue_context_release_command()); // Inject F1AP UE Context Release Complete and await NGAP UE Context Release Complete - send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete(); + ASSERT_TRUE(send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete()); // STATUS: UE should be removed at this stage auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); @@ -197,41 +227,41 @@ TEST_F(cu_cp_ue_context_release_test, when_pdu_session_resource_setup_request_is_received_during_release_then_error_indication_is_sent) { // Setup PDU Session - setup_ue_pdu_session(); + ASSERT_TRUE(setup_ue_pdu_session()); // Inject NGAP UE Context Release Command and await Bearer Context Release Command - send_ngap_ue_context_release_command_and_await_bearer_context_release_command(); + ASSERT_TRUE(send_ngap_ue_context_release_command_and_await_bearer_context_release_command()); // Inject Bearer Context Release Complete and await F1AP UE Context Release Command - send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command(); + ASSERT_TRUE(send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command()); // Inject PDU Session Resource Setup Request - send_pdu_session_resource_setup_request(); + ASSERT_TRUE(send_pdu_session_resource_setup_request()); // Inject F1AP UE Context Release Complete and await NGAP UE Context Release Complete - send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete(); + ASSERT_TRUE(send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete()); // STATUS: UE should be removed at this stage auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); ASSERT_EQ(report.ues.size(), 0) << "UE should be removed"; // STATUS: An error indication should be sent to the AMF - await_error_indication(); + ASSERT_TRUE(await_error_indication()); } TEST_F(cu_cp_ue_context_release_test, when_ue_context_release_command_received_then_release_succeeds) { // Setup PDU Session - setup_ue_pdu_session(); + ASSERT_TRUE(setup_ue_pdu_session()); // Inject NGAP UE Context Release Command and await Bearer Context Release Command - send_ngap_ue_context_release_command_and_await_bearer_context_release_command(); + ASSERT_TRUE(send_ngap_ue_context_release_command_and_await_bearer_context_release_command()); // Inject Bearer Context Release Complete and await F1AP UE Context Release Command - send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command(); + ASSERT_TRUE(send_bearer_context_release_complete_and_await_f1ap_ue_context_release_command()); // Inject F1AP UE Context Release Complete and await NGAP UE Context Release Complete - send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete(); + ASSERT_TRUE(send_f1ap_ue_context_release_complete_and_await_ngap_ue_context_release_complete()); // STATUS: UE should be removed at this stage auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); @@ -242,10 +272,10 @@ TEST_F(cu_cp_ue_context_release_test, when_du_initiated_ue_context_release_received_then_ue_context_release_request_is_sent) { // Setup PDU Session - setup_ue_pdu_session(); + ASSERT_TRUE(setup_ue_pdu_session()); // Inject F1AP UE Context Release Request and await NGAP UE Context Release Request - send_f1ap_ue_context_release_request_and_await_ngap_ue_context_release_request(); + ASSERT_TRUE(send_f1ap_ue_context_release_request_and_await_ngap_ue_context_release_request()); } TEST_F( @@ -285,13 +315,13 @@ TEST_F( } // Inject F1AP UE Context Release Request - send_f1ap_ue_context_release_request(cu_ue_id, du_ue_id); + ASSERT_TRUE(send_f1ap_ue_context_release_request(cu_ue_id, du_ue_id)); // No NGAP UE Context Release Request should be sent to the AMF ASSERT_NE(ngap_pdu.pdu.type().value, asn1::ngap::ngap_pdu_c::types_opts::init_msg); // Inject F1AP UE Context Release Complete - send_f1ap_ue_context_release_complete(cu_ue_id, du_ue_id); + ASSERT_TRUE(send_f1ap_ue_context_release_complete(cu_ue_id, du_ue_id)); // STATUS: UE should be removed at this stage auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); From 8776c0a8dca077ba77b5bf451700155e4d292219 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:05:54 +0200 Subject: [PATCH 115/407] cu_cp: refactor cu-cp handover test --- tests/unittests/cu_cp/cu_cp_handover_test.cpp | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_handover_test.cpp index 7d863f8375..49e93c82b5 100644 --- a/tests/unittests/cu_cp/cu_cp_handover_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_handover_test.cpp @@ -12,6 +12,7 @@ #include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "tests/unittests/ngap/ngap_test_messages.h" @@ -47,63 +48,68 @@ class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Tes EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); } - void send_handover_request_and_await_bearer_context_setup_request() + [[nodiscard]] bool send_handover_request_and_await_bearer_context_setup_request() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject Handover Request and wait for Bearer Context Setup Request get_amf().push_tx_pdu(generate_valid_handover_request(amf_ue_id)); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Setup Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Setup Request"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_setup_request(e1ap_pdu), "Invalid Bearer Context Setup Request"); cu_cp_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(e1ap_pdu.pdu.init_msg().value.bearer_context_setup_request()->gnb_cu_cp_ue_e1ap_id); + return true; } - void send_bearer_context_setup_response_and_await_ue_context_setup_request() + [[nodiscard]] bool send_bearer_context_setup_response_and_await_ue_context_setup_request() { // Inject Bearer Context Setup Response and wait for UE Context Setup Request get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_setup_response(cu_cp_e1ap_id, cu_up_e1ap_id)); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Setup Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Setup Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_setup_request(f1ap_pdu), "Invalid UE Context Setup Request"); cu_ue_id = int_to_gnb_cu_ue_f1ap_id(f1ap_pdu.pdu.init_msg().value.ue_context_setup_request()->gnb_cu_ue_f1ap_id); + return true; } - void send_ue_context_setup_response_and_await_bearer_context_modification_request() + [[nodiscard]] bool send_ue_context_setup_response_and_await_bearer_context_modification_request() { // Inject UE Context Setup Response and wait for Bearer Context Modification Request get_du(du_idx).push_ul_pdu(generate_ue_context_setup_response(cu_ue_id, du_ue_id, crnti)); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), "Invalid Bearer Context Modification Request"); + return true; } - void send_bearer_context_modification_response_and_await_handover_request_ack() + [[nodiscard]] bool send_bearer_context_modification_response_and_await_handover_request_ack() { // Inject Bearer Context Modification Response and wait for Handover Request Ack get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Handover Request Ack"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Handover Request Ack"); report_fatal_error_if_not(test_helpers::is_valid_handover_request_ack(ngap_pdu), "Invalid Handover Request Ack"); + return true; } - void send_rrc_reconfiguration_complete_and_await_handover_notify() + [[nodiscard]] bool send_rrc_reconfiguration_complete_and_await_handover_notify() { // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for Handover Notify get_du(du_idx).push_ul_pdu(generate_ul_rrc_message_transfer( cu_ue_id, du_ue_id, srb_id_t::srb1, make_byte_buffer("800008004e17dae3").value())); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Handover Notify"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Handover Notify"); report_fatal_error_if_not(test_helpers::is_valid_handover_notify(ngap_pdu), "Invalid Handover Notify"); + return true; } unsigned du_idx = 0; @@ -125,17 +131,17 @@ class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Tes TEST_F(cu_cp_handover_test, when_handover_request_received_then_handover_notify_is_sent) { // Inject Handover Request and await Bearer Context Setup Request - send_handover_request_and_await_bearer_context_setup_request(); + ASSERT_TRUE(send_handover_request_and_await_bearer_context_setup_request()); // Inject Bearer Context Setup Response and await UE Context Setup Request - send_bearer_context_setup_response_and_await_ue_context_setup_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_setup_request()); // Inject UE Context Setup Response and await Bearer Context Modification Request - send_ue_context_setup_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_setup_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await Handover Request Ack - send_bearer_context_modification_response_and_await_handover_request_ack(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_handover_request_ack()); // Inject RRC Reconfiguration Complete and await Handover Notify - send_rrc_reconfiguration_complete_and_await_handover_notify(); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_handover_notify()); } From c626e25a478e46443004f5c3a25bbff609f6b262 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:16:14 +0200 Subject: [PATCH 116/407] cu_cp: refactor inactivity notification test --- .../cu_cp_inactivity_notification_test.cpp | 110 ++++++++++-------- 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp b/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp index b843f51f6e..1deabb3511 100644 --- a/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_inactivity_notification_test.cpp @@ -45,77 +45,91 @@ class cu_cp_inactivity_notification_test : public cu_cp_test_environment, public EXPECT_NE(ue_ctx, nullptr); } - void setup_pdu_session(pdu_session_id_t psi_, - drb_id_t drb_id_, - qos_flow_id_t qfi_, - byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), - bool is_initial_session_ = true) + [[nodiscard]] bool + setup_pdu_session(pdu_session_id_t psi_, + drb_id_t drb_id_, + qos_flow_id_t qfi_, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), + bool is_initial_session_ = true) { - EXPECT_TRUE(cu_cp_test_environment::setup_pdu_session(du_idx, - cu_up_idx, - du_ue_id, - crnti, - cu_up_e1ap_id, - psi_, - drb_id_, - qfi_, - std::move(rrc_reconfiguration_complete), - is_initial_session_)); + return cu_cp_test_environment::setup_pdu_session(du_idx, + cu_up_idx, + du_ue_id, + crnti, + cu_up_e1ap_id, + psi_, + drb_id_, + qfi_, + std::move(rrc_reconfiguration_complete), + is_initial_session_); } - void send_bearer_context_inactivity_notification(const e1ap_message& inactivity_notification) + [[nodiscard]] bool send_bearer_context_inactivity_notification(const e1ap_message& inactivity_notification) { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject inactivity notification get_cu_up(cu_up_idx).push_tx_pdu(inactivity_notification); + return true; } - void send_ue_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() + [[nodiscard]] bool send_ue_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject inactivity notification and wait for UE Context Release Request - send_bearer_context_inactivity_notification( - generate_bearer_context_inactivity_notification_with_ue_level(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + if (!send_bearer_context_inactivity_notification(generate_bearer_context_inactivity_notification_with_ue_level( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id))) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive UE Context Release Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), "Invalid UE Context Release Request"); + return true; } - void send_drb_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() + [[nodiscard]] bool send_drb_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject inactivity notification and wait for UE Context Release Request - send_bearer_context_inactivity_notification(generate_bearer_context_inactivity_notification_with_drb_level( - ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {drb_id_t::drb1})); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + if (!send_bearer_context_inactivity_notification(generate_bearer_context_inactivity_notification_with_drb_level( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {drb_id_t::drb1}))) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive UE Context Release Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), "Invalid UE Context Release Request"); + return true; } - void send_pdu_session_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() + [[nodiscard]] bool + send_pdu_session_level_bearer_context_inactivity_notification_and_await_ue_context_release_request() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject inactivity notification and wait for UE Context Release Request - send_bearer_context_inactivity_notification(generate_bearer_context_inactivity_notification_with_pdu_session_level( - ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {psi})); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + if (!send_bearer_context_inactivity_notification( + generate_bearer_context_inactivity_notification_with_pdu_session_level( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {psi}))) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive UE Context Release Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), "Invalid UE Context Release Request"); + return true; } unsigned du_idx = 0; @@ -141,12 +155,12 @@ TEST_F(cu_cp_inactivity_notification_test, when_unsupported_inactivity_message_received_then_ue_context_release_request_is_not_sent) { // Setup second PDU session - setup_pdu_session(psi2, drb_id_t::drb2, qfi2, generate_rrc_reconfiguration_complete_pdu(0, 8), false); + ASSERT_TRUE(setup_pdu_session(psi2, drb_id_t::drb2, qfi2, generate_rrc_reconfiguration_complete_pdu(0, 8), false)); // Inject unsupported Inactivity Notification e1ap_message inactivity_notification = generate_bearer_context_inactivity_notification_with_drb_level( ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {drb_id_t::drb1}, {drb_id_t::drb2}); - send_bearer_context_inactivity_notification(inactivity_notification); + ASSERT_TRUE(send_bearer_context_inactivity_notification(inactivity_notification)); // check that the UE Context Release Request was not sent to the AMF srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), @@ -157,14 +171,14 @@ TEST_F(cu_cp_inactivity_notification_test, when_ue_level_inactivity_message_received_then_ue_context_release_request_is_sent) { // Inject Inactivity Notification and await UE Context Release Request - send_ue_level_bearer_context_inactivity_notification_and_await_ue_context_release_request(); + ASSERT_TRUE(send_ue_level_bearer_context_inactivity_notification_and_await_ue_context_release_request()); } TEST_F(cu_cp_inactivity_notification_test, when_drb_level_inactivity_message_with_inactivity_for_all_drbs_received_then_ue_context_release_request_is_sent) { // Inject Inactivity Notification and await UE Context Release Request - send_drb_level_bearer_context_inactivity_notification_and_await_ue_context_release_request(); + ASSERT_TRUE(send_drb_level_bearer_context_inactivity_notification_and_await_ue_context_release_request()); } TEST_F( @@ -172,5 +186,5 @@ TEST_F( when_pdu_session_level_inactivity_message_with_inactivity_for_all_drbs_received_then_ue_context_release_request_is_sent) { // Inject Inactivity Notification and await UE Context Release Request - send_pdu_session_level_bearer_context_inactivity_notification_and_await_ue_context_release_request(); + ASSERT_TRUE(send_pdu_session_level_bearer_context_inactivity_notification_and_await_ue_context_release_request()); } From 0218f854d82da0f73d07fad98e50e824c16780f7 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:24:51 +0200 Subject: [PATCH 117/407] cu_cp: refactor initial context setup test --- .../cu_cp_initial_context_setup_test.cpp | 132 +++++++++--------- 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp index f0027f9593..383aa6ad3a 100644 --- a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp @@ -55,10 +55,13 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : EXPECT_NE(ue_ctx, nullptr); } - void send_initial_context_setup_request(bool with_pdu_sessions = false, bool with_ue_capabilities = false) + [[nodiscard]] bool send_initial_context_setup_request(bool with_pdu_sessions = false, + bool with_ue_capabilities = false) { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); // Inject NGAP Initial Context Setup Request ngap_message init_ctxt_setup_req; @@ -78,13 +81,13 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : } get_amf().push_tx_pdu(init_ctxt_setup_req); + return true; } - void send_ue_context_setup_request_and_await_response() + [[nodiscard]] bool send_ue_context_setup_request_and_await_response() { // Wait for F1AP UE Context Setup Request (containing Security Mode Command). - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Security Mode Command"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), "Failed to receive Security Mode Command"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_setup_request(f1ap_pdu), "Invalid UE Context Setup Request"); const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); @@ -95,9 +98,10 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : // Inject UE Context Setup Response f1ap_message ue_ctxt_setup_response = generate_ue_context_setup_response(ue_ctx->cu_ue_id.value(), du_ue_id); get_du(du_idx).push_ul_pdu(ue_ctxt_setup_response); + return true; } - void send_security_mode_complete_and_await_ue_capability_enquiry() + [[nodiscard]] bool send_security_mode_complete_and_await_ue_capability_enquiry() { // Inject Security Mode Complete f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( @@ -105,17 +109,17 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); // Wait for UE Capability Enquiry - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Capability Enquiry"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), "Failed to receive UE Capability Enquiry"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); report_fatal_error_if_not( test_helpers::is_valid_rrc_ue_capability_enquiry(test_helpers::extract_dl_dcch_msg(rrc_container)), "Invalid UE Capability Enquiry"); + return true; } - void send_ue_capability_info_and_await_registration_accept_and_initial_context_setup_response() + [[nodiscard]] bool send_ue_capability_info_and_await_registration_accept_and_initial_context_setup_response() { // Inject UL RRC Message Transfer (containing UE Capability Info) get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( @@ -129,19 +133,19 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : .value())); // Wait for DL RRC Message Transfer (containing NAS Registration Accept) - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive DL RRC Message, containing NAS Registration Accept"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive DL RRC Message, containing NAS Registration Accept"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); // Wait for Initial Context Setup Response - result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Initial Context Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Initial Context Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_initial_context_setup_response(ngap_pdu), "Invalid init ctxt setup"); + return true; } - void send_security_mode_complete_and_await_registration_accept_and_initial_context_setup_response() + [[nodiscard]] bool send_security_mode_complete_and_await_registration_accept_and_initial_context_setup_response() { // Inject Security Mode Complete f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( @@ -149,19 +153,19 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); // Wait for DL RRC Message Transfer (containing NAS Registration Accept) - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive DL RRC Message, containing NAS Registration Accept"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive DL RRC Message, containing NAS Registration Accept"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); // Wait for Initial Context Setup Response - result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Initial Context Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Initial Context Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_initial_context_setup_response(ngap_pdu), "Invalid init ctxt setup"); + return true; } - void send_ue_capability_info_and_handle_pdu_session_resource_setup_request() + [[nodiscard]] bool send_ue_capability_info_and_handle_pdu_session_resource_setup_request() { // Inject UL RRC Message Transfer (containing UE Capability Info) get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( @@ -175,8 +179,8 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : .value())); // Wait for E1AP Bearer Context Setup Request - bool result = this->wait_for_e1ap_tx_pdu(0, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive E1AP Bearer Context Setup Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive E1AP Bearer Context Setup Request"); cu_cp_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(e1ap_pdu.pdu.init_msg().value.bearer_context_setup_request()->gnb_cu_cp_ue_e1ap_id); @@ -184,21 +188,21 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : // Inject Bearer Context Setup Response and wait for F1AP UE Context Modification Request. get_cu_up(0).push_tx_pdu(generate_bearer_context_setup_response(cu_cp_e1ap_id, cu_up_e1ap_id)); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP UE Context Modification Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive F1AP UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification"); // Inject UE Context Modification Response and wait for Bearer Context Modification to be sent to CU-UP. get_du(du_idx).push_ul_pdu( test_helpers::generate_ue_context_modification_response(du_ue_id, ue_ctx->cu_ue_id.value(), crnti)); - result = this->wait_for_e1ap_tx_pdu(0, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive E1AP Bearer Context Modification"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive E1AP Bearer Context Modification"); // Inject E1AP Bearer Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) get_cu_up(0).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); @@ -210,9 +214,10 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1}), "Invalid RRC Reconfiguration"); + return true; } - void send_rrc_reconfiguration_complete_and_await_initial_context_setup_response() + [[nodiscard]] bool send_rrc_reconfiguration_complete_and_await_initial_context_setup_response() { // Inject UL RRC Message Transfer (containing RRC Reconfiguration Complete) f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( @@ -220,37 +225,38 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); // Wait for Initial Context Setup Response - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Initial Context Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Initial Context Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_initial_context_setup_response(ngap_pdu), "Invalid init ctxt setup"); + return true; } - void await_initial_context_setup_failure() + [[nodiscard]] bool await_initial_context_setup_failure() { // Wait for NGAP Initial Context Setup Failure - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive Initial Context Setup Failure"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Initial Context Setup Failure"); report_fatal_error_if_not(test_helpers::is_valid_initial_context_setup_failure(ngap_pdu), "Invalid Initial Context Setup Failure"); + return true; } - void await_ue_capability_info_indication() + [[nodiscard]] bool await_ue_capability_info_indication() { // Wait for UE Capability Info Indication - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Radio Capability Info Indication"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive UE Radio Capability Info Indication"); report_fatal_error_if_not(test_helpers::is_valid_ue_radio_capability_info_indication(ngap_pdu), "Invalid UE Radio Capability Info Indication"); + return true; } - void await_ue_context_release_request() + [[nodiscard]] bool await_ue_context_release_request() { // Wait for UE Context Release Request - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Request"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive UE Context Release Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_request(ngap_pdu), "Invalid UE Context Release Request"); + return true; } unsigned du_idx = 0; @@ -271,7 +277,7 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : TEST_F(cu_cp_initial_context_setup_test, when_ue_context_setup_fails_then_initial_context_setup_fails) { // Inject Initial Context Setup Request - send_initial_context_setup_request(); + ASSERT_TRUE(send_initial_context_setup_request()); // Inject UE Context Setup Failure f1ap_message ue_ctxt_setup_failure = @@ -279,16 +285,16 @@ TEST_F(cu_cp_initial_context_setup_test, when_ue_context_setup_fails_then_initia get_du(du_idx).push_ul_pdu(ue_ctxt_setup_failure); // Wait for NGAP Initial Context Setup Failure - await_initial_context_setup_failure(); + ASSERT_TRUE(await_initial_context_setup_failure()); } TEST_F(cu_cp_initial_context_setup_test, when_security_mode_command_fails_then_initial_context_setup_fails) { // Inject Initial Context Setup Request - send_initial_context_setup_request(); + ASSERT_TRUE(send_initial_context_setup_request()); // Wait for F1AP UE Context Setup Request (containing Security Mode Command) and inject UE Context Setup Response - send_ue_context_setup_request_and_await_response(); + ASSERT_TRUE(send_ue_context_setup_request_and_await_response()); // Inject Security Mode Failure f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( @@ -296,77 +302,77 @@ TEST_F(cu_cp_initial_context_setup_test, when_security_mode_command_fails_then_i get_du(du_idx).push_ul_pdu(ul_rrc_msg_transfer); // Wait for NGAP Initial Context Setup Failure - await_initial_context_setup_failure(); + ASSERT_TRUE(await_initial_context_setup_failure()); } TEST_F(cu_cp_initial_context_setup_test, when_ue_capability_enquiry_fails_then_initial_context_setup_fails) { // Inject Initial Context Setup Request - send_initial_context_setup_request(); + ASSERT_TRUE(send_initial_context_setup_request()); // Wait for F1AP UE Context Setup Request (containing Security Mode Command) and inject UE Context Setup Response - send_ue_context_setup_request_and_await_response(); + ASSERT_TRUE(send_ue_context_setup_request_and_await_response()); // Inject Security Mode Complete and await UE Capability Enquiry - send_security_mode_complete_and_await_ue_capability_enquiry(); + ASSERT_TRUE(send_security_mode_complete_and_await_ue_capability_enquiry()); // Fail UE Capability Enquiry (UE doesn't respond) ASSERT_FALSE(tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), [&]() { return false; })); // Wait for NGAP Initial Context Setup Failure - await_initial_context_setup_failure(); + ASSERT_TRUE(await_initial_context_setup_failure()); } TEST_F(cu_cp_initial_context_setup_test, when_ue_capability_enquiry_successful_then_initial_context_setup_succeeds) { // Inject Initial Context Setup Request - send_initial_context_setup_request(); + ASSERT_TRUE(send_initial_context_setup_request()); // Wait for F1AP UE Context Setup Request (containing Security Mode Command) and inject UE Context Setup Response - send_ue_context_setup_request_and_await_response(); + ASSERT_TRUE(send_ue_context_setup_request_and_await_response()); // Inject Security Mode Complete and await UE Capability Enquiry - send_security_mode_complete_and_await_ue_capability_enquiry(); + ASSERT_TRUE(send_security_mode_complete_and_await_ue_capability_enquiry()); // Inject UE Capability Info and await DL RRC Message (Registration Accept) and Initial Context Setup Response - send_ue_capability_info_and_await_registration_accept_and_initial_context_setup_response(); + ASSERT_TRUE(send_ue_capability_info_and_await_registration_accept_and_initial_context_setup_response()); // Wait for UE Capability Info Indication - await_ue_capability_info_indication(); + ASSERT_TRUE(await_ue_capability_info_indication()); } TEST_F(cu_cp_initial_context_setup_test, when_initial_context_setup_contains_valid_pdu_sessions_to_setup_then_initial_context_setup_succeeds) { // Inject Initial Context Setup Request - send_initial_context_setup_request(true); + ASSERT_TRUE(send_initial_context_setup_request(true)); // Wait for F1AP UE Context Setup Request (containing Security Mode Command) and inject UE Context Setup Response - send_ue_context_setup_request_and_await_response(); + ASSERT_TRUE(send_ue_context_setup_request_and_await_response()); // Inject Security Mode Complete and await UE Capability Enquiry - send_security_mode_complete_and_await_ue_capability_enquiry(); + ASSERT_TRUE(send_security_mode_complete_and_await_ue_capability_enquiry()); // Inject UE Capability Info and handle PDU Session Resource Setup List Context Request - send_ue_capability_info_and_handle_pdu_session_resource_setup_request(); + ASSERT_TRUE(send_ue_capability_info_and_handle_pdu_session_resource_setup_request()); // Inject RRC Reconfiguration Complete and await Initial Context Setup Response - send_rrc_reconfiguration_complete_and_await_initial_context_setup_response(); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_initial_context_setup_response()); // Wait for UE Capability Info Indication - await_ue_capability_info_indication(); + ASSERT_TRUE(await_ue_capability_info_indication()); } TEST_F(cu_cp_initial_context_setup_test, when_initial_context_setup_contains_ue_capabilities_then_initial_context_setup_succeeds) { // Inject Initial Context Setup Request with UE capabilities - send_initial_context_setup_request(false, true); + ASSERT_TRUE(send_initial_context_setup_request(false, true)); // Wait for F1AP UE Context Setup Request (containing Security Mode Command) and inject UE Context Setup Response - send_ue_context_setup_request_and_await_response(); + ASSERT_TRUE(send_ue_context_setup_request_and_await_response()); // Inject Security Mode Complete and await DL RRC Message (Registration Accept) and Initial Context Setup Response - send_security_mode_complete_and_await_registration_accept_and_initial_context_setup_response(); + ASSERT_TRUE(send_security_mode_complete_and_await_registration_accept_and_initial_context_setup_response()); } From 1e249941659a0c1580a43cd3d07d1eb48e7e6c9c Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:28:36 +0200 Subject: [PATCH 118/407] cu_cp: refactor inter du handover test --- .../cu_cp/cu_cp_inter_du_handover_test.cpp | 61 +++++++++++-------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp index d182aed490..8a00272d2e 100644 --- a/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_inter_du_handover_test.cpp @@ -11,6 +11,7 @@ #include "cu_cp_test_environment.h" #include "tests/test_doubles/e1ap/e1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "srsran/e1ap/common/e1ap_types.h" @@ -58,7 +59,7 @@ class cu_cp_inter_du_handover_test : public cu_cp_test_environment, public ::tes EXPECT_NE(ue_ctx, nullptr); } - void send_rrc_measurement_report_and_await_ue_context_setup_request() + [[nodiscard]] bool send_rrc_measurement_report_and_await_ue_context_setup_request() { // Inject UL RRC Message (containing RRC Measurement Report) and wait for UE Context Setup Request get_du(source_du_idx) @@ -67,20 +68,22 @@ class cu_cp_inter_du_handover_test : public cu_cp_test_environment, public ::tes ue_ctx->du_ue_id.value(), srb_id_t::srb1, make_byte_buffer("000800410004015f741fe0804bf183fcaa6e9699").value())); - bool result = this->wait_for_f1ap_tx_pdu(target_du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Setup Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(target_du_idx, f1ap_pdu), + "Failed to receive UE Context Setup Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_setup_request_with_ue_capabilities(f1ap_pdu), "Invalid UE Context Setup Request"); + return true; } - void send_ue_context_setup_failure() + [[nodiscard]] bool send_ue_context_setup_failure() { // Inject UE Context Setup Failure get_du(target_du_idx) .push_ul_pdu(generate_ue_context_setup_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + return true; } - void send_ue_context_setup_response_and_await_bearer_context_modification_request() + [[nodiscard]] bool send_ue_context_setup_response_and_await_bearer_context_modification_request() { // Inject UE Context Setup Response and await Bearer Context Modification Request get_du(target_du_idx) @@ -104,25 +107,27 @@ class cu_cp_inter_du_handover_test : public cu_cp_test_environment, public ::tes "004000000410c04080c100e0d0000e388000000400800100c001" "0120044014c00004620090e3800c") .value())); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Modification Request"); report_fatal_error_if_not( test_helpers::is_valid_bearer_context_modification_request_with_ue_security_info(e1ap_pdu), "Invalid Bearer Context Modification Request"); + return true; } - void send_bearer_context_modification_failure_and_await_f1ap_ue_context_release_command() + [[nodiscard]] bool send_bearer_context_modification_failure_and_await_f1ap_ue_context_release_command() { // Inject Bearer Context Modification Failure and wait for UE Context Release Command get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(target_du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(target_du_idx, f1ap_pdu), + "Failed to receive UE Context Release Command"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), "Invalid UE Context Release Command"); + return true; } - void send_bearer_context_modification_response_and_await_ue_context_modification_request() + [[nodiscard]] bool send_bearer_context_modification_response_and_await_ue_context_modification_request() { // Inject Bearer Context Modification Response and wait for RRC Reconfiguration get_cu_up(cu_up_idx).push_tx_pdu( @@ -131,30 +136,34 @@ class cu_cp_inter_du_handover_test : public cu_cp_test_environment, public ::tes report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification Request"); + return true; } - void send_ue_context_modification_response() + [[nodiscard]] bool send_ue_context_modification_response() { // Inject UE Context Modification Response and wait for UE Context Release Command get_du(source_du_idx) .push_ul_pdu( generate_ue_context_modification_response(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value(), crnti)); + return true; } - void send_rrc_reconfiguration_complete() + [[nodiscard]] bool send_rrc_reconfiguration_complete() { get_du(target_du_idx) .push_ul_pdu(generate_ul_rrc_message_transfer(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value(), srb_id_t::srb1, make_byte_buffer("8000080035c41efd").value())); + return true; } - void send_f1ap_ue_context_release_complete(unsigned du_idx) + [[nodiscard]] bool send_f1ap_ue_context_release_complete(unsigned du_idx) { // Inject F1AP UE Context Release Complete get_du(du_idx).push_ul_pdu( generate_ue_context_release_complete(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); + return true; } unsigned source_du_idx = 0; @@ -182,10 +191,10 @@ class cu_cp_inter_du_handover_test : public cu_cp_test_environment, public ::tes TEST_F(cu_cp_inter_du_handover_test, when_ue_context_setup_fails_then_ho_fails) { // Inject Measurement Report and await F1AP UE Context Setup Request - send_rrc_measurement_report_and_await_ue_context_setup_request(); + ASSERT_TRUE(send_rrc_measurement_report_and_await_ue_context_setup_request()); // Inject UE Context Setup Failure - send_ue_context_setup_failure(); + ASSERT_TRUE(send_ue_context_setup_failure()); // STATUS: UE should be removed from target DU auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); @@ -195,16 +204,16 @@ TEST_F(cu_cp_inter_du_handover_test, when_ue_context_setup_fails_then_ho_fails) TEST_F(cu_cp_inter_du_handover_test, when_bearer_context_modification_fails_then_ho_fails) { // Inject Measurement Report and await F1AP UE Context Setup Request - send_rrc_measurement_report_and_await_ue_context_setup_request(); + ASSERT_TRUE(send_rrc_measurement_report_and_await_ue_context_setup_request()); // Inject UE Context Setup Response and await Bearer Context Modification Request - send_ue_context_setup_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_setup_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Failure - send_bearer_context_modification_failure_and_await_f1ap_ue_context_release_command(); + ASSERT_TRUE(send_bearer_context_modification_failure_and_await_f1ap_ue_context_release_command()); // Inject F1AP UE Context Release Complete - send_f1ap_ue_context_release_complete(target_du_idx); + ASSERT_TRUE(send_f1ap_ue_context_release_complete(target_du_idx)); // STATUS: UE should be removed from target DU auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); @@ -214,22 +223,22 @@ TEST_F(cu_cp_inter_du_handover_test, when_bearer_context_modification_fails_then TEST_F(cu_cp_inter_du_handover_test, when_ho_succeeds_then_source_ue_is_removed) { // Inject Measurement Report and await F1AP UE Context Setup Request - send_rrc_measurement_report_and_await_ue_context_setup_request(); + ASSERT_TRUE(send_rrc_measurement_report_and_await_ue_context_setup_request()); // Inject UE Context Setup Response and await Bearer Context Modification Request - send_ue_context_setup_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_setup_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response - send_ue_context_modification_response(); + ASSERT_TRUE(send_ue_context_modification_response()); // Inject RRC Reconfiguration Complete - send_rrc_reconfiguration_complete(); + ASSERT_TRUE(send_rrc_reconfiguration_complete()); // Inject F1AP UE Context Release Complete - send_f1ap_ue_context_release_complete(source_du_idx); + ASSERT_TRUE(send_f1ap_ue_context_release_complete(source_du_idx)); // STATUS: UE should be removed from source DU auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); From 75697c6db1d945fdffb21c8d6330534123d3e004 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:35:18 +0200 Subject: [PATCH 119/407] cu_cp: refactor paging test --- tests/unittests/cu_cp/cu_cp_paging_test.cpp | 68 +++++++++++---------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_paging_test.cpp b/tests/unittests/cu_cp/cu_cp_paging_test.cpp index 1a61efa5b6..a71b3f0dc9 100644 --- a/tests/unittests/cu_cp/cu_cp_paging_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_paging_test.cpp @@ -11,6 +11,7 @@ #include "cu_cp_test_environment.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/ngap/ngap_test_messages.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents.h" #include "srsran/asn1/ngap/ngap_pdu_contents.h" @@ -30,7 +31,7 @@ class cu_cp_paging_test : public cu_cp_test_environment, public ::testing::Test run_ng_setup(); } - unsigned connect_du() + [[nodiscard]] unsigned connect_du() { // Connect DU (note that this creates a DU processor, but the DU is only connected after the F1Setup procedure) std::optional ret = connect_new_du(); @@ -38,7 +39,7 @@ class cu_cp_paging_test : public cu_cp_test_environment, public ::testing::Test return ret.value(); } - unsigned setup_du(const f1ap_message& f1_setup_request) + [[nodiscard]] unsigned setup_du(const f1ap_message& f1_setup_request) { // Setup DU unsigned tmp_du_idx = connect_du(); @@ -48,36 +49,42 @@ class cu_cp_paging_test : public cu_cp_test_environment, public ::testing::Test return tmp_du_idx; } - void send_ngap_paging(unsigned du_idx_, const ngap_message& paging_msg) + [[nodiscard]] bool send_ngap_paging(unsigned du_idx_, const ngap_message& paging_msg) { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx_).try_pop_dl_pdu(f1ap_pdu), - "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx_).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); get_amf().push_tx_pdu(paging_msg); + return true; } - void send_minimal_ngap_paging_and_await_f1ap_paging(unsigned du_idx_) + [[nodiscard]] bool send_minimal_ngap_paging_and_await_f1ap_paging(unsigned du_idx_) { // Inject NGAP Paging and wait for F1AP Paging - send_ngap_paging(du_idx_, generate_valid_minimal_paging_message()); - bool result = this->wait_for_f1ap_tx_pdu(du_idx_, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP Paging"); + if (!send_ngap_paging(du_idx_, generate_valid_minimal_paging_message())) { + return false; + } + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx_, f1ap_pdu), "Failed to receive F1AP Paging"); report_fatal_error_if_not(test_helpers::is_valid_paging(f1ap_pdu), "Invalid F1AP Paging"); report_fatal_error_if_not(is_valid_minimal_paging_result(f1ap_pdu), "Invalid minimal F1AP Paging"); + return true; } - void send_ngap_paging_and_await_f1ap_paging(unsigned du_idx_) + [[nodiscard]] bool send_ngap_paging_and_await_f1ap_paging(unsigned du_idx_) { // Inject NGAP Paging and wait for F1AP Paging - send_ngap_paging(du_idx_, generate_valid_paging_message()); - bool result = this->wait_for_f1ap_tx_pdu(du_idx_, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP Paging"); + if (!send_ngap_paging(du_idx_, generate_valid_paging_message())) { + return false; + } + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx_, f1ap_pdu), "Failed to receive F1AP Paging"); report_fatal_error_if_not(test_helpers::is_valid_paging(f1ap_pdu), "Invalid F1AP Paging"); report_fatal_error_if_not(is_valid_paging_result(f1ap_pdu), "Invalid F1AP Paging"); + return true; } - bool is_valid_minimal_paging_result(const f1ap_message& msg) + [[nodiscard]] bool is_valid_minimal_paging_result(const f1ap_message& msg) { const auto& paging_msg = msg.pdu.init_msg().value.paging(); @@ -117,7 +124,7 @@ class cu_cp_paging_test : public cu_cp_test_environment, public ::testing::Test return true; } - bool is_valid_paging_result(const f1ap_message& msg) + [[nodiscard]] bool is_valid_paging_result(const f1ap_message& msg) { if (!is_valid_minimal_paging_result(msg)) { return false; @@ -165,10 +172,10 @@ TEST_F(cu_cp_paging_test, when_du_connection_not_finished_then_paging_is_not_sen unsigned du_idx = connect_du(); // Inject NGAP Paging with only mandatory values - send_ngap_paging(du_idx, generate_valid_minimal_paging_message()); + ASSERT_TRUE(send_ngap_paging(du_idx, generate_valid_minimal_paging_message())); // Make sure that no paging was sent to the DU - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "Paging was sent to DU before F1Setup"); + ASSERT_FALSE(this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu)); } TEST_F(cu_cp_paging_test, when_no_du_for_tac_exists_then_paging_is_not_sent_to_du) @@ -179,10 +186,10 @@ TEST_F(cu_cp_paging_test, when_no_du_for_tac_exists_then_paging_is_not_sent_to_d // Inject NGAP Paging with unknown TAC ngap_message paging_msg = generate_valid_minimal_paging_message(); paging_msg.pdu.init_msg().value.paging()->tai_list_for_paging[0].tai.tac.from_number(8); - send_ngap_paging(du_idx, paging_msg); + ASSERT_TRUE(send_ngap_paging(du_idx, paging_msg)); // Make sure that no paging was sent to the DU - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "Paging with unknown TAC was sent to DU"); + ASSERT_FALSE(this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu)); } TEST_F(cu_cp_paging_test, when_assist_data_for_paging_for_unknown_tac_is_included_then_paging_is_not_sent_to_du) @@ -193,11 +200,10 @@ TEST_F(cu_cp_paging_test, when_assist_data_for_paging_for_unknown_tac_is_include // Inject NGAP Paging with unknown TAC but assist data for paging ngap_message paging_msg = generate_valid_paging_message(); paging_msg.pdu.init_msg().value.paging()->tai_list_for_paging[0].tai.tac.from_number(8); - send_ngap_paging(du_idx, paging_msg); + ASSERT_TRUE(send_ngap_paging(du_idx, paging_msg)); // Make sure that no paging was sent to the DU - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), - "Paging with unknown TAC but assist data was sent to DU"); + ASSERT_FALSE(this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu)); } TEST_F(cu_cp_paging_test, when_invalid_paging_message_received_then_paging_is_not_sent_to_du) @@ -206,10 +212,10 @@ TEST_F(cu_cp_paging_test, when_invalid_paging_message_received_then_paging_is_no unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); // Inject invalid NGAP Paging - send_ngap_paging(du_idx, generate_invalid_paging_message()); + ASSERT_TRUE(send_ngap_paging(du_idx, generate_invalid_paging_message())); // Make sure that no paging was sent to the DU - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "Invalid Paging was sent to DU"); + ASSERT_FALSE(this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu)); } TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_sent_to_du) @@ -218,7 +224,7 @@ TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_sent unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); // Inject NGAP Paging with only mandatory values and await F1AP Paging - send_minimal_ngap_paging_and_await_f1ap_paging(du_idx); + ASSERT_TRUE(send_minimal_ngap_paging_and_await_f1ap_paging(du_idx)); } TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_only_sent_to_du_with_matching_tac) @@ -231,10 +237,10 @@ TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_only test_helpers::generate_f1_setup_request(int_to_gnb_du_id(0x12), nr_cell_identity::create(6577).value(), 1, 8)); // Inject NGAP Paging with only mandatory values and await F1AP Paging - send_minimal_ngap_paging_and_await_f1ap_paging(du_idx); + ASSERT_TRUE(send_minimal_ngap_paging_and_await_f1ap_paging(du_idx)); // Make sure that no paging was sent to the second DU - srsran_assert(not this->get_du(du_idx2).try_pop_dl_pdu(f1ap_pdu), "Paging was sent to DU with different TAC"); + ASSERT_FALSE(this->get_du(du_idx2).try_pop_dl_pdu(f1ap_pdu)); } TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_only_sent_to_du_with_matching_nci) @@ -247,10 +253,10 @@ TEST_F(cu_cp_paging_test, when_valid_paging_message_received_then_paging_is_only test_helpers::generate_f1_setup_request(int_to_gnb_du_id(0x12), nr_cell_identity::create(6577).value(), 1, 7)); // Inject NGAP Paging with only mandatory values and await F1AP Paging - send_minimal_ngap_paging_and_await_f1ap_paging(du_idx); + ASSERT_TRUE(send_minimal_ngap_paging_and_await_f1ap_paging(du_idx)); // Make sure that no paging was sent to the second DU - srsran_assert(not this->get_du(du_idx2).try_pop_dl_pdu(f1ap_pdu), "Paging was sent to DU with different TAC"); + ASSERT_FALSE(this->get_du(du_idx2).try_pop_dl_pdu(f1ap_pdu)); } TEST_F(cu_cp_paging_test, when_valid_paging_message_with_optional_values_received_then_paging_is_sent_to_du) @@ -259,5 +265,5 @@ TEST_F(cu_cp_paging_test, when_valid_paging_message_with_optional_values_receive unsigned du_idx = setup_du(test_helpers::generate_f1_setup_request()); // Inject NGAP Paging with optional values and await F1AP Paging - send_ngap_paging_and_await_f1ap_paging(du_idx); + ASSERT_TRUE(send_ngap_paging_and_await_f1ap_paging(du_idx)); } From 82efc18cf746e9339726bda92a51507bc38afc8d Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:43:04 +0200 Subject: [PATCH 120/407] cu_cp: refactor pdu session resource modify test --- ...cu_cp_pdu_session_resource_modify_test.cpp | 214 ++++++++++-------- 1 file changed, 119 insertions(+), 95 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp index 12fb470cb7..252dab02a3 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_modify_test.cpp @@ -78,7 +78,7 @@ class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, pu f1ap_message f1ap_pdu; e1ap_message e1ap_pdu; - bool is_expected_pdu_session_resource_modify_response( + [[nodiscard]] bool is_expected_pdu_session_resource_modify_response( const std::vector& expected_pdu_sessions_to_modify, const std::vector& expected_pdu_sessions_failed_to_modify) { @@ -144,96 +144,106 @@ class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, pu return true; } - void send_pdu_session_modify_request_and_await_pdu_session_modify_response() + [[nodiscard]] bool send_pdu_session_modify_request_and_await_pdu_session_modify_response() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject PDU Session Resource Modify Request and wait for PDU Session Resource Modify Response get_amf().push_tx_pdu( generate_valid_pdu_session_resource_modify_request_message(amf_ue_id, ue_ctx->ran_ue_id.value(), psi2, {qfi2})); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Modify Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), "Invalid PDU Session Resource Modify Response"); report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi2}), "Unsuccessful PDU Session Resource Modify Response"); + return true; } - void send_pdu_session_modify_request_and_await_bearer_context_modification_request( + [[nodiscard]] bool send_pdu_session_modify_request_and_await_bearer_context_modification_request( pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1), const std::vector& flows_to_add = {uint_to_qos_flow_id(2)}, const std::vector& flows_to_release = {}) { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject PDU Session Resource Modify Request and wait for Bearer Context Modification Request get_amf().push_tx_pdu(generate_valid_pdu_session_resource_modify_request_message( amf_ue_id, ue_ctx->ran_ue_id.value(), pdu_session_id, flows_to_add, flows_to_release)); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), "Invalid Bearer Context Modification Request"); + return true; } - void send_bearer_context_modification_failure_and_await_pdu_session_modify_response() + [[nodiscard]] bool send_bearer_context_modification_failure_and_await_pdu_session_modify_response() { // Inject Bearer Context Modification Failure and wait for PDU Session Resource Setup Response get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Modify Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), "Invalid PDU Session Resource Modify Response"); report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi}), "Unsuccessful PDU Session Resource Modify Response"); + return true; } - void send_bearer_context_modification_response_and_await_ue_context_modification_request( + [[nodiscard]] bool send_bearer_context_modification_response_and_await_ue_context_modification_request( pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1), drb_id_t drb_id = drb_id_t::drb2) { // Inject Bearer Context Modification Response and wait for PDU Session Resource Setup Response get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value(), {}, {{pdu_session_id, drb_id}})); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification Request"); + return true; } - void send_ue_context_modification_failure_and_await_pdu_session_modify_response() + [[nodiscard]] bool send_ue_context_modification_failure_and_await_pdu_session_modify_response() { // Inject UE Context Modification Failure and wait for PDU Session Resource Setup Response get_du(du_idx).push_ul_pdu( generate_ue_context_modification_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Modify Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), "Invalid PDU Session Resource Modify Response"); report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi}), "Unsuccessful PDU Session Resource Modify Response"); + return true; } - void send_ue_context_modification_response_and_await_bearer_context_modification_request( + [[nodiscard]] bool send_ue_context_modification_response_and_await_bearer_context_modification_request( const std::vector& drbs_setup_mod_list = {drb_id_t::drb2}, const std::vector& drbs_modified_list = {}) { // Inject UE Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) get_du(du_idx).push_ul_pdu(generate_ue_context_modification_response( ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value(), crnti, drbs_setup_mod_list, drbs_modified_list)); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), "Invalid Bearer Context Modification Request"); + return true; } - void send_bearer_context_modification_response_and_await_rrc_reconfiguration( + [[nodiscard]] bool send_bearer_context_modification_response_and_await_rrc_reconfiguration( pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1), drb_id_t drb_to_modify = drb_id_t::drb2, bool is_drb_release = false) @@ -241,8 +251,8 @@ class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, pu // Inject Bearer Context Modification Response and wait for PDU Session Resource Setup Response get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value(), {}, {{pdu_session_id, drb_to_modify}})); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); { @@ -265,19 +275,23 @@ class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, pu "Invalid RRC Reconfiguration"); } } + return true; } - void timeout_rrc_reconfiguration_and_await_pdu_session_modify_response() + [[nodiscard]] bool timeout_rrc_reconfiguration_and_await_pdu_session_modify_response() { // Fail RRC Reconfiguration (UE doesn't respond) and wait for PDU Session Resource Setup Response - ASSERT_FALSE(tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), - [&]() { return false; })); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + if (tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), + [&]() { return false; })) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Modify Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), "Invalid PDU Session Resource Modify Response"); report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi}), "Unsuccessful PDU Session Resource Modify Response"); + return true; } bool send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( @@ -286,8 +300,8 @@ class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, pu // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for PDU Session Resource Modify Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, std::move(rrc_reconfiguration_complete))); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Modify Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), "Invalid PDU Session Resource Modify Response"); report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({psi}, {}), @@ -296,31 +310,46 @@ class cu_cp_pdu_session_resource_modify_test : public cu_cp_test_environment, pu return true; } - void modify_pdu_session_and_add_qos_flow( + [[nodiscard]] bool modify_pdu_session_and_add_qos_flow( pdu_session_id_t pdu_session_id, drb_id_t drb_id, qos_flow_id_t qos_flow_id, byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00080800e6847bbd").value()) { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(pdu_session_id, {qos_flow_id}, {}); + if (!send_pdu_session_modify_request_and_await_bearer_context_modification_request( + pdu_session_id, {qos_flow_id}, {})) { + return false; + } // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(pdu_session_id, drb_id); + if (!send_bearer_context_modification_response_and_await_ue_context_modification_request(pdu_session_id, drb_id)) { + return false; + } // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + if (!send_ue_context_modification_response_and_await_bearer_context_modification_request()) { + return false; + } // Inject Bearer Context Modification Response and await RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration(pdu_session_id, drb_id); + if (!send_bearer_context_modification_response_and_await_rrc_reconfiguration(pdu_session_id, drb_id)) { + return false; + } // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response - send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response(std::move(rrc_reconfiguration_complete)); + if (!send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( + std::move(rrc_reconfiguration_complete))) { + return false; + } + return true; } }; @@ -328,102 +357,103 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, when_modify_request_with_inactive_pdu_session_arrives_then_modification_fails) { // Inject PDU Session Resource Modify Request and await PDU Session Resource Modify Response - send_pdu_session_modify_request_and_await_pdu_session_modify_response(); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_pdu_session_modify_response()); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_bearer_ctxt_modification_fails_then_pdu_session_modify_fails) { // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Failure and await PDU Session Resource Modify Response - send_bearer_context_modification_failure_and_await_pdu_session_modify_response(); + ASSERT_TRUE(send_bearer_context_modification_failure_and_await_pdu_session_modify_response()); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_ue_ctxt_modification_fails_then_pdu_session_modify_fails) { // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Failure and await PDU Session Resource Modify Response - send_ue_context_modification_failure_and_await_pdu_session_modify_response(); + ASSERT_TRUE(send_ue_context_modification_failure_and_await_pdu_session_modify_response()); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_second_bearer_ctxt_modification_fails_then_pdu_session_modify_fails) { // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Failure and await PDU Session Resource Modify Response - send_bearer_context_modification_failure_and_await_pdu_session_modify_response(); + ASSERT_TRUE(send_bearer_context_modification_failure_and_await_pdu_session_modify_response()); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_rrc_reconfiguration_fails_then_pdu_session_modify_fails) { // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration()); // Let the RRC Reconfiguration timeout and await PDU Session Resource Modify Response - timeout_rrc_reconfiguration_and_await_pdu_session_modify_response(); + ASSERT_TRUE(timeout_rrc_reconfiguration_and_await_pdu_session_modify_response()); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_rrc_reconfiguration_succeeds_then_pdu_session_modify_succeeds) { // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration()); // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response - send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response(); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response()); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_valid_modification_arrives_and_qos_flow_can_be_removed_then_pdu_session_modification_succeeds) { // Run PDU session modification and add second QoS flow - modify_pdu_session_and_add_qos_flow(psi, drb_id_t::drb2, qfi2); + ASSERT_TRUE(modify_pdu_session_and_add_qos_flow(psi, drb_id_t::drb2, qfi2)); // Inject PDU Session Resource Modify Request and await Bearer Context Modification Request - send_pdu_session_modify_request_and_await_bearer_context_modification_request(psi, {}, {qfi2}); + ASSERT_TRUE(send_pdu_session_modify_request_and_await_bearer_context_modification_request(psi, {}, {qfi2})); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request({}, {drb_id_t::drb2}); + ASSERT_TRUE( + send_ue_context_modification_response_and_await_bearer_context_modification_request({}, {drb_id_t::drb2})); // Inject Bearer Context Modification Response and await RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration(psi, drb_id_t::drb2, true); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration(psi, drb_id_t::drb2, true)); // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Modify Response - send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( - generate_rrc_reconfiguration_complete_pdu(1, 9)); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_modify_response( + generate_rrc_reconfiguration_complete_pdu(1, 9))); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_many_qos_flows_are_added_pdu_session_modification_succeeds) @@ -432,10 +462,10 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, when_many_qos_flows_are_added_pdu unsigned transaction_id = 0; unsigned count = 8; for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow(psi, - uint_to_drb_id(i), - uint_to_qos_flow_id(i), - generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); + ASSERT_TRUE(modify_pdu_session_and_add_qos_flow(psi, + uint_to_drb_id(i), + uint_to_qos_flow_id(i), + generate_rrc_reconfiguration_complete_pdu(transaction_id, count))); count++; transaction_id++; if (transaction_id == 4) { @@ -450,10 +480,10 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, when_one_to_many_qos_flows_are_ad unsigned transaction_id = 0; unsigned count = 8; for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow(psi, - uint_to_drb_id(i), - uint_to_qos_flow_id(i), - generate_rrc_reconfiguration_complete_pdu(transaction_id, count)); + ASSERT_TRUE(modify_pdu_session_and_add_qos_flow(psi, + uint_to_drb_id(i), + uint_to_qos_flow_id(i), + generate_rrc_reconfiguration_complete_pdu(transaction_id, count))); count++; transaction_id++; if (transaction_id == 4) { @@ -465,27 +495,21 @@ TEST_F(cu_cp_pdu_session_resource_modify_test, when_one_to_many_qos_flows_are_ad // Inject PDU Session Resource Modify Request and wait for PDU Session Resource Modify Response get_amf().push_tx_pdu( generate_valid_pdu_session_resource_modify_request_message(amf_ue_id, ue_ctx->ran_ue_id.value(), psi2, {qfi2})); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); - report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), - "Invalid PDU Session Resource Modify Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi2}), - "Unsuccessful PDU Session Resource Modify Response"); + ASSERT_TRUE(this->wait_for_ngap_tx_pdu(ngap_pdu)); + ASSERT_TRUE(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu)); + ASSERT_TRUE(is_expected_pdu_session_resource_modify_response({}, {psi2})); } TEST_F(cu_cp_pdu_session_resource_modify_test, when_valid_modification_is_received_twice_then_second_modification_fails) { // Run PDU session modification and add second QoS flow - modify_pdu_session_and_add_qos_flow(psi, drb_id_t::drb2, qfi2); + ASSERT_TRUE(modify_pdu_session_and_add_qos_flow(psi, drb_id_t::drb2, qfi2)); // Run PDU session modification again and try to add same QoS flow // Inject PDU Session Resource Modify Request and wait for PDU Session Resource Modify Response get_amf().push_tx_pdu( generate_valid_pdu_session_resource_modify_request_message(amf_ue_id, ue_ctx->ran_ue_id.value(), psi2, {qfi2})); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Modify Response"); - report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu), - "Invalid PDU Session Resource Modify Response"); - report_fatal_error_if_not(is_expected_pdu_session_resource_modify_response({}, {psi2}), - "Unsuccessful PDU Session Resource Modify Response"); + ASSERT_TRUE(this->wait_for_ngap_tx_pdu(ngap_pdu)); + ASSERT_TRUE(test_helpers::is_valid_pdu_session_resource_modify_response(ngap_pdu)); + ASSERT_TRUE(is_expected_pdu_session_resource_modify_response({}, {psi2})); } From e8ff71da902cca6f6c81fcbef489c10331fb793b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:47:26 +0200 Subject: [PATCH 121/407] cu_cp: refactor pdu session resource release test --- ...u_cp_pdu_session_resource_release_test.cpp | 152 ++++++++++-------- 1 file changed, 83 insertions(+), 69 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp index 6fd903d7e1..10a023c1a8 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_release_test.cpp @@ -74,18 +74,20 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p f1ap_message f1ap_pdu; e1ap_message e1ap_pdu; - void setup_second_pdu_session() + [[nodiscard]] bool setup_second_pdu_session() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Modification Request get_amf().push_tx_pdu(generate_valid_pdu_session_resource_setup_request_message( ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi2, {{uint_to_qos_flow_id(2), 7}}}})); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), "Invalid Bearer Context Modification Request"); @@ -95,21 +97,22 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p cu_up_e1ap_id, {{psi2, drb_test_params{drb_id_t::drb2, uint_to_qos_flow_id(2)}}}, {})); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification Request"); // Inject UE Context Modification Response and await Bearer Context Modification Request - ASSERT_TRUE( - cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( - du_idx, cu_up_idx, du_ue_id, crnti)); + if (!cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( + du_idx, cu_up_idx, du_ue_id, crnti)) { + return false; + } // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value(), {}, {{psi2, drb_id_t::drb2}})); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); { @@ -125,86 +128,96 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, generate_rrc_reconfiguration_complete_pdu(0, 8))); - result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi2}, {}), "Unsuccessful PDU Session Resource Setup Response"); + return true; } - void send_pdu_session_release_command_and_await_bearer_context_modification_request() + [[nodiscard]] bool send_pdu_session_release_command_and_await_bearer_context_modification_request() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject Bearer Context Setup Response and wait for UE Context Modification Request get_amf().push_tx_pdu( generate_valid_pdu_session_resource_release_command(amf_ue_id, ue_ctx->ran_ue_id.value(), psi)); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Modification Request"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_modification_request(e1ap_pdu), "Invalid Bearer Context Modification Request"); + return true; } - void send_pdu_session_release_command_and_await_bearer_context_release_command() + [[nodiscard]] bool send_pdu_session_release_command_and_await_bearer_context_release_command() { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject Bearer Context Setup Response and wait for UE Context Release Command get_amf().push_tx_pdu( generate_valid_pdu_session_resource_release_command(amf_ue_id, ue_ctx->ran_ue_id.value(), psi)); - bool result = this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive Bearer Context Release Command"); + report_fatal_error_if_not(this->wait_for_e1ap_tx_pdu(cu_up_idx, e1ap_pdu), + "Failed to receive Bearer Context Release Command"); report_fatal_error_if_not(test_helpers::is_valid_bearer_context_release_command(e1ap_pdu), "Invalid Bearer Context Release Command"); + return true; } - void send_bearer_context_modification_failure_and_await_ue_context_modification_request() + [[nodiscard]] bool send_bearer_context_modification_failure_and_await_ue_context_modification_request() { // Inject Bearer Context Modification Failure and wait for UE Context Modification Request get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification Request"); + return true; } - void send_bearer_context_modification_response_and_await_ue_context_modification_request() + [[nodiscard]] bool send_bearer_context_modification_response_and_await_ue_context_modification_request() { // Inject Bearer Context Modification Response and wait for UE Context Modification Request get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification Request"); + return true; } - void send_bearer_context_release_complete_and_await_ue_context_modification_request() + [[nodiscard]] bool send_bearer_context_release_complete_and_await_ue_context_modification_request() { // Inject Bearer Context Release Complete and wait for UE Context Modification Request get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_release_complete(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), "Invalid UE Context Modification Request"); + return true; } - void send_ue_context_modification_response_and_await_rrc_reconfiguration() + [[nodiscard]] bool send_ue_context_modification_response_and_await_rrc_reconfiguration() { // Inject UE Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) get_du(du_idx).push_ul_pdu( test_helpers::generate_ue_context_modification_response(du_ue_id, ue_ctx->cu_ue_id.value(), crnti)); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); { @@ -213,15 +226,16 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), {}, {}), "Invalid RRC Reconfiguration"); } + return true; } - void send_ue_context_modification_failure_and_await_rrc_reconfiguration() + [[nodiscard]] bool send_ue_context_modification_failure_and_await_rrc_reconfiguration() { // Inject UE Context Modification Failure and wait for DL RRC Message (containing RRC Reconfiguration) get_du(du_idx).push_ul_pdu( generate_ue_context_modification_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), "Invalid DL RRC Message Transfer"); { @@ -230,19 +244,19 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), {}, {}), "Invalid RRC Reconfiguration"); } + return true; } - bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response() + [[nodiscard]] bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response() { // Inject UL RRC Message (containing RRC Reconfiguration Complete) and wait for PDU Session Resource Release // Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, generate_rrc_reconfiguration_complete_pdu(3, 7))); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Release Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Release Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_release_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); - return true; } }; @@ -250,68 +264,68 @@ class cu_cp_pdu_session_resource_release_test : public cu_cp_test_environment, p TEST_F(cu_cp_pdu_session_resource_release_test, when_bearer_context_modification_failure_received_then_release_succeeds) { // Add second PDU session - setup_second_pdu_session(); + ASSERT_TRUE(setup_second_pdu_session()); // Inject NGAP PDU Session Resource Release Command and await Bearer Context Modification Request - send_pdu_session_release_command_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_release_command_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Failure and await UE Context Modification Request - send_bearer_context_modification_failure_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_failure_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await RRC Reconfiguration - send_ue_context_modification_response_and_await_rrc_reconfiguration(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_rrc_reconfiguration()); // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_release_test, when_ue_context_modification_failure_received_then_release_succeeds) { // Add second PDU session - setup_second_pdu_session(); + ASSERT_TRUE(setup_second_pdu_session()); // Inject NGAP PDU Session Resource Release Command and await Bearer Context Modification Request - send_pdu_session_release_command_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_release_command_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Failure and await RRC Reconfiguration - send_ue_context_modification_failure_and_await_rrc_reconfiguration(); + ASSERT_TRUE(send_ue_context_modification_failure_and_await_rrc_reconfiguration()); // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_release_test, when_all_sub_actions_succeed_then_release_succeeds) { // Add second PDU session - setup_second_pdu_session(); + ASSERT_TRUE(setup_second_pdu_session()); // Inject NGAP PDU Session Resource Release Command and await Bearer Context Modification Request - send_pdu_session_release_command_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_pdu_session_release_command_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await UE Context Modification Request - send_bearer_context_modification_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await RRC Reconfiguration - send_ue_context_modification_response_and_await_rrc_reconfiguration(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_rrc_reconfiguration()); // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_release_test, when_only_pdu_session_released_then_bearer_context_release_command_sent) { // Inject NGAP PDU Session Resource Release Command and await Bearer Context Release Command - send_pdu_session_release_command_and_await_bearer_context_release_command(); + ASSERT_TRUE(send_pdu_session_release_command_and_await_bearer_context_release_command()); // Inject Bearer Context Release Complete and await UE Context Modification Request - send_bearer_context_release_complete_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_release_complete_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await RRC Reconfiguration - send_ue_context_modification_response_and_await_rrc_reconfiguration(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_rrc_reconfiguration()); // Inject RRC Reconfiguration Complete and await PDU Session Resource Release Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response(); -} \ No newline at end of file + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response()); +} From d8da86d1c99001489217bc6b370211c94a5cb158 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:54:35 +0200 Subject: [PATCH 122/407] cu_cp: refactor pdu session resource setup test --- .../cu_cp_pdu_session_resource_setup_test.cpp | 267 +++++++++--------- 1 file changed, 133 insertions(+), 134 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp index 1269d4e12e..c725bc70ca 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp @@ -60,22 +60,23 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub EXPECT_NE(ue_ctx, nullptr); } - void setup_pdu_session(pdu_session_id_t psi_, - drb_id_t drb_id_, - qos_flow_id_t qfi_, - byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), - bool is_initial_session_ = true) + [[nodiscard]] bool + setup_pdu_session(pdu_session_id_t psi_, + drb_id_t drb_id_, + qos_flow_id_t qfi_, + byte_buffer rrc_reconfiguration_complete = make_byte_buffer("00070e00cc6fcda5").value(), + bool is_initial_session_ = true) { - EXPECT_TRUE(cu_cp_test_environment::setup_pdu_session(du_idx, - cu_up_idx, - du_ue_id, - crnti, - cu_up_e1ap_id, - psi_, - drb_id_, - qfi_, - std::move(rrc_reconfiguration_complete), - is_initial_session_)); + return cu_cp_test_environment::setup_pdu_session(du_idx, + cu_up_idx, + du_ue_id, + crnti, + cu_up_e1ap_id, + psi_, + drb_id_, + qfi_, + std::move(rrc_reconfiguration_complete), + is_initial_session_); } ngap_message generate_pdu_session_resource_setup_request_with_unconfigured_fiveqi() const @@ -86,138 +87,145 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub return request; } - void send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( + [[nodiscard]] bool send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( const ngap_message& pdu_session_resource_setup_request) { - srsran_assert(not this->get_amf().try_pop_rx_pdu(ngap_pdu), "there are still NGAP messages to pop from AMF"); - srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); - srsran_assert(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); + report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), + "there are still F1AP DL messages to pop from DU"); + report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), + "there are still E1AP messages to pop from CU-UP"); // Inject PDU Session Resource Setup Request and wait for PDU Session Resource Setup Response get_amf().push_tx_pdu(pdu_session_resource_setup_request); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); + return true; } - void send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + [[nodiscard]] bool send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( const ngap_message& pdu_session_resource_setup_request) { - ASSERT_TRUE(cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( - pdu_session_resource_setup_request, du_idx, cu_up_idx, du_ue_id)); + return cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + pdu_session_resource_setup_request, du_idx, cu_up_idx, du_ue_id); } - void send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + [[nodiscard]] bool send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( const ngap_message& pdu_session_resource_setup_request) { - ASSERT_TRUE( - cu_cp_test_environment::send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( - pdu_session_resource_setup_request, du_idx)); + return cu_cp_test_environment:: + send_pdu_session_resource_setup_request_and_await_bearer_context_modification_request( + pdu_session_resource_setup_request, du_idx); } - void send_bearer_context_setup_failure_and_await_pdu_session_setup_response() + [[nodiscard]] bool send_bearer_context_setup_failure_and_await_pdu_session_setup_response() { // Inject Bearer Context Setup Failure and wait for PDU Session Resource Setup Response get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_setup_failure(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); + return true; } - void send_bearer_context_setup_response_and_await_ue_context_modification_request() + [[nodiscard]] bool send_bearer_context_setup_response_and_await_ue_context_modification_request() { - ASSERT_TRUE(cu_cp_test_environment::send_bearer_context_setup_response_and_await_ue_context_modification_request( - du_idx, cu_up_idx, du_ue_id, cu_up_e1ap_id, psi, qfi)); + return cu_cp_test_environment::send_bearer_context_setup_response_and_await_ue_context_modification_request( + du_idx, cu_up_idx, du_ue_id, cu_up_e1ap_id, psi, qfi); } - void send_bearer_context_modification_response_and_await_ue_context_modification_request() + [[nodiscard]] bool send_bearer_context_modification_response_and_await_ue_context_modification_request() { - ASSERT_TRUE( - cu_cp_test_environment::send_bearer_context_modification_response_and_await_ue_context_modification_request( - du_idx, cu_up_idx, du_ue_id, psi2, drb_id_t::drb2, qfi2)); + return cu_cp_test_environment::send_bearer_context_modification_response_and_await_ue_context_modification_request( + du_idx, cu_up_idx, du_ue_id, psi2, drb_id_t::drb2, qfi2); } - void send_ue_context_modification_failure_and_await_pdu_session_setup_response() + [[nodiscard]] bool send_ue_context_modification_failure_and_await_pdu_session_setup_response() { // Inject UE Context Modification Failure and wait for PDU Session Resource Setup Response get_du(du_idx).push_ul_pdu( generate_ue_context_modification_failure(ue_ctx->cu_ue_id.value(), ue_ctx->du_ue_id.value())); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); + return true; } - void send_ue_context_modification_response_and_await_bearer_context_modification_request() + [[nodiscard]] bool send_ue_context_modification_response_and_await_bearer_context_modification_request() { - ASSERT_TRUE( - cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( - du_idx, cu_up_idx, du_ue_id, crnti)); + return cu_cp_test_environment::send_ue_context_modification_response_and_await_bearer_context_modification_request( + du_idx, cu_up_idx, du_ue_id, crnti); } - void send_bearer_context_modification_failure_and_await_pdu_session_setup_response() + [[nodiscard]] bool send_bearer_context_modification_failure_and_await_pdu_session_setup_response() { // Inject Bearer Context Modification Failure and wait for PDU Session Resource Setup Response get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_modification_failure(ue_ctx->cu_cp_e1ap_id.value(), ue_ctx->cu_up_e1ap_id.value())); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); + return true; } - void send_bearer_context_modification_response_and_await_rrc_reconfiguration( + [[nodiscard]] bool send_bearer_context_modification_response_and_await_rrc_reconfiguration( const std::map& pdu_sessions_to_add = {}, const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}, const std::optional>& expected_srbs_to_add_mod = std::nullopt, const std::optional>& expected_drbs_to_add_mod = std::nullopt) { - ASSERT_TRUE(cu_cp_test_environment::send_bearer_context_modification_response_and_await_rrc_reconfiguration( + return cu_cp_test_environment::send_bearer_context_modification_response_and_await_rrc_reconfiguration( du_idx, cu_up_idx, du_ue_id, pdu_sessions_to_add, pdu_sessions_to_modify, expected_srbs_to_add_mod, - expected_drbs_to_add_mod)); + expected_drbs_to_add_mod); } - void timeout_rrc_reconfiguration_and_await_pdu_session_setup_response() + [[nodiscard]] bool timeout_rrc_reconfiguration_and_await_pdu_session_setup_response() { // Fail RRC Reconfiguration (UE doesn't respond) and wait for PDU Session Resource Setup Response - ASSERT_FALSE(tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), - [&]() { return false; })); - bool result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); + if (tick_until(std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), + [&]() { return false; })) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), + "Failed to receive PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), "Invalid PDU Session Resource Setup Response"); report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {}, {psi}), "Unsuccessful PDU Session Resource Setup Response"); + return true; } - void send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + [[nodiscard]] bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( byte_buffer rrc_container, const std::vector& expected_pdu_sessions_to_setup, const std::vector& expected_pdu_sessions_failed_to_setup) { - ASSERT_TRUE(cu_cp_test_environment::send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + return cu_cp_test_environment::send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( du_idx, du_ue_id, std::move(rrc_container), expected_pdu_sessions_to_setup, - expected_pdu_sessions_failed_to_setup)); + expected_pdu_sessions_failed_to_setup); } unsigned du_idx = 0; @@ -244,129 +252,129 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, when_pdu_session_setup_request_with_unconfigured_fiveqi_received_setup_fails) { // Inject NGAP PDU Session Resource Setup Request and await PDU Session Setup Response - send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( - generate_pdu_session_resource_setup_request_with_unconfigured_fiveqi()); + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( + generate_pdu_session_resource_setup_request_with_unconfigured_fiveqi())); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_bearer_context_setup_failure_received_then_setup_fails) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); // Inject Bearer Context Setup Failure and await PDU Session Resource Setup Response - send_bearer_context_setup_failure_and_await_pdu_session_setup_response(); + ASSERT_TRUE(send_bearer_context_setup_failure_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_ue_context_modification_failure_received_then_setup_fails) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request - send_bearer_context_setup_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Failure and await PDU Session Resource Setup Response - send_ue_context_modification_failure_and_await_pdu_session_setup_response(); + ASSERT_TRUE(send_ue_context_modification_failure_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_bearer_context_modification_failure_received_then_setup_fails) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request - send_bearer_context_setup_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Failure and await PDU Session Resource Setup Response - send_bearer_context_modification_failure_and_await_pdu_session_setup_response(); + ASSERT_TRUE(send_bearer_context_modification_failure_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_rrc_reconfiguration_fails_then_setup_fails) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request - send_bearer_context_setup_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration( - {}, {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1}); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1})); // Let the RRC Reconfiguration timeout and await PDU Session Resource Setup Response - timeout_rrc_reconfiguration_and_await_pdu_session_setup_response(); + ASSERT_TRUE(timeout_rrc_reconfiguration_and_await_pdu_session_setup_response()); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_rrc_reconfiguration_succeeds_then_setup_succeeds) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request - send_bearer_context_setup_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration( - {}, {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1}); + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1})); // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( - generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {}); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {})); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_pdu_session_setup_for_existing_session_arrives_then_setup_fails) { // Setup first PDU session - setup_pdu_session(psi, drb_id_t::drb1, qfi); + ASSERT_TRUE(setup_pdu_session(psi, drb_id_t::drb1, qfi)); // Inject NGAP PDU Session Resource Setup Request and await PDU Session Setup Response - send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_pdu_session_setup_response( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_setup_for_pdu_sessions_with_two_qos_flows_received_setup_succeeds) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}, {qfi2, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}, {qfi2, 9}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request - send_bearer_context_setup_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration( + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration( {}, {{psi, drb_id_t::drb1}, {psi2, drb_id_t::drb2}}, std::vector{srb_id_t::srb2}, - std::vector{drb_id_t::drb1, drb_id_t::drb2}); + std::vector{drb_id_t::drb1, drb_id_t::drb2})); // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( - generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {}); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {})); } TEST_F( @@ -374,82 +382,73 @@ TEST_F( when_setup_for_two_pdu_sessions_is_requested_but_only_first_could_be_setup_at_cu_up_setup_succeeds_with_fail_list) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), - {{psi, {qos_flow_test_params{qfi, 9}}}, {psi2, {qos_flow_test_params{qfi2, 7}}}})); + {{psi, {qos_flow_test_params{qfi, 9}}}, {psi2, {qos_flow_test_params{qfi2, 7}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_setup_response( ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {{psi, drb_test_params{drb_id_t::drb1, qfi}}}, {psi2})); - bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); - report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), - "Invalid UE Context Modification Request"); + ASSERT_TRUE(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu)); + ASSERT_TRUE(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu)); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration get_cu_up(cu_up_idx).push_tx_pdu( generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); - result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); - report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); - report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), - "Invalid DL RRC Message Transfer"); + ASSERT_TRUE(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu)); + ASSERT_TRUE(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu)); { const byte_buffer& rrc_container = test_helpers::get_rrc_container(f1ap_pdu); - report_fatal_error_if_not( - test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), - true, - std::vector{srb_id_t::srb2}, - std::vector{drb_id_t::drb1}), - "Invalid RRC Reconfiguration"); + ASSERT_TRUE(test_helpers::is_valid_rrc_reconfiguration(test_helpers::extract_dl_dcch_msg(rrc_container), + true, + std::vector{srb_id_t::srb2}, + std::vector{drb_id_t::drb1})); } // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response get_du(du_idx).push_ul_pdu(test_helpers::create_ul_rrc_message_transfer( du_ue_id, ue_ctx->cu_ue_id.value(), srb_id_t::srb1, make_byte_buffer("00070e00cc6fcda5").value())); - result = this->wait_for_ngap_tx_pdu(ngap_pdu); - report_fatal_error_if_not(result, "Failed to receive PDU Session Resource Setup Response"); - report_fatal_error_if_not(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu), - "Invalid PDU Session Resource Setup Response"); - report_fatal_error_if_not(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi}, {psi2}), - "Unsuccessful PDU Session Resource Setup Response"); + ASSERT_TRUE(this->wait_for_ngap_tx_pdu(ngap_pdu)); + ASSERT_TRUE(test_helpers::is_valid_pdu_session_resource_setup_response(ngap_pdu)); + ASSERT_TRUE(test_helpers::is_expected_pdu_session_resource_setup_response(ngap_pdu, {psi}, {psi2})); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_setup_for_two_pdu_sessions_is_requested_and_both_succeed_setup_succeeds) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request - send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( generate_valid_pdu_session_resource_setup_request_message( - ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}, {psi2, {{qfi2, 9}}}})); + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}, {psi2, {{qfi2, 9}}}}))); // Inject Bearer Context Setup Response and await UE Context Modification Request - send_bearer_context_setup_response_and_await_ue_context_modification_request(); + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); // Inject UE Context Modification Response and await Bearer Context Modification Request - send_ue_context_modification_response_and_await_bearer_context_modification_request(); + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration - send_bearer_context_modification_response_and_await_rrc_reconfiguration( + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration( {}, {{psi, drb_id_t::drb1}, {psi2, drb_id_t::drb2}}, std::vector{srb_id_t::srb2}, - std::vector{drb_id_t::drb1, drb_id_t::drb2}); + std::vector{drb_id_t::drb1, drb_id_t::drb2})); // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response - send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( - generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {}); + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + generate_rrc_reconfiguration_complete_pdu(3, 7), {psi}, {})); } TEST_F(cu_cp_pdu_session_resource_setup_test, when_two_consecutive_setups_arrive_bearer_setup_and_modification_succeed) { // Setup first PDU session - setup_pdu_session(psi, drb_id_t::drb1, qfi); + ASSERT_TRUE(setup_pdu_session(psi, drb_id_t::drb1, qfi)); // Setup second PDU session - setup_pdu_session(psi2, drb_id_t::drb2, qfi2, generate_rrc_reconfiguration_complete_pdu(0, 8), false); -} \ No newline at end of file + ASSERT_TRUE(setup_pdu_session(psi2, drb_id_t::drb2, qfi2, generate_rrc_reconfiguration_complete_pdu(0, 8), false)); +} From 3e808bc6ebed1e739774d6cfb767c2cdf1008b1b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 13:56:55 +0200 Subject: [PATCH 123/407] cu_cp: refactor reestablishment test --- .../cu_cp/cu_cp_reestablishment_test.cpp | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp b/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp index 253486ac67..711da5734f 100644 --- a/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_reestablishment_test.cpp @@ -13,6 +13,7 @@ #include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/test_doubles/ngap/ngap_test_message_validators.h" #include "tests/test_doubles/rrc/rrc_test_messages.h" +#include "tests/unittests/cu_cp/test_helpers.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" #include "srsran/asn1/ngap/ngap_pdu_contents.h" @@ -46,10 +47,10 @@ class cu_cp_reestablishment_test : public cu_cp_test_environment, public ::testi /// Run RRC Reestablishment. /// \return Returns true if Reestablishment is successful, and false if the gNB fallbacked to RRC Setup. - bool send_rrc_reest_request_and_wait_response(gnb_du_ue_f1ap_id_t new_du_ue_id, - rnti_t new_rnti, - rnti_t old_rnti_, - pci_t old_pci_) + [[nodiscard]] bool send_rrc_reest_request_and_wait_response(gnb_du_ue_f1ap_id_t new_du_ue_id, + rnti_t new_rnti, + rnti_t old_rnti_, + pci_t old_pci_) { // Generate RRC Reestablishment Request. byte_buffer rrc_container = @@ -103,34 +104,44 @@ class cu_cp_reestablishment_test : public cu_cp_test_environment, public ::testi return f1ap_pdu; } - void ue_sends_rrc_setup_complete(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id) + [[nodiscard]] bool ue_sends_rrc_setup_complete(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id) { // Generate RRC Setup Complete. byte_buffer pdu = pack_ul_dcch_msg(create_rrc_setup_complete()); // Prepend PDCP header and append MAC. - EXPECT_TRUE(pdu.prepend(std::array{0x00U, 0x00U})); - EXPECT_TRUE(pdu.append(std::array{})); + if (!pdu.prepend(std::array{0x00U, 0x00U})) { + return false; + } + if (!pdu.append(std::array{})) { + return false; + } // Send UL RRC Message to CU-CP. f1ap_message f1ap_ul_rrc_msg = test_helpers::create_ul_rrc_message_transfer(du_ue_id, cu_ue_id, srb_id_t::srb1, std::move(pdu)); get_du(du_idx).push_ul_pdu(f1ap_ul_rrc_msg); + return true; } - void ue_sends_rrc_reest_complete(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id) + [[nodiscard]] bool ue_sends_rrc_reest_complete(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id) { // Generate RRC Reestablishment Complete. byte_buffer pdu = pack_ul_dcch_msg(create_rrc_reestablishment_complete()); // Prepend PDCP header and append MAC. - EXPECT_TRUE(pdu.prepend(std::array{0x00U, 0x00U})); - EXPECT_TRUE(pdu.append(std::array{0x01, 0x1d, 0x37, 0x38})); + if (!pdu.prepend(std::array{0x00U, 0x00U})) { + return false; + } + if (!pdu.append(std::array{0x01, 0x1d, 0x37, 0x38})) { + return false; + } // Send UL RRC Message to CU-CP. f1ap_message f1ap_ul_rrc_msg = test_helpers::create_ul_rrc_message_transfer(du_ue_id, cu_ue_id, srb_id_t::srb1, std::move(pdu)); get_du(du_idx).push_ul_pdu(f1ap_ul_rrc_msg); + return true; } unsigned du_idx = 0; @@ -154,7 +165,7 @@ TEST_F(cu_cp_reestablishment_test, when_old_ue_does_not_exist_then_reestablishme << "RRC setup should have been sent"; // UE sends RRC Setup Complete - this->ue_sends_rrc_setup_complete(int_to_gnb_du_ue_f1ap_id(1), int_to_gnb_cu_ue_f1ap_id(1)); + ASSERT_TRUE(this->ue_sends_rrc_setup_complete(int_to_gnb_du_ue_f1ap_id(1), int_to_gnb_cu_ue_f1ap_id(1))); // old UE should not be removed. auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); @@ -175,7 +186,7 @@ TEST_F(cu_cp_reestablishment_test, when_old_ue_has_no_ngap_context_then_reestabl ASSERT_EQ(report.ues.size(), 2) << "Old UE should not be removed yet"; // UE sends RRC Setup Complete - this->ue_sends_rrc_setup_complete(int_to_gnb_du_ue_f1ap_id(1), int_to_gnb_cu_ue_f1ap_id(1)); + ASSERT_TRUE(this->ue_sends_rrc_setup_complete(int_to_gnb_du_ue_f1ap_id(1), int_to_gnb_cu_ue_f1ap_id(1))); // Given that the old UE still has no AMF-UE-ID, the CU-CP removes the UE context without sending the // NGAP UE Context Release Request to the AMF. @@ -246,7 +257,7 @@ TEST_F(cu_cp_reestablishment_test, when_old_ue_is_busy_with_a_procedure_then_ree // EVENT: new UE sends RRC Setup Complete and completes fallback procedure. gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(1); - this->ue_sends_rrc_setup_complete(new_du_ue_id, cu_ue_id); + ASSERT_TRUE(this->ue_sends_rrc_setup_complete(new_du_ue_id, cu_ue_id)); // STATUS: NGAP Initial UE Message should be sent for the new UE. ngap_message ngap_pdu; From 54a254e8b9a2141dd40578896dfdeac7e79eb56d Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 18:18:39 +0200 Subject: [PATCH 124/407] Support: Move is_iterable trait to support out of detail --- .../{detail/is_iterable.h => type_traits.h} | 7 ++--- lib/asn1/asn1_diff_utils.h | 26 +++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) rename include/srsran/support/{detail/is_iterable.h => type_traits.h} (86%) diff --git a/include/srsran/support/detail/is_iterable.h b/include/srsran/support/type_traits.h similarity index 86% rename from include/srsran/support/detail/is_iterable.h rename to include/srsran/support/type_traits.h index d9370abd3a..5e8db0d117 100644 --- a/include/srsran/support/detail/is_iterable.h +++ b/include/srsran/support/type_traits.h @@ -15,7 +15,8 @@ namespace srsran { namespace detail { -// To allow ADL with custom begin/end + +// To allow ADL with custom begin/end. using std::begin; using std::end; @@ -33,6 +34,6 @@ std::false_type is_iterable_impl(...); } // namespace detail template -using is_iterable = decltype(detail::is_iterable_impl(0)); +constexpr bool is_iterable = decltype(detail::is_iterable_impl(0))::value; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/asn1/asn1_diff_utils.h b/lib/asn1/asn1_diff_utils.h index bc80504175..eb1657e3b4 100644 --- a/lib/asn1/asn1_diff_utils.h +++ b/lib/asn1/asn1_diff_utils.h @@ -18,8 +18,8 @@ #pragma once #include "srsran/support/async/detail/function_signature.h" -#include "srsran/support/detail/is_iterable.h" #include "srsran/support/srsran_assert.h" +#include "srsran/support/type_traits.h" #include namespace srsran { @@ -121,12 +121,12 @@ void apply_addmodremlist_diff(AddModList& src_and_dest_list, /// \param[in] next_list Next list of objects. /// \param[in] id_func function to extract the ID from an object with type equal to the value_type of \c List. template -std::enable_if_t::value> calculate_addmodremlist_diff(const RemFunctor& rem_func, - const AddFunctor& add_func, - const ModFunctor& mod_func, - const List& prev_list, - const List& next_list, - const GetId& id_func) +std::enable_if_t> calculate_addmodremlist_diff(const RemFunctor& rem_func, + const AddFunctor& add_func, + const ModFunctor& mod_func, + const List& prev_list, + const List& next_list, + const GetId& id_func) { auto id_cmp_op = make_id_comparator(id_func); srsran_sanity_check(std::is_sorted(prev_list.begin(), prev_list.end(), id_cmp_op), "Expected sorted list"); @@ -165,12 +165,12 @@ std::enable_if_t::value> calculate_addmodremlist_dif /// \c toAddModList::value_type. /// \param[in] id_func function to extract the ID from an object with type equal to the value_type of \c List. template -std::enable_if_t::value> calculate_addmodremlist_diff(toAddModList& add_diff_list, - RemoveList& rem_diff_list, - const List& prev_list, - const List& next_list, - const ConvertElem& convert_func, - const GetId& id_func) +std::enable_if_t> calculate_addmodremlist_diff(toAddModList& add_diff_list, + RemoveList& rem_diff_list, + const List& prev_list, + const List& next_list, + const ConvertElem& convert_func, + const GetId& id_func) { if (&prev_list == &next_list) { // No difference because src and target are the same list. Early return. From b01f44da1abe5482832452a2eb2c56c616b700a7 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 5 Aug 2024 17:14:23 +0200 Subject: [PATCH 125/407] du-high: test for reestablishment of DRB1 during Reestablishment --- .../du_ue/du_ue_controller_impl.cpp | 2 +- .../integrationtests/du_high/du_high_test.cpp | 2 +- .../test_utils/du_high_env_simulator.cpp | 27 ++++- .../test_utils/du_high_env_simulator.h | 8 +- .../f1ap/f1ap_test_message_validators.cpp | 8 ++ .../f1ap/f1ap_test_message_validators.h | 2 + .../test_doubles/f1ap/f1ap_test_messages.cpp | 102 ++++++++++++++++++ tests/test_doubles/f1ap/f1ap_test_messages.h | 7 ++ 8 files changed, 153 insertions(+), 5 deletions(-) diff --git a/lib/du_manager/du_ue/du_ue_controller_impl.cpp b/lib/du_manager/du_ue/du_ue_controller_impl.cpp index db9ab396bc..8203d93a21 100644 --- a/lib/du_manager/du_ue/du_ue_controller_impl.cpp +++ b/lib/du_manager/du_ue/du_ue_controller_impl.cpp @@ -256,7 +256,7 @@ async_task du_ue_controller_impl::handle_drb_traffic_stop_request(spansecond->stop(); diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index e386bff7c6..d9f42cd12d 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -275,7 +275,7 @@ TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_then_old_u // Send DL RRC Message Transfer with old gNB-DU-UE-F1AP-ID. rnti_t rnti2 = to_rnti(0x4602); ASSERT_TRUE(add_ue(rnti2)); - ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti)); + ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti, reestablishment_stage::reest_complete)); ASSERT_FALSE(this->run_until( [this, rnti]() { diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 52e8a80220..3455189189 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -286,7 +286,7 @@ bool du_high_env_simulator::run_rrc_setup(rnti_t rnti) return run_msg4_and_await_msg5(u, msg); } -bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti) +bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti, reestablishment_stage stop_at) { auto it = ues.find(rnti); if (it == ues.end()) { @@ -302,12 +302,35 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti } const ue_sim_context& old_u = old_it->second; + // Generate DL RRC Message Transfer (containing RRC Reestablishment) f1ap_message msg = generate_dl_rrc_message_transfer( *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb1, byte_buffer::create({0x1, 0x2, 0x3}).value()); msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id_present = true; msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id = (uint64_t)old_u.du_ue_id.value(); - return run_msg4_and_await_msg5(u, msg); + // Send RRC Reestablishment and await response. + if (not run_msg4_and_await_msg5(u, msg)) { + return false; + } + if (stop_at == reestablishment_stage::reest_complete) { + return true; + } + + // Generate UE Context Modification procedure for DRB Reestablishment. + msg = test_helpers::generate_ue_context_modification_request(*u.du_ue_id, *u.cu_ue_id, {}, {}, {drb_id_t::drb1}); + cu_notifier.last_f1ap_msgs.clear(); + du_hi->get_f1ap_message_handler().handle_message(msg); + bool ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); + if (not ret) { + test_logger.error("rnti={}: F1AP UE Context Modification Request not sent back to the CU-CP", u.rnti); + return false; + } + if (not test_helpers::is_valid_ue_context_modification_response(cu_notifier.last_f1ap_msgs.back())) { + test_logger.error("rnti={}: F1AP UE Context Modification Response sent back to the CU-CP is not valid", u.rnti); + return false; + } + + return true; } bool du_high_env_simulator::run_msg4_and_await_msg5(const ue_sim_context& u, const f1ap_message& msg) diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index f550183cc8..22ec6ff8fd 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -57,7 +57,13 @@ class du_high_env_simulator /// Transfer) until the CU receives the RRC Setup Complete (via UL RRC Message Transfer). bool run_rrc_setup(rnti_t rnti); - bool run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti); + /// Run the RRC Reestablishment procedure for the given RNTI from the moment the CU-CP sends an RRC Reestablishment + /// (via DL RRC Message Transfer) until the CU receives the RRC Reestablishment Complete (via UL RRC Message + /// Transfer). + enum class reestablishment_stage { reest_complete, reconf_complete }; + [[nodiscard]] bool run_rrc_reestablishment(rnti_t rnti, + rnti_t old_rnti, + reestablishment_stage stop_at = reestablishment_stage::reconf_complete); bool run_ue_context_setup(rnti_t rnti); diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp index 0057eae9a5..d8febb9c3a 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp @@ -142,6 +142,14 @@ bool srsran::test_helpers::is_valid_ue_context_modification_request(const f1ap_m return true; } +bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome); + TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_F1AP_ID_UE_CONTEXT_MOD); + TRUE_OR_RETURN(is_packable(msg)); + return true; +} + bool srsran::test_helpers::is_valid_ue_context_release_command(const f1ap_message& msg) { TRUE_OR_RETURN(msg.pdu.type() == asn1::f1ap::f1ap_pdu_c::types_opts::init_msg); diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index 6935778bc5..0968d69a2d 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -44,6 +44,8 @@ bool is_ue_context_setup_response_valid(const f1ap_message& msg); bool is_valid_ue_context_modification_request(const f1ap_message& msg); +bool is_valid_ue_context_modification_response(const f1ap_message& msg); + bool is_valid_ue_context_release_command(const f1ap_message& msg); bool is_valid_paging(const f1ap_message& msg); diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.cpp b/tests/test_doubles/f1ap/f1ap_test_messages.cpp index 2a8676a586..8ebadb8f01 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_messages.cpp @@ -348,6 +348,108 @@ f1ap_message srsran::test_helpers::generate_ue_context_release_complete(gnb_cu_u return ue_ctxt_rel_complete_msg; } +static asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l generate_ul_up_tnl_info_to_be_setup_list_l() +{ + asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l list; + + list.resize(1); + auto& gtp_tun = list[0].ul_up_tnl_info.set_gtp_tunnel(); + auto addr = transport_layer_address::create_from_string("127.0.0.1"); + gtp_tun.transport_layer_address.from_string(addr.to_bitstring()); + gtp_tun.gtp_teid.from_number(1); + + return list; +} + +static asn1::f1ap::drbs_to_be_setup_mod_item_s generate_drb_am_mod_item(drb_id_t drbid) +{ + using namespace asn1::f1ap; + drbs_to_be_setup_mod_item_s drb; + drb.drb_id = drb_id_to_uint(drbid); + drb.qos_info.set_choice_ext().load_info_obj(ASN1_F1AP_ID_DRB_INFO); + auto& drb_info = drb.qos_info.choice_ext()->drb_info(); + drb_info.drb_qos.qos_characteristics.set_non_dyn_5qi().five_qi = 8; + drb_info.drb_qos.ngra_nalloc_retention_prio.prio_level = 1; + drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_cap.value = + pre_emption_cap_opts::shall_not_trigger_pre_emption; + drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_vulnerability.value = + pre_emption_vulnerability_opts::not_pre_emptable; + drb_info.drb_qos.reflective_qos_attribute_present = true; + drb_info.drb_qos.reflective_qos_attribute.value = + qos_flow_level_qos_params_s::reflective_qos_attribute_opts::subject_to; + drb_info.snssai.sst.from_string("01"); + drb_info.snssai.sd.from_string("0027db"); + drb.rlc_mode.value = rlc_mode_opts::rlc_am; + drb.ie_exts_present = true; + drb.ie_exts.dl_pdcp_sn_len_present = true; + drb.ie_exts.dl_pdcp_sn_len = pdcp_sn_len_opts::twelve_bits; + drb.ul_up_tnl_info_to_be_setup_list = generate_ul_up_tnl_info_to_be_setup_list_l(); + return drb; +} + +static asn1::f1ap::drbs_to_be_modified_item_s generate_to_modify_drb_am_mod_item(drb_id_t drbid) +{ + using namespace asn1::f1ap; + + drbs_to_be_modified_item_s drb; + drb.drb_id = drb_id_to_uint(drbid); + drb.ie_exts_present = true; + drb.ie_exts.dl_pdcp_sn_len_present = true; + drb.ie_exts.dl_pdcp_sn_len = pdcp_sn_len_opts::twelve_bits; + drb.ul_up_tnl_info_to_be_setup_list = generate_ul_up_tnl_info_to_be_setup_list_l(); + return drb; +} + +f1ap_message +srsran::test_helpers::generate_ue_context_modification_request(gnb_du_ue_f1ap_id_t du_ue_id, + gnb_cu_ue_f1ap_id_t cu_ue_id, + const std::initializer_list& drbs_to_setup, + const std::initializer_list& drbs_to_mod, + const std::initializer_list& drbs_to_rem) +{ + using namespace asn1::f1ap; + f1ap_message msg; + + msg.pdu.set_init_msg().load_info_obj(ASN1_F1AP_ID_UE_CONTEXT_MOD); + ue_context_mod_request_s& dl_msg = msg.pdu.init_msg().value.ue_context_mod_request(); + dl_msg->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(cu_ue_id); + dl_msg->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(du_ue_id); + + dl_msg->drbs_to_be_setup_mod_list_present = drbs_to_setup.size() > 0; + dl_msg->drbs_to_be_setup_mod_list.resize(drbs_to_setup.size()); + unsigned count = 0; + for (drb_id_t drbid : drbs_to_setup) { + dl_msg->drbs_to_be_setup_mod_list[count].load_info_obj(ASN1_F1AP_ID_DRBS_SETUP_MOD_ITEM); + dl_msg->drbs_to_be_setup_mod_list[count]->drbs_to_be_setup_mod_item() = generate_drb_am_mod_item(drbid); + ++count; + } + + dl_msg->drbs_to_be_released_list_present = drbs_to_rem.size() > 0; + dl_msg->drbs_to_be_released_list.resize(drbs_to_rem.size()); + count = 0; + for (drb_id_t drbid : drbs_to_rem) { + dl_msg->drbs_to_be_released_list[count].load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_RELEASED_ITEM); + dl_msg->drbs_to_be_released_list[count]->drbs_to_be_released_item().drb_id = drb_id_to_uint(drbid); + ++count; + } + + dl_msg->drbs_to_be_modified_list_present = drbs_to_mod.size() > 0; + dl_msg->drbs_to_be_modified_list.resize(drbs_to_mod.size()); + count = 0; + for (drb_id_t drbid : drbs_to_mod) { + dl_msg->drbs_to_be_modified_list[count].load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_MODIFIED_ITEM); + dl_msg->drbs_to_be_modified_list[count]->drbs_to_be_modified_item() = generate_to_modify_drb_am_mod_item(drbid); + ++count; + } + + dl_msg->rrc_container_present = true; + report_fatal_error_if_not( + dl_msg->rrc_container.append(test_rgen::random_vector(test_rgen::uniform_int(1, 100))), + "Failed to allocate RRC container"); + + return msg; +} + f1ap_message srsran::test_helpers::generate_ue_context_modification_response(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id, rnti_t crnti) diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.h b/tests/test_doubles/f1ap/f1ap_test_messages.h index 301ef3b594..0d5c5ae09c 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.h +++ b/tests/test_doubles/f1ap/f1ap_test_messages.h @@ -85,6 +85,13 @@ f1ap_message generate_ue_context_release_request(gnb_cu_ue_f1ap_id_t cu_ue_id, g f1ap_message generate_ue_context_release_complete(const f1ap_message& ue_ctxt_release_cmd); f1ap_message generate_ue_context_release_complete(gnb_cu_ue_f1ap_id_t cu_ue_id, gnb_du_ue_f1ap_id_t du_ue_id); +/// \brief Generates dummy F1AP UE CONTEXT MODIFICATION REQUEST message. +f1ap_message generate_ue_context_modification_request(gnb_du_ue_f1ap_id_t du_ue_id, + gnb_cu_ue_f1ap_id_t cu_ue_id, + const std::initializer_list& drbs_to_setup = {}, + const std::initializer_list& drbs_to_mod = {}, + const std::initializer_list& drbs_to_rem = {}); + /// \brief Generates dummy F1AP UE CONTEXT MODIFICATION RESPONSE message. f1ap_message generate_ue_context_modification_response(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id, rnti_t rnti); From 6afccf047736467164417811de54e4733a0581a1 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 5 Aug 2024 18:02:10 +0200 Subject: [PATCH 126/407] du-high: fix reestablishment test --- .../du_high/test_utils/du_high_env_simulator.cpp | 2 +- tests/test_doubles/f1ap/f1ap_test_messages.cpp | 9 ++++----- tests/test_doubles/f1ap/f1ap_test_messages.h | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 3455189189..5844d76f3c 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -317,7 +317,7 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti } // Generate UE Context Modification procedure for DRB Reestablishment. - msg = test_helpers::generate_ue_context_modification_request(*u.du_ue_id, *u.cu_ue_id, {}, {}, {drb_id_t::drb1}); + msg = test_helpers::generate_ue_context_modification_request(*u.du_ue_id, *u.cu_ue_id, {}, {drb_id_t::drb1}, {}); cu_notifier.last_f1ap_msgs.clear(); du_hi->get_f1ap_message_handler().handle_message(msg); bool ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.cpp b/tests/test_doubles/f1ap/f1ap_test_messages.cpp index 8ebadb8f01..f575490467 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_messages.cpp @@ -405,7 +405,8 @@ srsran::test_helpers::generate_ue_context_modification_request(gnb_du_ue_f1ap_id gnb_cu_ue_f1ap_id_t cu_ue_id, const std::initializer_list& drbs_to_setup, const std::initializer_list& drbs_to_mod, - const std::initializer_list& drbs_to_rem) + const std::initializer_list& drbs_to_rem, + byte_buffer rrc_container) { using namespace asn1::f1ap; f1ap_message msg; @@ -442,10 +443,8 @@ srsran::test_helpers::generate_ue_context_modification_request(gnb_du_ue_f1ap_id ++count; } - dl_msg->rrc_container_present = true; - report_fatal_error_if_not( - dl_msg->rrc_container.append(test_rgen::random_vector(test_rgen::uniform_int(1, 100))), - "Failed to allocate RRC container"); + dl_msg->rrc_container_present = not rrc_container.empty(); + dl_msg->rrc_container = rrc_container.copy(); return msg; } diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.h b/tests/test_doubles/f1ap/f1ap_test_messages.h index 0d5c5ae09c..96f8b6efd0 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.h +++ b/tests/test_doubles/f1ap/f1ap_test_messages.h @@ -90,7 +90,8 @@ f1ap_message generate_ue_context_modification_request(gnb_du_ue_f1ap_id_t gnb_cu_ue_f1ap_id_t cu_ue_id, const std::initializer_list& drbs_to_setup = {}, const std::initializer_list& drbs_to_mod = {}, - const std::initializer_list& drbs_to_rem = {}); + const std::initializer_list& drbs_to_rem = {}, + byte_buffer rrc_container = {}); /// \brief Generates dummy F1AP UE CONTEXT MODIFICATION RESPONSE message. f1ap_message From 99a2ccd5a60363d66513ee3a60ab98f01cb1f0ef Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 5 Aug 2024 18:23:18 +0200 Subject: [PATCH 127/407] du-high: make f1u du bearers indexable by ue index and drb id --- .../du_high/du_high_many_cells_test.cpp | 4 ++-- .../integrationtests/du_high/du_high_test.cpp | 8 ++++---- tests/test_doubles/f1u/dummy_f1u_du_gateway.h | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/integrationtests/du_high/du_high_many_cells_test.cpp b/tests/integrationtests/du_high/du_high_many_cells_test.cpp index a84386b8f3..dfd3e96d8c 100644 --- a/tests/integrationtests/du_high/du_high_many_cells_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_cells_test.cpp @@ -114,10 +114,10 @@ TEST_P(du_high_many_cells_tester, when_ue_created_in_multiple_cells_then_traffic // Forward several DRB PDUs to all UEs. const unsigned nof_pdcp_pdus = 100, pdcp_pdu_size = 128; for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { - for (unsigned c = 0; c != GetParam().nof_cells; ++c) { + for (auto& bearer : cu_up_sim.bearers) { nru_dl_message f1u_pdu{ .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; - cu_up_sim.created_du_notifs[c]->on_new_pdu(f1u_pdu); + bearer.second.rx_notifier->on_new_pdu(f1u_pdu); } } diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index d9f42cd12d..84b26ceca6 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -81,7 +81,7 @@ TEST_F(du_high_tester, when_ue_context_setup_completes_then_drb_is_active) for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { nru_dl_message f1u_pdu{ .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; - cu_up_sim.created_du_notifs[0]->on_new_pdu(f1u_pdu); + cu_up_sim.bearers.begin()->second.rx_notifier->on_new_pdu(f1u_pdu); } // Ensure DRB is active by verifying that the DRB PDUs are scheduled. @@ -141,7 +141,7 @@ TEST_F(du_high_tester, when_ue_context_setup_release_starts_then_drb_activity_st for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { nru_dl_message f1u_pdu{ .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; - cu_up_sim.created_du_notifs[0]->on_new_pdu(f1u_pdu); + cu_up_sim.bearers.begin()->second.rx_notifier->on_new_pdu(f1u_pdu); } // DU receives F1AP UE Context Release Command. @@ -230,7 +230,7 @@ TEST_F(du_high_tester, when_ue_context_modification_with_rem_drbs_is_received_th for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { nru_dl_message f1u_pdu{ .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; - cu_up_sim.created_du_notifs[0]->on_new_pdu(f1u_pdu); + cu_up_sim.bearers.begin()->second.rx_notifier->on_new_pdu(f1u_pdu); } // DU receives F1AP UE Context Modification Command. @@ -269,7 +269,7 @@ TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_then_old_u for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { nru_dl_message f1u_pdu{ .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; - cu_up_sim.created_du_notifs[0]->on_new_pdu(f1u_pdu); + cu_up_sim.bearers.begin()->second.rx_notifier->on_new_pdu(f1u_pdu); } // Send DL RRC Message Transfer with old gNB-DU-UE-F1AP-ID. diff --git a/tests/test_doubles/f1u/dummy_f1u_du_gateway.h b/tests/test_doubles/f1u/dummy_f1u_du_gateway.h index 3073c87124..07fcfd0d3e 100644 --- a/tests/test_doubles/f1u/dummy_f1u_du_gateway.h +++ b/tests/test_doubles/f1u/dummy_f1u_du_gateway.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/f1u/du/f1u_gateway.h" +#include namespace srsran { namespace srs_du { @@ -35,8 +36,11 @@ class f1u_gw_dummy_bearer : public f1u_du_gateway_bearer class cu_up_simulator : public f1u_du_gateway { public: - std::vector created_du_notifs; - std::vector registered_dl_tnls; + struct bearer_context_t { + srs_du::f1u_du_gateway_bearer_rx_notifier* rx_notifier; + up_transport_layer_info dl_tnl_info; + }; + std::map, bearer_context_t> bearers; std::optional last_ue_idx; std::optional last_drb_id; @@ -50,8 +54,7 @@ class cu_up_simulator : public f1u_du_gateway timer_factory timers, task_executor& ue_executor) override { - created_du_notifs.push_back(&du_rx); - registered_dl_tnls.push_back(dl_up_tnl_info); + bearers.insert(std::make_pair(std::make_pair(ue_index, drb_id), bearer_context_t{&du_rx, dl_up_tnl_info})); last_ue_idx = ue_index; last_drb_id = drb_id; auto bearer = std::make_unique(); @@ -60,10 +63,9 @@ class cu_up_simulator : public f1u_du_gateway void remove_du_bearer(const up_transport_layer_info& dl_tnl) override { - for (unsigned i = 0; i != registered_dl_tnls.size(); ++i) { - if (dl_tnl == registered_dl_tnls[i]) { - registered_dl_tnls.erase(registered_dl_tnls.begin() + i); - created_du_notifs.erase(created_du_notifs.begin() + i); + for (const auto& [key, value] : bearers) { + if (value.dl_tnl_info == dl_tnl) { + bearers.erase(key); break; } } From 10124e3785c1347b97638550409cfd0d0d4387d9 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 6 Aug 2024 11:06:59 +0200 Subject: [PATCH 128/407] du-high: retrieve old UE context during reestablishment --- lib/du_manager/du_ue/du_ue.h | 6 +- lib/du_manager/du_ue/du_ue_manager.cpp | 8 ++- .../procedures/ue_configuration_procedure.cpp | 57 +++++++++++++++++-- .../du_ran_resource_manager.h | 15 +++-- .../du_ran_resource_manager_impl.cpp | 40 ++++++++++--- .../du_ran_resource_manager_impl.h | 13 +++-- lib/f1ap/du/f1ap_du_impl.cpp | 3 + .../integrationtests/du_high/du_high_test.cpp | 16 +++++- .../test_utils/du_high_env_simulator.cpp | 4 ++ .../f1ap/f1ap_test_message_validators.cpp | 16 ++++++ .../f1ap/f1ap_test_message_validators.h | 1 + .../du_manager/du_manager_test_helpers.cpp | 16 +++++- .../du_manager/du_manager_test_helpers.h | 6 +- .../du_manager/du_ue/ue_manager_test.cpp | 2 +- .../procedures/ue_configuration_test.cpp | 5 +- 15 files changed, 173 insertions(+), 35 deletions(-) diff --git a/lib/du_manager/du_ue/du_ue.h b/lib/du_manager/du_ue/du_ue.h index 197c468236..b64c83637f 100644 --- a/lib/du_manager/du_ue/du_ue.h +++ b/lib/du_manager/du_ue/du_ue.h @@ -96,9 +96,9 @@ class du_ue : public du_ue_context, public du_ue_controller /// \brief Radio access network resources currently allocated to the UE. ue_ran_resource_configurator resources; - /// \brief Determines whether this UE is running the RRC Reestablishment procedure. - // TODO: refactor. - bool reestablishment_pending = false; + /// \brief Determines whether this UE is running the RRC Reestablishment procedure and which context was retrieved + /// from the old UE. + std::unique_ptr reestablished_cfg_pending; }; } // namespace srs_du diff --git a/lib/du_manager/du_ue/du_ue_manager.cpp b/lib/du_manager/du_ue/du_ue_manager.cpp index 186a8a059a..a7a84c8b87 100644 --- a/lib/du_manager/du_ue/du_ue_manager.cpp +++ b/lib/du_manager/du_ue/du_ue_manager.cpp @@ -111,11 +111,13 @@ async_task du_ue_manager::handle_ue_deactivation_request(du_ue_index_t ue_ void du_ue_manager::handle_reestablishment_request(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) { srsran_assert(ue_db.contains(new_ue_index), "Invalid UE index={}", new_ue_index); - srsran_assert(find_ue(old_ue_index) != nullptr, "Invalid UE index={}", old_ue_index); + auto old_ue_it = find_ue(old_ue_index); + srsran_assert(old_ue_it != nullptr, "Invalid UE index={}", old_ue_index); auto& new_ue = ue_db[new_ue_index]; - // Reset the cellGroupConfig of the new UE context, so that previous changes are included in the next UEContextUpdate. - new_ue.reestablishment_pending = true; + // Retrieve the old UE context for the RRC connection reestablishment procedure, as defined in TS 48.473, 8.4.2.2 and + // TS 38.401. + new_ue.reestablished_cfg_pending = std::make_unique(old_ue_it->resources.value()); // Delete the old UE context. schedule_async_task(old_ue_index, handle_ue_delete_request(f1ap_ue_delete_request{old_ue_index})); diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index ea4d094687..cd569b35b1 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -44,7 +44,7 @@ void ue_configuration_procedure::operator()(coro_contextresources.value(); - if (ue->resources.update(ue->pcell_index, request).release_required()) { + if (ue->resources.update(ue->pcell_index, request, ue->reestablished_cfg_pending.get()).release_required()) { proc_logger.log_proc_failure("Failed to allocate DU UE resources"); CORO_EARLY_RETURN(make_ue_config_failure()); } @@ -181,7 +181,56 @@ void ue_configuration_procedure::update_ue_context() } ue->bearers.add_drb(std::move(drb)); } - // TODO: Support DRB modifications. + + // > Modify existing UE DRBs. + for (const f1ap_drb_to_modify& drbtomod : request.drbs_to_mod) { + if (drbtomod.uluptnl_info_list.empty()) { + proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtomod.drb_id); + continue; + } + // Find the RLC configuration for this DRB. + auto it = std::find_if(ue->resources->rlc_bearers.begin(), + ue->resources->rlc_bearers.end(), + [&drbtomod](const rlc_bearer_config& e) { return e.drb_id == drbtomod.drb_id; }); + srsran_assert(it != ue->resources->rlc_bearers.end(), "The bearer config should be created at this point"); + + auto drb_it = ue->bearers.drbs().find(drbtomod.drb_id); + if (drb_it == ue->bearers.drbs().end()) { + // It's a DRB modification during RRC Reestablishment. We need to create a new DRB instance. + + // Find the F1-U configuration for this DRB. + // TODO: Retrieve old UE context for QoS. The way it is now, the old UE QoS has already been lost at this point. + auto f1u_cfg_it = std::find_if(du_params.ran.qos.begin(), du_params.ran.qos.end(), [&it](const auto& p) { + return it->rlc_cfg.mode == p.second.rlc.mode; + }); + srsran_assert(f1u_cfg_it != du_params.ran.qos.end(), "Undefined F1-U bearer config"); + + // Create DU DRB instance. + std::unique_ptr drb = + create_drb(drb_creation_info{ue->ue_index, + ue->pcell_index, + drbtomod.drb_id, + it->lcid, + it->rlc_cfg, + it->mac_cfg, + f1u_cfg_it->second.f1u, + drbtomod.uluptnl_info_list, + ue_mng.get_f1u_teid_pool(), + du_params, + ue->get_rlc_rlf_notifier(), + get_5qi_to_qos_characteristics_mapping(f1u_cfg_it->first), + std::nullopt, + {}}); + if (drb == nullptr) { + proc_logger.log_proc_warning("Failed to create {}. Cause: Failed to allocate DU UE resources.", + drbtomod.drb_id); + continue; + } + ue->bearers.add_drb(std::move(drb)); + } else { + // TODO: Support DRB modifications. + } + } } void ue_configuration_procedure::clear_old_ue_context() @@ -275,10 +324,10 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo // > Calculate ASN.1 CellGroupConfig to be sent in DU-to-CU container. asn1::rrc_nr::cell_group_cfg_s asn1_cell_group; - if (ue->reestablishment_pending) { + if (ue->reestablished_cfg_pending != nullptr) { // In case of reestablishment, we send the full configuration to the UE but without an SRB1 and with SRB2 and DRBs // set to "RLCReestablish". - ue->reestablishment_pending = false; + ue->reestablished_cfg_pending = nullptr; calculate_cell_group_config_diff(asn1_cell_group, cell_group_config{}, *ue->resources); auto it = std::find_if(asn1_cell_group.rlc_bearer_to_add_mod_list.begin(), diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h index 2acf908bf5..f0bc586ce5 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h @@ -37,10 +37,11 @@ class ue_ran_resource_configurator /// \brief Interface used to update the UE Resources on Reconfiguration and return the resources back to the pool, /// on UE deletion. struct resource_updater { - virtual ~resource_updater() = default; + virtual ~resource_updater() = default; virtual du_ue_resource_update_response update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req) = 0; - virtual const cell_group_config& get() = 0; + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context) = 0; + virtual const cell_group_config& get() = 0; }; explicit ue_ran_resource_configurator(std::unique_ptr ue_res_, std::string error = {}) : @@ -54,10 +55,14 @@ class ue_ran_resource_configurator /// /// \param pcell_index DU Cell Index of the UE's PCell. /// \param upd_req UE Context Update Request for a given UE. + /// \param reestablished_context Optional parameter to provide the previous context of the UE, in case of an + /// RRC Reestablishment. /// \return Outcome of the configuration. - du_ue_resource_update_response update(du_cell_index_t pcell_index, const f1ap_ue_context_update_request& upd_req) + du_ue_resource_update_response update(du_cell_index_t pcell_index, + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context = nullptr) { - return ue_res_impl->update(pcell_index, upd_req); + return ue_res_impl->update(pcell_index, upd_req, reestablished_context); } /// \brief Checks whether the UE resources have been correctly allocated. diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index 85739131f2..dfb2efeaa4 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -57,9 +57,10 @@ du_ue_ran_resource_updater_impl::~du_ue_ran_resource_updater_impl() } du_ue_resource_update_response du_ue_ran_resource_updater_impl::update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req) + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context) { - return parent->update_context(ue_index, pcell_index, upd_req); + return parent->update_context(ue_index, pcell_index, upd_req, reestablished_context); } /////////////////////////// @@ -69,7 +70,6 @@ du_ran_resource_manager_impl::du_ran_resource_manager_impl(span& srbs_, const std::map& qos_) : cell_cfg_list(cell_cfg_list_), - sched_cfg(scheduler_cfg), srb_config(srbs_), qos_config(qos_), logger(srslog::fetch_basic_logger("DU-MNG")), @@ -141,10 +141,25 @@ static error_type validate_drb_setup_request(const f1ap_drb_to_setu return {}; } +static void reestablish_context(cell_group_config& new_ue_cfg, const cell_group_config& old_ue_cfg) +{ + for (const rlc_bearer_config& old_bearer : old_ue_cfg.rlc_bearers) { + auto it = std::find_if( + new_ue_cfg.rlc_bearers.begin(), new_ue_cfg.rlc_bearers.end(), [&old_bearer](const rlc_bearer_config& item) { + return item.drb_id == old_bearer.drb_id and (item.drb_id.has_value() or (item.lcid == old_bearer.lcid)); + }); + if (it == new_ue_cfg.rlc_bearers.end()) { + // Bearer not found in new context. Add it. + new_ue_cfg.rlc_bearers.push_back(old_bearer); + } + } +} + du_ue_resource_update_response du_ran_resource_manager_impl::update_context(du_ue_index_t ue_index, du_cell_index_t pcell_idx, - const f1ap_ue_context_update_request& upd_req) + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context) { srsran_assert(ue_res_pool.contains(ue_index), "This function should only be called for an already allocated UE"); cell_group_config& ue_mcg = ue_res_pool[ue_index].cg_cfg; @@ -167,12 +182,22 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } + // > In case of RRC Reestablishment, retrieve old DRB context, to be considered in the config update. + if (reestablished_context != nullptr) { + reestablish_context(ue_mcg, *reestablished_context); + } + // > Deallocate removed SRBs / DRBs. for (drb_id_t drb_id : upd_req.drbs_to_rem) { auto it = std::find_if(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [drb_id](const rlc_bearer_config& b) { return b.drb_id == drb_id; }); - ue_mcg.rlc_bearers.erase(it); + if (it != ue_mcg.rlc_bearers.end()) { + ue_mcg.rlc_bearers.erase(it); + continue; + } else { + logger.warning("Failed to release {}. Cause: DRB not found", drb_id); + } } // > Allocate new SRBs. @@ -237,6 +262,7 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t break; } } + // > Modify existing DRBs. for (const f1ap_drb_to_modify& drb : upd_req.drbs_to_mod) { auto res = validate_drb_modification_request(drb, ue_mcg.rlc_bearers); @@ -244,9 +270,9 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t resp.failed_drbs.push_back(drb.drb_id); continue; } - // TODO: Support DRB modification. } - // >> Sort by LCID. + + // > Sort bearers by LCID. std::sort(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [](const auto& lhs, const auto& rhs) { return lhs.lcid < rhs.lcid; }); diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h index 54ddb45c14..c16306a462 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h @@ -32,7 +32,8 @@ class du_ue_ran_resource_updater_impl final : public ue_ran_resource_configurato ~du_ue_ran_resource_updater_impl() override; du_ue_resource_update_response update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req) override; + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context) override; const cell_group_config& get() override { return *cell_grp; } @@ -64,9 +65,13 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager /// \param ue_index Id of the UE whose context is being updated. /// \param pcell_idx DU Cell Id of the UE's PCell. /// \param upd_req UE Context Update Request received by the F1AP-DU from the CU. + /// \param reestablished_context Optional parameter to provide the previous context of the UE, in case of an RRC + /// Reestablishment. /// \return Result of the context update. - du_ue_resource_update_response - update_context(du_ue_index_t ue_index, du_cell_index_t pcell_idx, const f1ap_ue_context_update_request& upd_req); + du_ue_resource_update_response update_context(du_ue_index_t ue_index, + du_cell_index_t pcell_idx, + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context); /// \brief Deallocates the RAN resources taken by the UE, so that they can be used by future UEs. /// @@ -77,10 +82,8 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager error_type allocate_cell_resources(du_ue_index_t ue_index, du_cell_index_t cell_index, serv_cell_index_t serv_cell_index); void deallocate_cell_resources(du_ue_index_t ue_index, serv_cell_index_t serv_cell_index); - void modify_rlc_for_ntn(cell_group_config& ue_mcg); span cell_cfg_list; - const scheduler_expert_config& sched_cfg; const std::map& srb_config; const std::map& qos_config; srslog::basic_logger& logger; diff --git a/lib/f1ap/du/f1ap_du_impl.cpp b/lib/f1ap/du/f1ap_du_impl.cpp index 486cb7e749..1ba047f263 100644 --- a/lib/f1ap/du/f1ap_du_impl.cpp +++ b/lib/f1ap/du/f1ap_du_impl.cpp @@ -224,6 +224,9 @@ void f1ap_du_impl::handle_dl_rrc_message_transfer(const asn1::f1ap::dl_rrc_msg_t } if (msg->old_gnb_du_ue_f1ap_id_present) { + // [TS38.473, 8.4.2.2] The DL RRC MESSAGE TRANSFER message shall include, if available, the old gNB-DU UE F1AP ID + // IE so that the gNB-DU can retrieve the existing UE context in RRC connection reestablishment procedure, as + // defined in TS 38.401 [4]. // [TS38.473, 8.4.2.2] If the gNB-DU identifies the UE-associated logical F1-connection by the gNB-DU UE F1AP ID IE // in the DL RRC MESSAGE TRANSFER message and the old gNB-DU UE F1AP ID IE is included, it shall release the old // gNB-DU UE F1AP ID and the related configurations associated with the old gNB-DU UE F1AP ID. diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index 84b26ceca6..46148be728 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -288,6 +288,20 @@ TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_then_old_u 100)); } +TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_then_drbs_are_reestablished) +{ + // Create UE1. + rnti_t rnti1 = to_rnti(0x4601); + ASSERT_TRUE(add_ue(rnti1)); + ASSERT_TRUE(run_rrc_setup(rnti1)); + ASSERT_TRUE(run_ue_context_setup(rnti1)); + + // Run Reestablishment + rnti_t rnti2 = to_rnti(0x4602); + ASSERT_TRUE(add_ue(rnti2)); + ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti1)); +} + TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_but_same_cu_ue_f1ap_id_then_cu_ue_f1ap_id_is_reused) { @@ -297,7 +311,7 @@ TEST_F(du_high_tester, ASSERT_TRUE(run_rrc_setup(rnti1)); ASSERT_TRUE(run_ue_context_setup(rnti1)); - // Send DL RRC Message Transfer with old gNB-DU-UE-F1AP-ID and same gNB-CU-UE-F1AP-ID. + // Run Reestablishment, keeping the same gNB-CU-UE-F1AP-ID. this->next_cu_ue_id--; rnti_t rnti2 = to_rnti(0x4602); ASSERT_TRUE(add_ue(rnti2)); diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 5844d76f3c..4b7f738fb5 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -329,6 +329,10 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti test_logger.error("rnti={}: F1AP UE Context Modification Response sent back to the CU-CP is not valid", u.rnti); return false; } + const asn1::f1ap::ue_context_mod_resp_s& resp = + cu_notifier.last_f1ap_msgs.back().pdu.successful_outcome().value.ue_context_mod_resp(); + EXPECT_TRUE(resp->drbs_modified_list_present); + EXPECT_FALSE(resp->drbs_failed_to_be_modified_list_present); return true; } diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp index d8febb9c3a..d957f66f6b 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp @@ -150,6 +150,22 @@ bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_ return true; } +bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_message& resp_msg, + const f1ap_message& req_msg) +{ + TRUE_OR_RETURN(is_valid_ue_context_modification_request(req_msg)); + TRUE_OR_RETURN(is_valid_ue_context_modification_response(resp_msg)); + + const asn1::f1ap::ue_context_mod_request_s& mod_req = req_msg.pdu.init_msg().value.ue_context_mod_request(); + const asn1::f1ap::ue_context_mod_resp_s& mod_resp = req_msg.pdu.successful_outcome().value.ue_context_mod_resp(); + TRUE_OR_RETURN(mod_req->drbs_to_be_setup_mod_list.size() == + mod_resp->drbs_setup_mod_list.size() + mod_resp->drbs_failed_to_be_setup_mod_list.size()); + TRUE_OR_RETURN(mod_req->drbs_to_be_modified_list.size() == + mod_resp->drbs_modified_list.size() + mod_resp->drbs_failed_to_be_modified_list.size()); + + return true; +} + bool srsran::test_helpers::is_valid_ue_context_release_command(const f1ap_message& msg) { TRUE_OR_RETURN(msg.pdu.type() == asn1::f1ap::f1ap_pdu_c::types_opts::init_msg); diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index 0968d69a2d..35c8031822 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -45,6 +45,7 @@ bool is_ue_context_setup_response_valid(const f1ap_message& msg); bool is_valid_ue_context_modification_request(const f1ap_message& msg); bool is_valid_ue_context_modification_response(const f1ap_message& msg); +bool is_valid_ue_context_modification_response(const f1ap_message& resp_msg, const f1ap_message& req_msg); bool is_valid_ue_context_release_command(const f1ap_message& msg); diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index 658685e419..a7c9375ed4 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -42,7 +42,8 @@ dummy_ue_resource_configurator_factory::dummy_resource_updater::~dummy_resource_ du_ue_resource_update_response dummy_ue_resource_configurator_factory::dummy_resource_updater::update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req) + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context) { parent.ue_resource_pool[ue_index] = parent.next_context_update_result; return du_ue_resource_update_response{}; @@ -72,7 +73,8 @@ dummy_ue_resource_configurator_factory::create_ue_resource_configurator(du_ue_in f1ap_ue_context_update_request srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t ue_idx, std::initializer_list srbs_to_addmod, - std::initializer_list drbs_to_addmod) + std::initializer_list drbs_to_add, + std::initializer_list drbs_to_mod) { f1ap_ue_context_update_request req; @@ -84,7 +86,7 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t req.srbs_to_setup.back() = srb_id; } - for (drb_id_t drb_id : drbs_to_addmod) { + for (drb_id_t drb_id : drbs_to_add) { req.drbs_to_setup.emplace_back(); req.drbs_to_setup.back().drb_id = drb_id; req.drbs_to_setup.back().mode = rlc_mode::am; @@ -94,6 +96,14 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); } + for (drb_id_t drb_id : drbs_to_mod) { + req.drbs_to_mod.emplace_back(); + req.drbs_to_mod.back().drb_id = drb_id; + req.drbs_to_mod.back().uluptnl_info_list.resize(1); + req.drbs_to_mod.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); + req.drbs_to_mod.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); + } + return req; } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index efdc27efa8..c54ce58516 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -284,7 +284,8 @@ class dummy_ue_resource_configurator_factory : public du_ran_resource_manager dummy_resource_updater(dummy_ue_resource_configurator_factory& parent_, du_ue_index_t ue_index_); ~dummy_resource_updater(); du_ue_resource_update_response update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req) override; + const f1ap_ue_context_update_request& upd_req, + const cell_group_config* reestablished_context) override; const cell_group_config& get() override; du_ue_index_t ue_index; @@ -305,7 +306,8 @@ class dummy_ue_resource_configurator_factory : public du_ran_resource_manager f1ap_ue_context_update_request create_f1ap_ue_context_update_request(du_ue_index_t ue_idx, std::initializer_list srbs_to_addmod, - std::initializer_list drbs_to_addmod); + std::initializer_list drbs_to_add, + std::initializer_list drbs_to_mod = {}); class du_manager_test_bench { diff --git a/tests/unittests/du_manager/du_ue/ue_manager_test.cpp b/tests/unittests/du_manager/du_ue/ue_manager_test.cpp index 29d1724997..2b77864c3b 100644 --- a/tests/unittests/du_manager/du_ue/ue_manager_test.cpp +++ b/tests/unittests/du_manager/du_ue/ue_manager_test.cpp @@ -35,7 +35,7 @@ class du_ue_manager_tester : public ::testing::Test f1ap_dummy.next_ue_create_response.result = true; f1ap_dummy.next_ue_create_response.f1c_bearers_added.resize(2); } - ~du_ue_manager_tester() { srslog::flush(); } + ~du_ue_manager_tester() override { srslog::flush(); } ul_ccch_indication_message create_ul_ccch_message(rnti_t rnti) { diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 99da349be2..141a3383c4 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -380,7 +380,10 @@ TEST_F(ue_config_tester, when_reestablishment_is_signalled_then_bearers_are_marked_as_reestablishRLC_and_cell_config_are_sent) { // Mark UE as reestablishing. - test_ue->reestablishment_pending = true; + test_ue->reestablished_cfg_pending = std::make_unique(); + test_ue->reestablished_cfg_pending->rlc_bearers.emplace_back(); + test_ue->reestablished_cfg_pending->rlc_bearers.back().lcid = LCID_MIN_DRB; + test_ue->reestablished_cfg_pending->rlc_bearers.back().drb_id = drb_id_t::drb1; // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = From 42be27441397c860bdfbcdc215f324cafbc42a14 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 6 Aug 2024 13:39:14 +0200 Subject: [PATCH 129/407] du-high: fix ue_config_update test --- .../du_manager_procedure_test_helpers.cpp | 7 +++++++ .../procedures/ue_configuration_test.cpp | 19 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 677b3eb73b..61ddbe4783 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -89,6 +89,13 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); } + for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { + cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); + cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; + cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); + cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + } for (drb_id_t drb_id : req.drbs_to_rem) { auto it = std::find_if(cell_res_alloc.next_context_update_result.rlc_bearers.begin(), cell_res_alloc.next_context_update_result.rlc_bearers.end(), diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 141a3383c4..74bae84aa7 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -78,7 +78,8 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test } } - ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), req.srbs_to_setup.size() + req.drbs_to_setup.size()); + ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), + req.srbs_to_setup.size() + req.drbs_to_setup.size() + req.drbs_to_mod.size()); for (srb_id_t srb_id : req.srbs_to_setup) { auto srb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), @@ -100,6 +101,20 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test } } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { + auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), + cell_group.rlc_bearer_to_add_mod_list.end(), + [&drb](const auto& b) { + return b.served_radio_bearer.type().value == + asn1::rrc_nr::rlc_bearer_cfg_s::served_radio_bearer_c_::types::drb_id and + b.served_radio_bearer.drb_id() == drb_id_to_uint(drb.drb_id); + }); + ASSERT_NE(drb_it, cell_group.rlc_bearer_to_add_mod_list.end()); + ASSERT_FALSE(is_srb(uint_to_lcid(drb_it->lc_ch_id))); + ASSERT_TRUE(drb_it->mac_lc_ch_cfg_present); + ASSERT_TRUE(drb_it->rlc_cfg_present); + ASSERT_FALSE(drb_it->reestablish_rlc_present); + } + for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), [&drb](const auto& b) { @@ -387,7 +402,7 @@ TEST_F(ue_config_tester, // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = - create_f1ap_ue_context_update_request(test_ue->ue_index, {srb_id_t::srb2}, {drb_id_t::drb1}); + create_f1ap_ue_context_update_request(test_ue->ue_index, {srb_id_t::srb2}, {}, {drb_id_t::drb1}); f1ap_ue_context_update_response res = this->configure_ue(req); ASSERT_TRUE(res.result); ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, true, true)); From 5ac290f91b50d8dd7e858c0a5622c51d33d285d2 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 6 Aug 2024 15:17:11 +0200 Subject: [PATCH 130/407] du-high: extend f1ap message validators for the case of rrc reestablishment --- .../srsran/f1ap/common/ue_context_config.h | 2 + .../procedures/ue_configuration_procedure.cpp | 1 + lib/f1ap/common/asn1_helpers.cpp | 5 +++ .../test_utils/du_high_env_simulator.cpp | 4 +- .../f1ap/f1ap_test_message_validators.cpp | 41 ++++++++++++++++--- .../f1ap/f1ap_test_message_validators.h | 8 +++- 6 files changed, 51 insertions(+), 10 deletions(-) diff --git a/include/srsran/f1ap/common/ue_context_config.h b/include/srsran/f1ap/common/ue_context_config.h index 4d4af6b42a..e37432db4c 100644 --- a/include/srsran/f1ap/common/ue_context_config.h +++ b/include/srsran/f1ap/common/ue_context_config.h @@ -84,6 +84,8 @@ struct f1ap_drb_setupmod { std::optional lcid; /// DL Transport layer info for the given DRB. std::vector dluptnl_info_list; + /// Indicates whether the RLC has been reestablished. + bool rlc_reestablished = false; }; /// Parameters of a failed DRB setup/modify in the DU UE context. diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index cd569b35b1..bc65c371e9 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -320,6 +320,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo f1ap_drb_setupmod& drb_mod = resp.drbs_mod.back(); drb_mod.drb_id = drb_modified.drb_id; drb_mod.dluptnl_info_list = drb_modified.dluptnl_info_list; + drb_mod.rlc_reestablished = ue->reestablished_cfg_pending != nullptr; } // > Calculate ASN.1 CellGroupConfig to be sent in DU-to-CU container. diff --git a/lib/f1ap/common/asn1_helpers.cpp b/lib/f1ap/common/asn1_helpers.cpp index 1ba358b48e..daf6837b66 100644 --- a/lib/f1ap/common/asn1_helpers.cpp +++ b/lib/f1ap/common/asn1_helpers.cpp @@ -123,6 +123,11 @@ asn1::f1ap::drbs_modified_list_l srsran::make_drbs_modified_list(spandrbs_modified_item(), drbs[i]); + if (drbs[i].rlc_reestablished) { + list[i]->drbs_modified_item().ie_exts_present = true; + list[i]->drbs_modified_item().ie_exts.rlc_status_present = true; + list[i]->drbs_modified_item().ie_exts.rlc_status.reest_ind.value = asn1::f1ap::reest_ind_opts::reestablished; + } } return list; } diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 4b7f738fb5..031f1060b7 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -325,13 +325,13 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti test_logger.error("rnti={}: F1AP UE Context Modification Request not sent back to the CU-CP", u.rnti); return false; } - if (not test_helpers::is_valid_ue_context_modification_response(cu_notifier.last_f1ap_msgs.back())) { + if (not test_helpers::is_valid_ue_context_modification_response( + cu_notifier.last_f1ap_msgs.back(), msg, test_helpers::ue_context_mod_context::reestablistment)) { test_logger.error("rnti={}: F1AP UE Context Modification Response sent back to the CU-CP is not valid", u.rnti); return false; } const asn1::f1ap::ue_context_mod_resp_s& resp = cu_notifier.last_f1ap_msgs.back().pdu.successful_outcome().value.ue_context_mod_resp(); - EXPECT_TRUE(resp->drbs_modified_list_present); EXPECT_FALSE(resp->drbs_failed_to_be_modified_list_present); return true; diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp index d957f66f6b..f68d11d9f2 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp @@ -13,10 +13,10 @@ #include "../tests/test_doubles/rrc/rrc_test_message_validators.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents.h" -#include "srsran/asn1/rrc_nr/dl_dcch_msg_ies.h" #include "srsran/f1ap/common/f1ap_message.h" using namespace srsran; +using namespace asn1::f1ap; #define TRUE_OR_RETURN(cond) \ if (not(cond)) \ @@ -142,26 +142,55 @@ bool srsran::test_helpers::is_valid_ue_context_modification_request(const f1ap_m return true; } -bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_message& msg) +bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_message& msg, + ue_context_mod_context context) { TRUE_OR_RETURN(msg.pdu.type() == asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome); TRUE_OR_RETURN(msg.pdu.successful_outcome().proc_code == ASN1_F1AP_ID_UE_CONTEXT_MOD); TRUE_OR_RETURN(is_packable(msg)); + + const asn1::f1ap::ue_context_mod_resp_s& resp = msg.pdu.successful_outcome().value.ue_context_mod_resp(); + + TRUE_OR_RETURN(resp->drbs_setup_mod_list_present == (resp->drbs_setup_mod_list.size() > 0)); + TRUE_OR_RETURN(resp->drbs_modified_list_present == (resp->drbs_modified_list.size() > 0)); + + // Reestablishment case. + if (context == ue_context_mod_context::reestablistment) { + // See ORAN-WG5.C.1 6.10.1, intra-DU Reestablishment, UE Context Modification Response + TRUE_OR_RETURN(not resp->drbs_setup_mod_list_present); + for (const auto& drb : resp->drbs_modified_list) { + TRUE_OR_RETURN(drb->drbs_modified_item().dl_up_tnl_info_to_be_setup_list.size() > 0); + TRUE_OR_RETURN(drb->drbs_modified_item().ie_exts_present and + drb->drbs_modified_item().ie_exts.rlc_status_present and + drb->drbs_modified_item().ie_exts.rlc_status.reest_ind.value == reest_ind_opts::reestablished); + } + } + return true; } -bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_message& resp_msg, - const f1ap_message& req_msg) +bool srsran::test_helpers::is_valid_ue_context_modification_response(const f1ap_message& resp_msg, + const f1ap_message& req_msg, + ue_context_mod_context context) { TRUE_OR_RETURN(is_valid_ue_context_modification_request(req_msg)); - TRUE_OR_RETURN(is_valid_ue_context_modification_response(resp_msg)); + TRUE_OR_RETURN(is_valid_ue_context_modification_response(resp_msg, context)); const asn1::f1ap::ue_context_mod_request_s& mod_req = req_msg.pdu.init_msg().value.ue_context_mod_request(); - const asn1::f1ap::ue_context_mod_resp_s& mod_resp = req_msg.pdu.successful_outcome().value.ue_context_mod_resp(); + const asn1::f1ap::ue_context_mod_resp_s& mod_resp = resp_msg.pdu.successful_outcome().value.ue_context_mod_resp(); TRUE_OR_RETURN(mod_req->drbs_to_be_setup_mod_list.size() == mod_resp->drbs_setup_mod_list.size() + mod_resp->drbs_failed_to_be_setup_mod_list.size()); TRUE_OR_RETURN(mod_req->drbs_to_be_modified_list.size() == mod_resp->drbs_modified_list.size() + mod_resp->drbs_failed_to_be_modified_list.size()); + for (const auto& drb : mod_resp->drbs_setup_mod_list) { + auto drb_req_it = std::find_if( + mod_req->drbs_to_be_setup_mod_list.begin(), mod_req->drbs_to_be_setup_mod_list.end(), [&drb](const auto& e) { + return drb->drbs_setup_mod_item().drb_id == e->drbs_to_be_setup_mod_item().drb_id; + }); + TRUE_OR_RETURN(drb_req_it != mod_req->drbs_to_be_setup_mod_list.end()); + TRUE_OR_RETURN(drb->drbs_setup_mod_item().dl_up_tnl_info_to_be_setup_list.size() == + drb_req_it->value().drbs_to_be_setup_mod_item().ul_up_tnl_info_to_be_setup_list.size()); + } return true; } diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index 35c8031822..59b4382579 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -44,8 +44,12 @@ bool is_ue_context_setup_response_valid(const f1ap_message& msg); bool is_valid_ue_context_modification_request(const f1ap_message& msg); -bool is_valid_ue_context_modification_response(const f1ap_message& msg); -bool is_valid_ue_context_modification_response(const f1ap_message& resp_msg, const f1ap_message& req_msg); +enum class ue_context_mod_context { default_case, reestablistment }; +bool is_valid_ue_context_modification_response(const f1ap_message& msg, + ue_context_mod_context context = ue_context_mod_context::default_case); +bool is_valid_ue_context_modification_response(const f1ap_message& resp_msg, + const f1ap_message& req_msg, + ue_context_mod_context context = ue_context_mod_context::default_case); bool is_valid_ue_context_release_command(const f1ap_message& msg); From eb088274093440182a15f9d5cb567fa973419cb6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 6 Aug 2024 16:23:49 +0200 Subject: [PATCH 131/407] du-high: fix mac config during rrc reestablishment --- .../procedures/ue_configuration_procedure.cpp | 14 ++++++- .../integrationtests/du_high/du_high_test.cpp | 28 ++++++++++++++ .../test_utils/du_high_env_simulator.cpp | 38 ++++++++++++------- .../test_utils/du_high_env_simulator.h | 3 +- .../f1ap/f1ap_test_message_validators.h | 2 +- tests/test_doubles/mac/mac_test_messages.cpp | 33 ++++++++++------ tests/test_doubles/mac/mac_test_messages.h | 2 +- 7 files changed, 90 insertions(+), 30 deletions(-) diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index bc65c371e9..ba55fd8389 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -281,7 +281,19 @@ async_task ue_configuration_procedure::update_m lc_ch.ul_bearer = &bearer.connector.mac_rx_sdu_notifier; lc_ch.dl_bearer = &bearer.connector.mac_tx_sdu_notifier; } - // TODO: Support modifications in the MAC. + for (const auto& drb : request.drbs_to_mod) { + if (ue->bearers.drbs().count(drb.drb_id) == 0) { + // The DRB failed to be modified. Carry on with other DRBs. + continue; + } + du_ue_drb& bearer = *ue->bearers.drbs().at(drb.drb_id); + mac_ue_reconf_req.bearers_to_addmod.emplace_back(); + auto& lc_ch = mac_ue_reconf_req.bearers_to_addmod.back(); + lc_ch.lcid = bearer.lcid; + lc_ch.ul_bearer = &bearer.connector.mac_rx_sdu_notifier; + lc_ch.dl_bearer = &bearer.connector.mac_tx_sdu_notifier; + // TODO: Support modifications in the MAC config. + } // Create Scheduler UE Reconfig Request that will be embedded in the mac configuration request. mac_ue_reconf_req.sched_cfg = create_scheduler_ue_config_request(*ue); diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index 46148be728..d394ac3cd2 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -300,6 +300,20 @@ TEST_F(du_high_tester, when_dl_rrc_message_with_old_du_ue_id_received_then_drbs_ rnti_t rnti2 = to_rnti(0x4602); ASSERT_TRUE(add_ue(rnti2)); ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti1)); + + // Check that DRBs are active for the new C-RNTI. + const unsigned nof_pdcp_pdus = 10, pdcp_pdu_size = 128; + for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { + nru_dl_message f1u_pdu{ + .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; + cu_up_sim.bearers.at(std::make_pair(1, drb_id_t::drb1)).rx_notifier->on_new_pdu(f1u_pdu); + } + ASSERT_TRUE(this->run_until( + [this, rnti2]() { + return find_ue_pdsch_with_lcid(rnti2, LCID_MIN_DRB, phy.cells[0].last_dl_res.value().dl_res->ue_grants) != + nullptr; + }, + 100)); } TEST_F(du_high_tester, @@ -316,4 +330,18 @@ TEST_F(du_high_tester, rnti_t rnti2 = to_rnti(0x4602); ASSERT_TRUE(add_ue(rnti2)); ASSERT_TRUE(run_rrc_reestablishment(rnti2, rnti1)); + + // Check that DRBs are active for the new C-RNTI. + const unsigned nof_pdcp_pdus = 10, pdcp_pdu_size = 128; + for (unsigned i = 0; i < nof_pdcp_pdus; ++i) { + nru_dl_message f1u_pdu{ + .t_pdu = test_helpers::create_pdcp_pdu(pdcp_sn_size::size12bits, /* is_srb = */ false, i, pdcp_pdu_size, i)}; + cu_up_sim.bearers.at(std::make_pair(1, drb_id_t::drb1)).rx_notifier->on_new_pdu(f1u_pdu); + } + ASSERT_TRUE(this->run_until( + [this, rnti2]() { + return find_ue_pdsch_with_lcid(rnti2, LCID_MIN_DRB, phy.cells[0].last_dl_res.value().dl_res->ue_grants) != + nullptr; + }, + 100)); } diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 031f1060b7..6611559cda 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -281,9 +281,8 @@ bool du_high_env_simulator::run_rrc_setup(rnti_t rnti) // Send DL RRC Message which contains RRC Setup. f1ap_message msg = generate_dl_rrc_message_transfer( *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb0, byte_buffer::create({0x1, 0x2, 0x3}).value()); - du_hi->get_f1ap_message_handler().handle_message(msg); - return run_msg4_and_await_msg5(u, msg); + return send_dl_rrc_msg_and_await_ul_rrc_msg(u, msg, 0); } bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti, reestablishment_stage stop_at) @@ -309,14 +308,14 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti msg.pdu.init_msg().value.dl_rrc_msg_transfer()->old_gnb_du_ue_f1ap_id = (uint64_t)old_u.du_ue_id.value(); // Send RRC Reestablishment and await response. - if (not run_msg4_and_await_msg5(u, msg)) { + if (not send_dl_rrc_msg_and_await_ul_rrc_msg(u, msg, 0)) { return false; } if (stop_at == reestablishment_stage::reest_complete) { return true; } - // Generate UE Context Modification procedure for DRB Reestablishment. + // Run F1AP UE Context Modification procedure. msg = test_helpers::generate_ue_context_modification_request(*u.du_ue_id, *u.cu_ue_id, {}, {drb_id_t::drb1}, {}); cu_notifier.last_f1ap_msgs.clear(); du_hi->get_f1ap_message_handler().handle_message(msg); @@ -334,22 +333,32 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti cu_notifier.last_f1ap_msgs.back().pdu.successful_outcome().value.ue_context_mod_resp(); EXPECT_FALSE(resp->drbs_failed_to_be_modified_list_present); + // CU-CP sends RRC Reconfiguration and awaits RRC Reconfiguration Complete. + msg = generate_dl_rrc_message_transfer( + *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb1, byte_buffer::create({0x1, 0x2, 0x3}).value()); + if (not send_dl_rrc_msg_and_await_ul_rrc_msg(u, msg, 1)) { + return false; + } + return true; } -bool du_high_env_simulator::run_msg4_and_await_msg5(const ue_sim_context& u, const f1ap_message& msg) +bool du_high_env_simulator::send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_context& u, + const f1ap_message& dl_msg, + uint32_t rlc_ul_sn) { const auto& phy_cell = phy.cells[u.pcell_index]; - du_hi->get_f1ap_message_handler().handle_message(msg); + lcid_t dl_lcid = uint_to_lcid(dl_msg.pdu.init_msg().value.dl_rrc_msg_transfer()->srb_id); + lcid_t ul_lcid = dl_lcid == LCID_SRB0 ? LCID_SRB1 : dl_lcid; - lcid_t msg4_lcid = msg.pdu.init_msg().value.dl_rrc_msg_transfer()->srb_id == 0 ? LCID_SRB0 : LCID_SRB1; + du_hi->get_f1ap_message_handler().handle_message(dl_msg); // Wait for Msg4 to be sent to the PHY. bool ret = run_until([&]() { if (phy_cell.last_dl_res.has_value() and phy_cell.last_dl_res.value().dl_res != nullptr) { auto& dl_res = *phy_cell.last_dl_res.value().dl_res; - return find_ue_pdsch_with_lcid(u.rnti, msg4_lcid, dl_res.ue_grants) != nullptr; + return find_ue_pdsch_with_lcid(u.rnti, dl_lcid, dl_res.ue_grants) != nullptr; } return false; }); @@ -359,18 +368,19 @@ bool du_high_env_simulator::run_msg4_and_await_msg5(const ue_sim_context& u, con } // Wait for Msg4 to be ACKed. - unsigned msg4_k1 = 4; - for (unsigned i = 0; i != msg4_k1; ++i) { + unsigned dl_msg_k1 = 4; + for (unsigned i = 0; i != dl_msg_k1; ++i) { run_slot(); } // UE sends Msg5. Wait until F1AP forwards UL RRC Message to CU-CP. cu_notifier.last_f1ap_msgs.clear(); du_hi->get_pdu_handler().handle_rx_data_indication( - test_helpers::create_pdu_with_sdu(next_slot, u.rnti, lcid_t::LCID_SRB1)); - ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); - if (not ret or not test_helpers::is_ul_rrc_msg_transfer_valid(cu_notifier.last_f1ap_msgs.back(), srb_id_t::srb1)) { - test_logger.error("rnti={}: F1AP UL RRC Message (containing Msg5) not sent or is invalid", u.rnti); + test_helpers::create_pdu_with_sdu(next_slot, u.rnti, ul_lcid, rlc_ul_sn)); + ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); + srb_id_t ul_srb_id = int_to_srb_id(ul_lcid); + if (not ret or not test_helpers::is_ul_rrc_msg_transfer_valid(cu_notifier.last_f1ap_msgs.back(), ul_srb_id)) { + test_logger.error("rnti={}: F1AP UL RRC Message not sent or is invalid", u.rnti); return false; } diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index 22ec6ff8fd..fdce31fa06 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -101,7 +101,8 @@ class du_high_env_simulator std::array srbs; }; - bool run_msg4_and_await_msg5(const ue_sim_context& u, const f1ap_message& msg); + [[nodiscard]] bool + send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_context& u, const f1ap_message& dl_msg, uint32_t rlc_ul_sn); std::unordered_map ues; diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index 59b4382579..0233fdfb58 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -45,7 +45,7 @@ bool is_ue_context_setup_response_valid(const f1ap_message& msg); bool is_valid_ue_context_modification_request(const f1ap_message& msg); enum class ue_context_mod_context { default_case, reestablistment }; -bool is_valid_ue_context_modification_response(const f1ap_message& msg, +bool is_valid_ue_context_modification_response(const f1ap_message& msg, ue_context_mod_context context = ue_context_mod_context::default_case); bool is_valid_ue_context_modification_response(const f1ap_message& resp_msg, const f1ap_message& req_msg, diff --git a/tests/test_doubles/mac/mac_test_messages.cpp b/tests/test_doubles/mac/mac_test_messages.cpp index 996b8c6036..34fd959fac 100644 --- a/tests/test_doubles/mac/mac_test_messages.cpp +++ b/tests/test_doubles/mac/mac_test_messages.cpp @@ -25,19 +25,28 @@ srsran::test_helpers::create_ccch_message(slot_point sl_rx, rnti_t rnti, du_cell byte_buffer::create({0x34, 0x1e, 0x4f, 0xc0, 0x4f, 0xa6, 0x06, 0x3f, 0x00, 0x00, 0x00}).value()}}}; } -mac_rx_data_indication srsran::test_helpers::create_pdu_with_sdu(slot_point sl_rx, rnti_t rnti, lcid_t lcid) +mac_rx_data_indication +srsran::test_helpers::create_pdu_with_sdu(slot_point sl_rx, rnti_t rnti, lcid_t lcid, uint32_t rlc_sn) { - return mac_rx_data_indication{ - sl_rx, - to_du_cell_index(0), - {mac_rx_pdu{ - rnti, - 0, - 0, - byte_buffer::create({(uint8_t)lcid, 0x23, 0xc0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05, 0xdf, 0x80, 0x10, 0x5e, - 0x40, 0x03, 0x40, 0x40, 0x3c, 0x44, 0x3c, 0x3f, 0xc0, 0x00, 0x04, 0x0c, 0x95, - 0x1d, 0xa6, 0x0b, 0x80, 0xb8, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00}) - .value()}}}; + // assuming RLC SN size of 12bits. + uint8_t rlc_sn_part1 = (rlc_sn & 0xf00U) >> 8U; + uint8_t rlc_sn_part2 = (rlc_sn & 0xffU); + + byte_buffer mac_pdu = byte_buffer::create({(uint8_t)lcid, 0x23, static_cast(0xc0U + rlc_sn_part1), + rlc_sn_part2, 0x00, 0x00, + 0x10, 0x00, 0x05, + 0xdf, 0x80, 0x10, + 0x5e, 0x40, 0x03, + 0x40, 0x40, 0x3c, + 0x44, 0x3c, 0x3f, + 0xc0, 0x00, 0x04, + 0x0c, 0x95, 0x1d, + 0xa6, 0x0b, 0x80, + 0xb8, 0x38, 0x00, + 0x00, 0x00, 0x00, + 0x00}) + .value(); + return mac_rx_data_indication{sl_rx, to_du_cell_index(0), {mac_rx_pdu{rnti, 0, 0, std::move(mac_pdu)}}}; } mac_crc_indication_message srsran::test_helpers::create_crc_indication(slot_point sl_rx, rnti_t rnti, harq_id_t h_id) diff --git a/tests/test_doubles/mac/mac_test_messages.h b/tests/test_doubles/mac/mac_test_messages.h index 1b36426380..0e28ae5070 100644 --- a/tests/test_doubles/mac/mac_test_messages.h +++ b/tests/test_doubles/mac/mac_test_messages.h @@ -25,7 +25,7 @@ namespace test_helpers { mac_rx_data_indication create_ccch_message(slot_point sl_rx, rnti_t rnti, du_cell_index_t du_cell_index = to_du_cell_index(0)); -mac_rx_data_indication create_pdu_with_sdu(slot_point sl_rx, rnti_t rnti, lcid_t lcid); +mac_rx_data_indication create_pdu_with_sdu(slot_point sl_rx, rnti_t rnti, lcid_t lcid, uint32_t rlc_sn = 0); /// \brief Generate MAC UCI PDU from PUCCH information, with all HARQ-ACKs set to ACK, SRs set as not detected and CSI /// set as 1s. From 209e6b445e3959b8e4e090472f0716560c36c082 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 29 Jul 2024 12:30:41 +0200 Subject: [PATCH 132/407] ran: rename MAX_NOF_PUCCH_RESOURCES to MAX_NOF_UE_PUCCH_RESOURCES --- include/srsran/ran/pucch/pucch_configuration.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/srsran/ran/pucch/pucch_configuration.h b/include/srsran/ran/pucch/pucch_configuration.h index 9532026c15..9fcf6a8904 100644 --- a/include/srsran/ran/pucch/pucch_configuration.h +++ b/include/srsran/ran/pucch/pucch_configuration.h @@ -27,9 +27,9 @@ namespace srsran { /// \remark See TS 38.331, "maxNrofPUCCH-ResourceSets". constexpr size_t MAX_NOF_PUCCH_RESOURCE_SETS = 4; -/// Maximum number of PUCCH resources. +/// Maximum number of PUCCH resources that can be configured for a UE. /// \remark See TS 38.331, "maxNrofPUCCH-Resources". -constexpr size_t MAX_NOF_PUCCH_RESOURCES = 128; +constexpr size_t MAX_NOF_UE_PUCCH_RESOURCES = 128; /// Maximum number of PUCCH Resources per PUCCH-ResourceSet. /// \remark See TS 38.331, "maxNrofPUCCH-ResourcesPerSet". Only valid for the first \c pucch_resource_set, see @@ -188,7 +188,7 @@ struct pucch_config { // NOTE: PUCCH resource set ID 0 can only contain PUCCH format 0 and 1. static_vector pucch_res_set; /// List of \c PUCCH-Resource. - static_vector pucch_res_list; + static_vector pucch_res_list; /// \c format1 .. \c format4, which contain the parameters that are common to a given PUCCH Format. std::optional format_1_common_param; std::optional format_2_common_param; From 8e4ef3f3b56bbbc009e603cb1e673694f3f6cd4d Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 29 Jul 2024 12:32:40 +0200 Subject: [PATCH 133/407] ran, sched: move maximum PUCCH resources handled by PUCCH resource manager to PUCCH constants --- include/srsran/ran/pucch/pucch_constants.h | 9 +++++++++ .../pucch_scheduling/pucch_resource_manager.h | 11 +++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/srsran/ran/pucch/pucch_constants.h b/include/srsran/ran/pucch/pucch_constants.h index 9a51019024..96bb5f5731 100644 --- a/include/srsran/ran/pucch/pucch_constants.h +++ b/include/srsran/ran/pucch/pucch_constants.h @@ -67,5 +67,14 @@ static constexpr unsigned MAX_NOF_LLR = MAX_NOF_RE * 2; /// Information Element \e PUCCH-FormatConfig. static constexpr float MAX_CODE_RATE = 0.80F; +/// [Implementation-defined] Maximum number of PUCCH resources handled by the PUCCH resource manager. +/// \remark See TS 38.331, "maxNrofPUCCH-Resources". +constexpr size_t MAX_NOF_CELL_PUCCH_RESOURCES{128}; + +/// Maximum number of common PUCCH resources handled by the PUCCH resource manager. +/// \remark See TS 38.331, section 9.2.1, maximum value is given by the number of possible values of r_PUCCH, which +/// is 16. +constexpr size_t MAX_NOF_CELL_COMMON_PUCCH_RESOURCES{16}; + } // namespace pucch_constants } // namespace srsran diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.h b/lib/scheduler/pucch_scheduling/pucch_resource_manager.h index b4fc5d8dff..edf4c06363 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.h +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.h @@ -11,6 +11,7 @@ #pragma once #include "../config/ue_configuration.h" +#include "srsran/ran/pucch/pucch_constants.h" namespace srsran { @@ -152,20 +153,14 @@ class pucch_resource_manager static const size_t RES_MANAGER_RING_BUFFER_SIZE = get_allocator_ring_size_gt_min(SCHEDULER_MAX_K0 + SCHEDULER_MAX_K1 + NTN_CELL_SPECIFIC_KOFFSET_MAX); - // [Implementation-defined] We assume as the maximum number of PUCCH resources that can be handled by the resource - // manager \c maxNrofPUCCH-Resources, TS 38.331. - static const size_t MAX_PUCCH_RESOURCES{128}; - // As per Section 9.2.1, TS 38.213, this is given by the number of possible values of r_PUCCH, which is 16. - static const size_t MAX_COMMON_PUCCH_RESOURCES{16}; - // Tracks usage of PUCCH resources. struct resource_tracker { rnti_t rnti; pucch_resource_usage resource_usage; }; - using pucch_res_record_array = std::array; - using common_res_record_array = std::array; + using pucch_res_record_array = std::array; + using common_res_record_array = std::array; // Record for the RNTI and PUCCH resource indicator used for a given resource at a given slot; this information is // used to keep track of which resources are available and which UE is using them. This information is preserved over From f6082fec608b7f6ca4723cd33ee46a0c71688b51 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 29 Jul 2024 12:34:24 +0200 Subject: [PATCH 134/407] du_mgr: add validation for the number of PUCCH resources generated for the cell --- .../pucch_resource_generator.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp index f2a2aa468e..d8d5331795 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -584,10 +584,18 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned const std::vector pucch_f2_resource_list = nof_res_f2 > 0 ? compute_f2_res(nof_res_f2, f2_params, bwp_size_rbs) : std::vector{}; - return merge_f0_f1_f2_resource_lists(pucch_f0_f1_resource_list, - pucch_f2_resource_list, - has_f0 ? std::nullopt : std::optional{nof_css}, - bwp_size_rbs); + auto res_list = merge_f0_f1_f2_resource_lists(pucch_f0_f1_resource_list, + pucch_f2_resource_list, + has_f0 ? std::nullopt : std::optional{nof_css}, + bwp_size_rbs); + if (res_list.size() > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { + srsran_assertion_failure("With the given parameters, the number of PUCCH resources generated for the " + "cell exceeds maximum supported limit of {}", + pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES); + return {}; + } + + return res_list; } static unsigned cell_res_list_validator(const std::vector& res_list, From 7df07b3a54f6f1fc670ab8197c80fa28ccece157 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 29 Jul 2024 12:34:45 +0200 Subject: [PATCH 135/407] sched: minor refactor --- .../pucch_scheduling/pucch_allocator_impl.cpp | 2 +- .../pucch_resource_manager.cpp | 30 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index a52a49120b..df7fd99f0e 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -88,7 +88,7 @@ static pucch_resource* get_sr_pucch_res_cfg(const pucch_config& pucch_cfg) return res.res_id.cell_res_id == sr_pucch_res_id; }); - return res_cfg != pucch_res_list.end() ? const_cast(&(*res_cfg)) : nullptr; + return res_cfg != pucch_res_list.end() ? const_cast(res_cfg) : nullptr; } ////////////// Public functions ////////////// diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp index 93ac166118..d9ddea275d 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp @@ -25,16 +25,14 @@ static int get_pucch_res_idx_for_csi(const ue_cell_configuration& ue_cell_cfg) // TODO: extend by passing the BWP id. const bwp_id_t bwp_id = srsran::MIN_BWP_ID; const auto& csi_report_cfg = ue_cell_cfg.cfg_dedicated().csi_meas_cfg.value().csi_report_cfg_list[csi_report_cfg_idx]; - const auto& csi_pucch_res_list = + span csi_pucch_res_list = std::get(csi_report_cfg.report_cfg_type) .pucch_csi_res_list; - const auto& it = std::find_if(csi_pucch_res_list.begin(), - csi_pucch_res_list.end(), - [](const csi_report_config::pucch_csi_resource& csi) { return csi.ul_bwp == bwp_id; }); - - if (it != csi_pucch_res_list.end()) { - return static_cast(it->pucch_res_id.cell_res_id); + for (const auto& csi : csi_pucch_res_list) { + if (csi.ul_bwp == bwp_id) { + return static_cast(csi.pucch_res_id.cell_res_id); + } } return -1; @@ -136,12 +134,13 @@ const pucch_resource* pucch_resource_manager::reserve_csi_resource(slot_point // Get resource list of wanted slot. auto& slot_record = get_slot_resource_counter(slot_csi); - if (slot_record.ues_using_pucch_res[csi_pucch_res_idx].rnti != rnti_t::INVALID_RNTI and - slot_record.ues_using_pucch_res[csi_pucch_res_idx].rnti != crnti) { + if (csi_pucch_res_idx >= slot_record.ues_using_pucch_res.size() or + (slot_record.ues_using_pucch_res[csi_pucch_res_idx].rnti != rnti_t::INVALID_RNTI and + slot_record.ues_using_pucch_res[csi_pucch_res_idx].rnti != crnti)) { return nullptr; } - const auto& pucch_res_list = + span pucch_res_list = ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().pucch_res_list; // Search for the PUCCH resource with the correct PUCCH resource ID from the PUCCH resource list. const auto* res_cfg = @@ -160,7 +159,7 @@ const pucch_resource* pucch_resource_manager::reserve_csi_resource(slot_point slot_record.ues_using_pucch_res[csi_pucch_res_idx].resource_usage = pucch_resource_usage::CSI; } - return &(*res_cfg); + return res_cfg; }; const pucch_resource* @@ -197,7 +196,7 @@ pucch_resource_manager::reserve_sr_res_available(slot_point slot_sr, rnti_t crnt slot_record.ues_using_pucch_res[sr_pucch_res_id].resource_usage = pucch_resource_usage::SR; } - return &(*res_cfg); + return res_cfg; }; bool pucch_resource_manager::release_harq_set_0_resource(slot_point slot_harq, @@ -383,8 +382,7 @@ pucch_harq_resource_alloc_record pucch_resource_manager::reserve_next_harq_res_a // If there is an available resource, try to allocate it. if (available_resource != slot_ue_res_array.end() and - static_cast(available_resource - slot_ue_res_array.begin()) < - pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(res_set_idx)].pucch_res_id_list.size()) { + static_cast(available_resource - slot_ue_res_array.begin()) < ue_res_id_set_for_harq.size()) { // Get the PUCCH resource indicator from the available resource position within the span. const auto pucch_res_indicator = static_cast(available_resource - slot_ue_res_array.begin()); // Get the PUCCH resource ID from the PUCCH resource indicator and the PUCCH resource set. @@ -401,7 +399,7 @@ pucch_harq_resource_alloc_record pucch_resource_manager::reserve_next_harq_res_a available_resource->rnti = crnti; available_resource->resource_usage = res_set_idx == pucch_res_set_idx::set_0 ? pucch_resource_usage::HARQ_SET_0 : pucch_resource_usage::HARQ_SET_1; - return pucch_harq_resource_alloc_record{.pucch_res = &(*res_cfg), .pucch_res_indicator = pucch_res_indicator}; + return pucch_harq_resource_alloc_record{.pucch_res = res_cfg, .pucch_res_indicator = pucch_res_indicator}; } } return pucch_harq_resource_alloc_record{.pucch_res = nullptr}; @@ -454,7 +452,7 @@ const pucch_resource* pucch_resource_manager::reserve_harq_res_by_res_indicator( pucch_res_tracker.resource_usage = res_set_idx == pucch_res_set_idx::set_0 ? pucch_resource_usage::HARQ_SET_0 : pucch_resource_usage::HARQ_SET_1; } - return &(*res_cfg); + return res_cfg; } bool pucch_resource_manager::release_harq_resource(slot_point slot_harq, From 9e21c59009d432689ff97c7ad4569dd7e8f65443 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 29 Jul 2024 12:36:32 +0200 Subject: [PATCH 136/407] ran,sched: increase maximum number of PUCCH resources handled by the PUCCH resource manager to 256 --- include/srsran/ran/pucch/pucch_constants.h | 9 ++++----- lib/scheduler/pucch_scheduling/pucch_resource_manager.h | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/srsran/ran/pucch/pucch_constants.h b/include/srsran/ran/pucch/pucch_constants.h index 96bb5f5731..96ebfa77b5 100644 --- a/include/srsran/ran/pucch/pucch_constants.h +++ b/include/srsran/ran/pucch/pucch_constants.h @@ -67,14 +67,13 @@ static constexpr unsigned MAX_NOF_LLR = MAX_NOF_RE * 2; /// Information Element \e PUCCH-FormatConfig. static constexpr float MAX_CODE_RATE = 0.80F; -/// [Implementation-defined] Maximum number of PUCCH resources handled by the PUCCH resource manager. -/// \remark See TS 38.331, "maxNrofPUCCH-Resources". -constexpr size_t MAX_NOF_CELL_PUCCH_RESOURCES{128}; +/// [Implementation-defined] Maximum number of PUCCH resources in a cell. +constexpr size_t MAX_NOF_CELL_PUCCH_RESOURCES = 256; -/// Maximum number of common PUCCH resources handled by the PUCCH resource manager. +/// Maximum number of common PUCCH resources in a cell. /// \remark See TS 38.331, section 9.2.1, maximum value is given by the number of possible values of r_PUCCH, which /// is 16. -constexpr size_t MAX_NOF_CELL_COMMON_PUCCH_RESOURCES{16}; +constexpr size_t MAX_NOF_CELL_COMMON_PUCCH_RESOURCES = 16; } // namespace pucch_constants } // namespace srsran diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.h b/lib/scheduler/pucch_scheduling/pucch_resource_manager.h index edf4c06363..29631c3b53 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.h +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.h @@ -30,8 +30,8 @@ enum class pucch_resource_usage { NOT_USED = 0, HARQ_SET_0, HARQ_SET_1, SR, CSI /// The correct functioning of pucch_resource_manager is based on the following assumptions: /// (i) Each UE has max 8 PUCCH F0/F1 and max 8 PUCCH F2 dedicated to HARQ-ACK reporting. /// (ii) Each UE has max 1 SR-dedicated PUCCH F0/F1 resource and max 1 CSI-dedicated PUCCH F2 resource. -/// (iii) The cell PUCCH resource list can have max 128 PUCCH resource, including all formats; at cell level, there is -/// no constraint on how many resource must be F0/F1, F2, or for SR or for CSI. +/// (iii) The cell PUCCH resource list can have max \c MAX_NOF_CELL_PUCCH_RESOURCES PUCCH resource, including all +/// formats; at cell level, there is no constraint on how many resource must be F0/F1, F2, or for SR or for CSI. /// (vi) UEs can have different PUCCH resource lists; however the PUCCH resource ID is unique with the cell. This /// implies that if two UEs have the same PUCCH resource within their lists, their PUCCH resource ID must be the /// same. From a77b6733ceaa837b4ef74c863e18ce17d79fafa4 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 6 Aug 2024 13:06:53 +0200 Subject: [PATCH 137/407] du,sched: add checks for max pucch_cell_res_id Signed-off-by: Carlo Galiotto --- .../du_high/du_high_config_validator.cpp | 10 ++++++++++ .../pucch_resource_generator.cpp | 1 + .../config/serving_cell_config_validator.cpp | 7 +++++++ .../pucch_scheduling/pucch_resource_manager.cpp | 16 ++++++++++++---- 4 files changed, 30 insertions(+), 4 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 e29e019a54..145ef24a14 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 @@ -13,6 +13,7 @@ #include "srsran/ran/nr_cell_identity.h" #include "srsran/ran/pdcch/pdcch_type0_css_coreset_config.h" #include "srsran/ran/prach/prach_helper.h" +#include "srsran/ran/pucch/pucch_constants.h" #include "srsran/rlc/rlc_config.h" using namespace srsran; @@ -409,6 +410,15 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& return false; } + if ((pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq + pucch_cfg.nof_ue_pucch_f2_res_harq) * + pucch_cfg.nof_cell_harq_pucch_sets + + pucch_cfg.nof_cell_sr_resources + pucch_cfg.nof_cell_csi_resources > + pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { + fmt::print("With the given PUCCH parameters, the number of PUCCH resources per cell exceeds the limit={}.\n", + pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES); + return false; + } + return true; } diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp index d8d5331795..e60b5a7326 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -588,6 +588,7 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned pucch_f2_resource_list, has_f0 ? std::nullopt : std::optional{nof_css}, bwp_size_rbs); + if (res_list.size() > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { srsran_assertion_failure("With the given parameters, the number of PUCCH resources generated for the " "cell exceeds maximum supported limit of {}", diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index 5e152add55..c666760660 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -171,6 +171,13 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel } } + // Verify that each PUCCH resource has a valid cell resource ID. + for (auto res_idx : pucch_cfg.pucch_res_list) { + VERIFY(res_idx.res_id.cell_res_id < pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES, + "PUCCH cell res. id={} exceeds the maximum supported PUCCH resource ID", + res_idx.res_id.cell_res_id); + } + // Verify each resource format matches the corresponding parameters. for (auto res : pucch_cfg.pucch_res_list) { const bool format_match_format_params = diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp index d9ddea275d..5cb73134f4 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp @@ -173,8 +173,9 @@ pucch_resource_manager::reserve_sr_res_available(slot_point slot_sr, rnti_t crnt // We assume each UE only has 1 SR Resource Config configured. const unsigned sr_pucch_res_id = pucch_cfg.sr_res_list[0].pucch_res_id.cell_res_id; - if (slot_record.ues_using_pucch_res[sr_pucch_res_id].rnti != rnti_t::INVALID_RNTI and - slot_record.ues_using_pucch_res[sr_pucch_res_id].rnti != crnti) { + if (sr_pucch_res_id >= slot_record.ues_using_pucch_res.size() or + (slot_record.ues_using_pucch_res[sr_pucch_res_id].rnti != rnti_t::INVALID_RNTI and + slot_record.ues_using_pucch_res[sr_pucch_res_id].rnti != crnti)) { return nullptr; } @@ -224,7 +225,8 @@ bool pucch_resource_manager::release_sr_resource(slot_point slot_sr, rnti_t crnt // We assume each UE only has 1 SR Resource Config configured. const unsigned sr_pucch_res_id = pucch_cfg.sr_res_list[0].pucch_res_id.cell_res_id; - if (slot_record.ues_using_pucch_res[sr_pucch_res_id].rnti != crnti) { + if (sr_pucch_res_id >= slot_record.ues_using_pucch_res.size() or + slot_record.ues_using_pucch_res[sr_pucch_res_id].rnti != crnti) { return false; } @@ -247,7 +249,8 @@ bool pucch_resource_manager::release_csi_resource(slot_point s if (csi_pucch_res_idx < 0) { return false; } - if (slot_record.ues_using_pucch_res[csi_pucch_res_idx].rnti != crnti) { + if (static_cast(csi_pucch_res_idx) >= slot_record.ues_using_pucch_res.size() or + slot_record.ues_using_pucch_res[csi_pucch_res_idx].rnti != crnti) { return false; } @@ -427,6 +430,11 @@ const pucch_resource* pucch_resource_manager::reserve_harq_res_by_res_indicator( // Get PUCCH resource ID from the PUCCH resource set. const unsigned pucch_res_id = ue_res_id_set_for_harq[res_indicator].cell_res_id; + // Extra safe check. Make sure cell_res_id is valid, even though this should be ensured by the UE config validator. + if (pucch_res_id >= res_counter.ues_using_pucch_res.size()) { + return nullptr; + } + // Get the PUCCH resource tracker in the PUCCH resource manager. auto& pucch_res_tracker = res_counter.ues_using_pucch_res[pucch_res_id]; const auto& pucch_res_list = pucch_cfg.pucch_res_list; From 9cdc97e4dc5e82ed80863011916add0aa79e08de Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 1 Aug 2024 18:09:01 +0100 Subject: [PATCH 138/407] udp_gw,cu_up: drop packets if pool occupancy is too high --- apps/cu/cu_appconfig.h | 1 + apps/cu/cu_appconfig_cli11_schema.cpp | 6 ++++++ apps/units/cu_up/cu_up_unit_config.h | 1 + apps/units/cu_up/cu_up_unit_config_cli11_schema.cpp | 3 +++ apps/units/cu_up/cu_up_unit_config_translators.cpp | 1 + include/srsran/cu_up/cu_up_configuration.h | 7 +++++-- include/srsran/gateways/udp_network_gateway.h | 3 ++- lib/gateways/udp_network_gateway_impl.cpp | 8 +++++++- lib/gateways/udp_network_gateway_impl.h | 2 +- 9 files changed, 27 insertions(+), 5 deletions(-) diff --git a/apps/cu/cu_appconfig.h b/apps/cu/cu_appconfig.h index 5c5ab00f65..70fd0e6ab1 100644 --- a/apps/cu/cu_appconfig.h +++ b/apps/cu/cu_appconfig.h @@ -22,6 +22,7 @@ namespace srs_cu { struct cu_nru_appconfig { std::string bind_addr = "127.0.10.1"; // Bind address used by the F1-U interface int udp_rx_max_msgs = 256; // Max number of UDP packets received by a single syscall on the F1-U interface. + float pool_occupancy_threshold = 0.9; // Buffer pool occupancy threshold after which packets are dropped. }; /// F1AP configuration diff --git a/apps/cu/cu_appconfig_cli11_schema.cpp b/apps/cu/cu_appconfig_cli11_schema.cpp index fc27a9f27f..17ab26f466 100644 --- a/apps/cu/cu_appconfig_cli11_schema.cpp +++ b/apps/cu/cu_appconfig_cli11_schema.cpp @@ -30,6 +30,12 @@ static void configure_cli11_nru_args(CLI::App& app, srs_cu::cu_nru_appconfig& nr "Default local IP address interfaces bind to, unless a specific bind address is specified") ->check(CLI::ValidIPV4); add_option(app, "--udp_max_rx_msgs", nru_cfg.udp_rx_max_msgs, "Maximum amount of messages RX in a single syscall"); + add_option(app, + "--pool_threshold", + nru_cfg.pool_occupancy_threshold, + "Pool accupancy threshold after which packets are dropped") + ->check(CLI::Range(0.0, 1.0)); + ; } void srsran::configure_cli11_with_cu_appconfig_schema(CLI::App& app, cu_appconfig& cu_cfg) diff --git a/apps/units/cu_up/cu_up_unit_config.h b/apps/units/cu_up/cu_up_unit_config.h index beeae79db8..4f42a271a7 100644 --- a/apps/units/cu_up/cu_up_unit_config.h +++ b/apps/units/cu_up/cu_up_unit_config.h @@ -31,6 +31,7 @@ struct cu_up_unit_upf_config { std::string n3_bind_interface = "auto"; std::string n3_ext_addr = "auto"; int udp_rx_max_msgs = 256; + float pool_threshold = 0.9; bool no_core = false; }; 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 e00b3a2591..b8a34f5d5a 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 @@ -87,6 +87,9 @@ static void configure_cli11_upf_args(CLI::App& app, cu_up_unit_upf_config& upf_p "External IP address that is advertised to receive GTP-U packets from UPF via N3 interface") ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); add_option(app, "--udp_max_rx_msgs", upf_params.udp_rx_max_msgs, "Maximum amount of messages RX in a single syscall"); + add_option( + app, "--pool_threshold", upf_params.pool_threshold, "Pool accupancy threshold after which packets are dropped") + ->check(CLI::Range(0.0, 1.0)); add_option(app, "--no_core", upf_params.no_core, "Allow gNB to run without a core"); } diff --git a/apps/units/cu_up/cu_up_unit_config_translators.cpp b/apps/units/cu_up/cu_up_unit_config_translators.cpp index 2fcfa65a41..f9c876454f 100644 --- a/apps/units/cu_up/cu_up_unit_config_translators.cpp +++ b/apps/units/cu_up/cu_up_unit_config_translators.cpp @@ -30,6 +30,7 @@ srs_cu_up::cu_up_configuration srsran::generate_cu_up_config(const cu_up_unit_co out_cfg.net_cfg.n3_ext_addr = config.upf_cfg.n3_ext_addr; out_cfg.net_cfg.n3_bind_interface = config.upf_cfg.n3_bind_interface; out_cfg.net_cfg.n3_rx_max_mmsg = config.upf_cfg.udp_rx_max_msgs; + out_cfg.net_cfg.pool_threshold = config.upf_cfg.pool_threshold; out_cfg.test_mode_cfg.enabled = config.test_mode_cfg.enabled; out_cfg.test_mode_cfg.integrity_enabled = config.test_mode_cfg.integrity_enabled; diff --git a/include/srsran/cu_up/cu_up_configuration.h b/include/srsran/cu_up/cu_up_configuration.h index dde9ec3570..5c364a925d 100644 --- a/include/srsran/cu_up/cu_up_configuration.h +++ b/include/srsran/cu_up/cu_up_configuration.h @@ -48,6 +48,9 @@ struct network_interface_config { /// Maximum amount of packets received in a single syscall. int n3_rx_max_mmsg = 256; + /// Pool occupancy threshold after which we drop packets. + float pool_threshold = 0.9; + /// Local IP address to bind for connection from DU to receive uplink user-plane traffic. std::string f1u_bind_addr = "127.0.2.1"; @@ -113,8 +116,8 @@ struct formatter { } template - auto format(srsran::srs_cu_up::network_interface_config cfg, FormatContext& ctx) - -> decltype(std::declval().out()) + auto format(srsran::srs_cu_up::network_interface_config cfg, + FormatContext& ctx) -> decltype(std::declval().out()) { return format_to(ctx.out(), "upf_port={}, n3_bind_addr={}, n3_bind_port={}, f1u_bind_addr={}, f1u_bind_port={}", diff --git a/include/srsran/gateways/udp_network_gateway.h b/include/srsran/gateways/udp_network_gateway.h index cdc3a8afd6..ce80d70bde 100644 --- a/include/srsran/gateways/udp_network_gateway.h +++ b/include/srsran/gateways/udp_network_gateway.h @@ -21,7 +21,8 @@ struct sockaddr_storage; namespace srsran { struct udp_network_gateway_config : common_network_gateway_config { - unsigned rx_max_mmsg = 256; + unsigned rx_max_mmsg = 256; + float pool_occupancy_threshold = 0.9; }; /// Interface to inject PDUs into gateway entity. diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index 65cec2ae43..e951ec050f 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -31,7 +31,7 @@ udp_network_gateway_impl::udp_network_gateway_impl(udp_network_gateway_config logger(srslog::fetch_basic_logger("UDP-GW")), io_tx_executor(io_tx_executor_) { - logger.info("UDP GW configured. rx_max_mmsg={}", config.rx_max_mmsg); + logger.info("UDP GW configured. rx_max_mmsg={} pool_thres={}", config.rx_max_mmsg, config.pool_occupancy_threshold); // Allocate RX buffers rx_mem.resize(config.rx_max_mmsg); @@ -228,6 +228,12 @@ void udp_network_gateway_impl::receive() return; } + float pool_occupancy = get_byte_buffer_segment_pool_current_size_approx() / get_byte_buffer_segment_pool_capacity(); + if (pool_occupancy >= config.pool_occupancy_threshold) { + logger.debug("Buffer pool occupancy at {}. Dropping {} packets", pool_occupancy, rx_msgs); + return; + } + for (int i = 0; i < rx_msgs; ++i) { span payload(rx_mem[i].data(), rx_msghdr[i].msg_len); byte_buffer pdu = {}; diff --git a/lib/gateways/udp_network_gateway_impl.h b/lib/gateways/udp_network_gateway_impl.h index d505ce423a..ee25bb7551 100644 --- a/lib/gateways/udp_network_gateway_impl.h +++ b/lib/gateways/udp_network_gateway_impl.h @@ -27,7 +27,7 @@ class udp_network_gateway_impl final : public udp_network_gateway public: explicit udp_network_gateway_impl(udp_network_gateway_config config_, network_gateway_data_notifier_with_src_addr& data_notifier_, - task_executor& io_executor_); + task_executor& io_tx_executor_); ~udp_network_gateway_impl() override { close_socket(); } bool subscribe_to(io_broker& broker) override; From 3904f8aad9c6c231e68e62a40ed223a85c4e9b94 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 2 Aug 2024 16:40:30 +0100 Subject: [PATCH 139/407] f1u: limit pool threshold on du and cu apps --- apps/cu/cu.cpp | 3 ++- apps/du/du.cpp | 3 ++- apps/du/du_appconfig.h | 6 +++--- apps/du/du_appconfig_cli11_schema.cpp | 3 +++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 6b1a09bd64..bf04b61b87 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -293,7 +293,8 @@ int main(int argc, char** argv) udp_network_gateway_config cu_f1u_gw_config = {}; cu_f1u_gw_config.bind_address = cu_cfg.nru_cfg.bind_addr; cu_f1u_gw_config.bind_port = GTPU_PORT; - cu_f1u_gw_config.reuse_addr = true; + cu_f1u_gw_config.reuse_addr = false; + cu_f1u_gw_config.pool_occupancy_threshold = cu_cfg.nru_cfg.pool_occupancy_threshold; 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 = diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 4e1edb8867..b59d0e7c72 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -280,7 +280,8 @@ int main(int argc, char** argv) udp_network_gateway_config du_f1u_gw_config = {}; du_f1u_gw_config.bind_address = du_cfg.nru_cfg.bind_address; du_f1u_gw_config.bind_port = GTPU_PORT; - du_f1u_gw_config.reuse_addr = true; + du_f1u_gw_config.reuse_addr = false; + du_f1u_gw_config.pool_occupancy_threshold = du_cfg.nru_cfg.pool_threshold; std::unique_ptr du_f1u_gw = srs_cu_up::create_udp_ngu_gateway( du_f1u_gw_config, *epoll_broker, diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index e1a684a8fb..0726e65c55 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -29,9 +29,9 @@ struct f1ap_appconfig { }; struct nru_appconfig { - unsigned pdu_queue_size = 2048; - /// IP address to bind the F1-U interface to. - std::string bind_address = "127.0.10.2"; + unsigned pdu_queue_size = 2048; + std::string bind_address = "127.0.10.2"; + float pool_threshold = 0.9; }; /// Metrics report configuration. diff --git a/apps/du/du_appconfig_cli11_schema.cpp b/apps/du/du_appconfig_cli11_schema.cpp index 105c90c40d..74c54602a0 100644 --- a/apps/du/du_appconfig_cli11_schema.cpp +++ b/apps/du/du_appconfig_cli11_schema.cpp @@ -236,6 +236,9 @@ static void configure_cli11_f1u_args(CLI::App& app, srs_du::nru_appconfig& f1u_p app.add_option( "--bind_addr", f1u_params.bind_address, "DU F1-U bind address. If left empty, implicit bind is performed") ->capture_default_str(); + app.add_option( + "--pool_threshold", f1u_params.pool_threshold, "Pool occupancy threshold after which packets are dropped") + ->capture_default_str(); } static void configure_cli11_hal_args(CLI::App& app, std::optional& config) From 2fa566472e6d2c4c6e40b6667b2ca80f826e2514 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 2 Aug 2024 18:21:21 +0100 Subject: [PATCH 140/407] udp: added unit test to occupancy check in UDP gateway --- apps/cu/cu_appconfig_cli11_schema.cpp | 2 +- include/srsran/cu_up/cu_up_configuration.h | 3 +- lib/gateways/udp_network_gateway_impl.cpp | 26 +-- lib/gateways/udp_network_gateway_impl.h | 3 + tests/unittests/gateways/CMakeLists.txt | 8 +- ...dp_network_gateway_pool_depletion_test.cpp | 164 ++++++++++++++++++ 6 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp diff --git a/apps/cu/cu_appconfig_cli11_schema.cpp b/apps/cu/cu_appconfig_cli11_schema.cpp index 17ab26f466..9cdb2b7120 100644 --- a/apps/cu/cu_appconfig_cli11_schema.cpp +++ b/apps/cu/cu_appconfig_cli11_schema.cpp @@ -33,7 +33,7 @@ static void configure_cli11_nru_args(CLI::App& app, srs_cu::cu_nru_appconfig& nr add_option(app, "--pool_threshold", nru_cfg.pool_occupancy_threshold, - "Pool accupancy threshold after which packets are dropped") + "Pool occupancy threshold after which packets are dropped") ->check(CLI::Range(0.0, 1.0)); ; } diff --git a/include/srsran/cu_up/cu_up_configuration.h b/include/srsran/cu_up/cu_up_configuration.h index 5c364a925d..758065a176 100644 --- a/include/srsran/cu_up/cu_up_configuration.h +++ b/include/srsran/cu_up/cu_up_configuration.h @@ -116,8 +116,7 @@ struct formatter { } template - auto format(srsran::srs_cu_up::network_interface_config cfg, - FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::srs_cu_up::network_interface_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), "upf_port={}, n3_bind_addr={}, n3_bind_port={}, f1u_bind_addr={}, f1u_bind_port={}", diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index e951ec050f..935cf827d0 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -66,8 +66,6 @@ void udp_network_gateway_impl::handle_pdu(byte_buffer pdu, const sockaddr_storag void udp_network_gateway_impl::handle_pdu_impl(const byte_buffer& pdu, const sockaddr_storage& dest_addr) { - logger.debug("Sending PDU of {} bytes", pdu.length()); - if (not sock_fd.is_open()) { logger.error("Socket not initialized"); return; @@ -94,7 +92,7 @@ void udp_network_gateway_impl::handle_pdu_impl(const byte_buffer& pdu, const soc strerror(errno)); } - logger.debug("PDU was sent successfully"); + logger.debug("Sent PDU of {} bytes", pdu.length()); } void udp_network_gateway_impl::handle_io_error(io_broker::error_code code) @@ -228,17 +226,23 @@ void udp_network_gateway_impl::receive() return; } - float pool_occupancy = get_byte_buffer_segment_pool_current_size_approx() / get_byte_buffer_segment_pool_capacity(); - if (pool_occupancy >= config.pool_occupancy_threshold) { - logger.debug("Buffer pool occupancy at {}. Dropping {} packets", pool_occupancy, rx_msgs); - return; - } - for (int i = 0; i < rx_msgs; ++i) { + float pool_occupancy = + (1 - (float)get_byte_buffer_segment_pool_current_size_approx() / get_byte_buffer_segment_pool_capacity()); + if (pool_occupancy >= config.pool_occupancy_threshold) { + if (warn_low_buffer_pool) { + logger.warning("Buffer pool at {}% occupancy. Dropping {} packets", pool_occupancy * 100, rx_msgs - i); + warn_low_buffer_pool = false; + return; + } + logger.info("Buffer pool at {}% occupancy. Dropping {} packets", pool_occupancy * 100, rx_msgs - i); + return; + } span payload(rx_mem[i].data(), rx_msghdr[i].msg_len); - byte_buffer pdu = {}; + + byte_buffer pdu = {}; if (pdu.append(payload)) { - logger.debug("Received {} bytes on UDP socket", rx_msghdr[i].msg_len); + logger.debug("Received {} bytes on UDP socket. Pool occupancy {}%", rx_msghdr[i].msg_len, pool_occupancy * 100); data_notifier.on_new_pdu(std::move(pdu), *(sockaddr_storage*)rx_msghdr[i].msg_hdr.msg_name); } else { logger.error("Could not allocate byte buffer. Received {} bytes on UDP socket", rx_msghdr[i].msg_len); diff --git a/lib/gateways/udp_network_gateway_impl.h b/lib/gateways/udp_network_gateway_impl.h index ee25bb7551..11d69f9271 100644 --- a/lib/gateways/udp_network_gateway_impl.h +++ b/lib/gateways/udp_network_gateway_impl.h @@ -79,6 +79,9 @@ class udp_network_gateway_impl final : public udp_network_gateway // Temporary Tx buffer for transmission. std::array tx_mem; + + // Helper boolean to avoid spamming the logs in case of buffer pool depletion + bool warn_low_buffer_pool = true; }; } // namespace srsran diff --git a/tests/unittests/gateways/CMakeLists.txt b/tests/unittests/gateways/CMakeLists.txt index a66710e821..72405ba3e9 100644 --- a/tests/unittests/gateways/CMakeLists.txt +++ b/tests/unittests/gateways/CMakeLists.txt @@ -19,4 +19,10 @@ set_tests_properties(sctp_network_gateway_test PROPERTIES LABELS "tsan") add_executable(udp_network_gateway_test udp_network_gateway_test.cpp) target_link_libraries(udp_network_gateway_test srsran_gateway srsran_support srslog gtest gtest_main) -gtest_discover_tests(udp_network_gateway_test) +add_test(udp_network_gateway_test udp_network_gateway_test) +set_tests_properties(udp_network_gateway_test PROPERTIES LABELS "tsan") + +add_executable(udp_network_gateway_pool_depletion_test udp_network_gateway_pool_depletion_test.cpp) +target_link_libraries(udp_network_gateway_pool_depletion_test srsran_gateway srsran_support srslog gtest gtest_main) +add_test(udp_network_gateway_pool_depletion_test udp_network_gateway_pool_depletion_test) +set_tests_properties(udp_network_gateway_pool_depletion_test PROPERTIES LABELS "tsan") diff --git a/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp b/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp new file mode 100644 index 0000000000..227105ae0f --- /dev/null +++ b/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp @@ -0,0 +1,164 @@ +/* + * + * 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 "test_helpers.h" +#include "srsran/gateways/udp_network_gateway.h" +#include "srsran/gateways/udp_network_gateway_factory.h" +#include "srsran/support/executors/manual_task_worker.h" + +using namespace srsran; + +constexpr uint32_t pool_size = 128; + +class udp_pool_network_gateway_tester : public ::testing::Test +{ +protected: + void SetUp() override + { + srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); + srslog::init(); + + // init GW logger + srslog::fetch_basic_logger("UDP-GW", false).set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("UDP-GW", false).set_hex_dump_max_size(100); + + tx_sock_fd = unique_fd{::socket(AF_INET, SOCK_DGRAM, 0)}; + ASSERT_TRUE(tx_sock_fd.is_open()); + + sockaddr_in tx_addr = {}; + tx_addr.sin_family = AF_INET; + tx_addr.sin_port = ::htons(0); + + ASSERT_EQ(::inet_pton(AF_INET, client_address_v4.data(), &tx_addr.sin_addr), 1); + ASSERT_EQ(::bind(tx_sock_fd.value(), (sockaddr*)&tx_addr, sizeof(tx_addr)), 0); + } + + void TearDown() override + { + // flush logger after each test + srslog::flush(); + + stop_token.store(true, std::memory_order_relaxed); + if (rx_thread.joinable()) { + rx_thread.join(); + } + } + + void set_config(udp_network_gateway_config server_config) + { + server = create_udp_network_gateway({std::move(server_config), server_data_notifier, io_tx_executor}); + ASSERT_NE(server, nullptr); + } + + // spawn a thread to receive data + void start_receive_thread() + { + rx_thread = std::thread([this]() { + stop_token.store(false); + while (not stop_token.load(std::memory_order_relaxed)) { + // call receive() on socket + server->receive(); + + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } + }); + } + + void send_to_server(const std::string& dest_addr, uint16_t port) + { + in_addr inaddr_v4 = {}; + in6_addr inaddr_v6 = {}; + sockaddr_storage addr_storage = {}; + + if (inet_pton(AF_INET, dest_addr.c_str(), &inaddr_v4) == 1) { + sockaddr_in* tmp = (sockaddr_in*)&addr_storage; + tmp->sin_family = AF_INET; + tmp->sin_addr = inaddr_v4; + tmp->sin_port = htons(port); + } else if (inet_pton(AF_INET6, dest_addr.c_str(), &inaddr_v6) == 1) { + sockaddr_in6* tmp = (sockaddr_in6*)&addr_storage; + tmp->sin6_family = AF_INET6; + tmp->sin6_addr = inaddr_v6; + tmp->sin6_port = htons(port); + } else { + FAIL(); + } + + std::array buffer = {}; + ::sendto(tx_sock_fd.value(), + buffer.data(), + buffer.size(), + 0, + reinterpret_cast(&addr_storage), + sizeof(addr_storage)); + } + + dummy_network_gateway_control_notifier server_control_notifier; + dummy_network_gateway_control_notifier client_control_notifier; + + dummy_network_gateway_data_notifier_with_src_addr server_data_notifier; + dummy_network_gateway_data_notifier_with_src_addr client_data_notifier; + + std::unique_ptr server; + + manual_task_worker io_tx_executor{128}; + + std::string server_address_v4 = "127.0.0.1"; + std::string client_address_v4 = "127.0.1.1"; + +private: + std::thread rx_thread; + std::atomic stop_token = {false}; + unique_fd tx_sock_fd; // we use a normal socket for transmission of packets instead of another UDP GW, to avoid having + // to use byte buffers for TX and having multiple threads allocating from the buffer pool +}; + +TEST_F(udp_pool_network_gateway_tester, when_config_valid_then_trx_succeeds) +{ + // create server config + udp_network_gateway_config server_config; + server_config.bind_address = server_address_v4; + server_config.bind_port = 0; + server_config.non_blocking_mode = false; + server_config.pool_occupancy_threshold = 0.5; + + // set configs + set_config(server_config); + + // create and bind gateways + ASSERT_TRUE(server->create_and_bind()); + + std::string server_address = {}; + ASSERT_TRUE(server->get_bind_address(server_address)); + std::optional server_port = server->get_bind_port(); + ASSERT_TRUE(server_port.has_value()); + start_receive_thread(); + + unsigned n_pdus = 64; + std::vector pdu_list; + for (unsigned i = 0; i < n_pdus; i++) { + send_to_server(server_address_v4, server_port.value()); + expected rx_pdu = server_data_notifier.get_rx_pdu_blocking(); + ASSERT_TRUE(rx_pdu.has_value()); + + pdu_list.push_back(std::move(rx_pdu.value())); // move pdus to keep pool full + } + + send_to_server(server_address_v4, server_port.value()); + expected rx_pdu = server_data_notifier.get_rx_pdu_blocking(); + ASSERT_FALSE(rx_pdu.has_value()); // should not have been received +} + +int main(int argc, char** argv) +{ + init_byte_buffer_segment_pool(pool_size); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From a57acdc0f15b1ff5669e260a1930082d8e77a9a5 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 25 Jul 2024 17:54:09 +0200 Subject: [PATCH 141/407] ofh: add a handler for the reception window close event. It check the context repository and notify pending contexts to the upper PHY --- .../ofh/receiver/ofh_receiver_configuration.h | 2 + lib/ofh/ofh_factories.cpp | 8 +- lib/ofh/receiver/CMakeLists.txt | 1 + .../receiver/ofh_closed_rx_window_handler.cpp | 102 ++++++++++++++++++ .../receiver/ofh_closed_rx_window_handler.h | 75 +++++++++++++ .../ofh_message_receiver_task_dispatcher.h | 1 + lib/ofh/receiver/ofh_receiver_factories.cpp | 7 +- lib/ofh/receiver/ofh_receiver_impl.cpp | 53 ++++++++- lib/ofh/receiver/ofh_receiver_impl.h | 25 ++++- .../ofh_uplane_prach_data_flow_notifier.cpp | 5 +- .../ofh_uplane_prach_data_flow_notifier.h | 1 + ...ofh_uplane_prach_symbol_data_flow_writer.h | 1 + ...fh_uplane_rx_symbol_data_flow_notifier.cpp | 7 +- .../ofh_uplane_rx_symbol_data_flow_notifier.h | 1 + .../ofh_uplane_rx_symbol_data_flow_writer.h | 1 + lib/ofh/support/prach_context_repository.h | 60 ++++++++--- lib/ofh/support/uplink_context_repository.h | 74 ++++++++----- ...lane_scheduling_commands_task_dispatcher.h | 2 +- .../transmitter/ofh_transmitter_factories.h | 1 + .../receiver/ofh_message_receiver_test.cpp | 23 +++- ...ane_prach_symbol_data_flow_writer_test.cpp | 5 + .../ofh_uplink_request_handler_impl_test.cpp | 1 + 22 files changed, 393 insertions(+), 63 deletions(-) create mode 100644 lib/ofh/receiver/ofh_closed_rx_window_handler.cpp create mode 100644 lib/ofh/receiver/ofh_closed_rx_window_handler.h diff --git a/include/srsran/ofh/receiver/ofh_receiver_configuration.h b/include/srsran/ofh/receiver/ofh_receiver_configuration.h index cc894529f8..27f635b8d3 100644 --- a/include/srsran/ofh/receiver/ofh_receiver_configuration.h +++ b/include/srsran/ofh/receiver/ofh_receiver_configuration.h @@ -56,6 +56,8 @@ struct receiver_config { bool ignore_ecpri_payload_size_field = false; /// If set to true, the sequence id encoded in a eCPRI packet is ignored. bool ignore_ecpri_seq_id_field = false; + /// If set to true, warn of unreceived Radio Unit frames. + bool warn_unreceived_ru_frames = true; }; } // namespace ofh diff --git a/lib/ofh/ofh_factories.cpp b/lib/ofh/ofh_factories.cpp index 0a2a0f1b3b..0d484ef275 100644 --- a/lib/ofh/ofh_factories.cpp +++ b/lib/ofh/ofh_factories.cpp @@ -43,6 +43,7 @@ static receiver_config generate_receiver_config(const sector_configuration& conf rx_config.is_prach_control_plane_enabled = config.is_prach_control_plane_enabled; rx_config.ignore_ecpri_payload_size_field = config.ignore_ecpri_payload_size_field; rx_config.ignore_ecpri_seq_id_field = config.ignore_ecpri_seq_id_field; + rx_config.warn_unreceived_ru_frames = config.warn_unreceived_ru_frames; // For the rx eAxCs, configure only those that will be used, so the other eAxCs can be discarded as soon as possible. rx_config.prach_eaxc.assign(config.prach_eaxc.begin(), config.prach_eaxc.begin() + config.nof_antennas_ul); @@ -153,10 +154,9 @@ std::unique_ptr srsran::ofh::create_ofh_sector(const sector_configuratio { unsigned repository_size = sector_cfg.max_processing_delay_slots * 4; - srslog::basic_logger* repo_logger = sector_cfg.warn_unreceived_ru_frames ? sector_deps.logger : nullptr; - auto cp_repo = std::make_shared(repository_size); - auto prach_repo = std::make_shared(repository_size, repo_logger); - auto slot_repo = std::make_shared(repository_size, repo_logger); + auto cp_repo = std::make_shared(repository_size); + auto prach_repo = std::make_shared(repository_size); + auto slot_repo = std::make_shared(repository_size); // Build the ethernet txrx. auto eth_txrx = create_txrx(sector_cfg, diff --git a/lib/ofh/receiver/CMakeLists.txt b/lib/ofh/receiver/CMakeLists.txt index 8cc1c59989..e745311f90 100644 --- a/lib/ofh/receiver/CMakeLists.txt +++ b/lib/ofh/receiver/CMakeLists.txt @@ -7,6 +7,7 @@ # set(SOURCES + ofh_closed_rx_window_handler.cpp ofh_data_flow_uplane_uplink_data_impl.cpp ofh_data_flow_uplane_uplink_prach_impl.cpp ofh_message_receiver.cpp diff --git a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp new file mode 100644 index 0000000000..42c2d29707 --- /dev/null +++ b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp @@ -0,0 +1,102 @@ +/* + * + * 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 "ofh_closed_rx_window_handler.h" +#include "srsran/support/executors/task_executor.h" + +using namespace srsran; +using namespace ofh; + +closed_rx_window_handler::closed_rx_window_handler(const closed_rx_window_handler_config& config, + closed_rx_window_handler_dependencies dependencies) : + notification_delay_in_symbols(config.nof_symbols_to_process_uplink + config.rx_timing_params.sym_end + 1), + log_unreceived_messages(config.warn_unreceived_ru_frames), + logger(*dependencies.logger), + executor(*dependencies.executor), + prach_repo(std::move(dependencies.prach_repo)), + uplink_repo(std::move(dependencies.uplink_repo)), + notifier(std::move(dependencies.notifier)) +{ + srsran_assert(dependencies.logger, "Invalid logger"); + srsran_assert(dependencies.executor, "Invalid executor"); + srsran_assert(prach_repo, "Invalid PRACH context repository"); + srsran_assert(uplink_repo, "Invalid uplink context repository"); + srsran_assert(notifier, "Invalid U-Plane received symbol notifier"); +} + +void closed_rx_window_handler::on_new_symbol(slot_symbol_point slot_symbol) +{ + if (!executor.defer([slot_symbol, this]() { + // Use an internal slot symbol to decide the context to notify. + slot_symbol_point internal_slot = slot_symbol - notification_delay_in_symbols; + handle_uplink(internal_slot); + handle_prach(internal_slot); + })) { + logger.warning("Failed to dispatch checking for lost messages in reception for slot '{}' and symbol '{}'", + slot_symbol.get_slot(), + slot_symbol.get_symbol_index()); + } +} + +void closed_rx_window_handler::handle_uplink(slot_symbol_point slot_symbol) +{ + const auto& context = + uplink_repo->pop_complete_resource_grid_symbol(slot_symbol.get_slot(), slot_symbol.get_symbol_index()); + + if (!context.has_value()) { + return; + } + + const auto ctx_value = context.value(); + uplane_rx_symbol_context notification_context = { + ctx_value.context.slot, slot_symbol.get_symbol_index(), ctx_value.context.sector}; + notifier->on_new_uplink_symbol(notification_context, ctx_value.grid->get_reader()); + + // Log unreceived messages. + if (log_unreceived_messages) { + logger.warning("Missed incoming User-Plane uplink messages for slot '{}', symbol '{}' and sector#{}", + ctx_value.context.slot, + slot_symbol.get_symbol_index(), + ctx_value.context.sector); + } + + logger.debug("Notifying UL symbol in slot '{}', symbol '{}' for sector#{}", + notification_context.slot, + notification_context.symbol, + notification_context.sector); +} + +void closed_rx_window_handler::handle_prach(slot_symbol_point slot_symbol) +{ + // As the PRACH is send when all the symbols are received, wait until new slot to notify it PRACH buffer. + if (slot_symbol.get_symbol_index() != 0) { + return; + } + + slot_point slot = slot_symbol.get_slot() - 1; + const auto& context = prach_repo->pop_prach_buffer(slot); + + // Nothing to do. + if (!context.has_value()) { + return; + } + + const auto& ctx_value = context.value<>(); + + notifier->on_new_prach_window_data(ctx_value.context, *ctx_value.buffer); + + if (log_unreceived_messages) { + logger.warning("Missed incoming User-Plane PRACH messages for slot '{}' and sector#{}", + ctx_value.context.sector, + ctx_value.context.sector); + } + + logger.debug("Notifying PRACH in slot '{}' for sector#{}", ctx_value.context.slot, ctx_value.context.sector); +} \ No newline at end of file diff --git a/lib/ofh/receiver/ofh_closed_rx_window_handler.h b/lib/ofh/receiver/ofh_closed_rx_window_handler.h new file mode 100644 index 0000000000..f2b51c7334 --- /dev/null +++ b/lib/ofh/receiver/ofh_closed_rx_window_handler.h @@ -0,0 +1,75 @@ +/* + * + * 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 "../support/prach_context_repository.h" +#include "../support/uplink_context_repository.h" +#include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" +#include "srsran/ofh/receiver/ofh_receiver_timing_parameters.h" +#include "srsran/ofh/timing/ofh_ota_symbol_boundary_notifier.h" +#include "srsran/ofh/timing/slot_symbol_point.h" +#include "srsran/srslog/logger.h" + +namespace srsran { + +class task_executor; + +namespace ofh { + +/// Closed reception window handler configuration. +struct closed_rx_window_handler_config { + /// Number of symbols that takes to decode an Open Fronthaul message. It delays closing the reception window. + unsigned nof_symbols_to_process_uplink = 0; + /// Open Fronthaul receive window parameters. + rx_window_timing_parameters rx_timing_params; + /// Warn unreceived Open Fronthaul messages. + bool warn_unreceived_ru_frames = true; +}; + +/// Closed reception window handler dependencies. +struct closed_rx_window_handler_dependencies { + srslog::basic_logger* logger = nullptr; + task_executor* executor = nullptr; + std::shared_ptr prach_repo; + std::shared_ptr uplink_repo; + std::shared_ptr notifier; +}; + +/// Open Fronthaul closed reception window handler. +class closed_rx_window_handler : public ota_symbol_boundary_notifier +{ +public: + closed_rx_window_handler(const closed_rx_window_handler_config& config, + closed_rx_window_handler_dependencies dependencies); + + void on_new_symbol(slot_symbol_point slot_symbol) override; + +private: + void handle_uplink(slot_symbol_point slot_symbol); + + void handle_prach(slot_symbol_point slot_symbol); + +private: + /// \brief Notification delay of the resource grid or PRACH buffer in symbol unit. + /// + /// This delay is calculated with the T4a_max parameter plus the number of symbols that takes to decode a received + /// Open Fronthaul message. + const unsigned notification_delay_in_symbols; + const bool log_unreceived_messages; + srslog::basic_logger& logger; + task_executor& executor; + std::shared_ptr prach_repo; + std::shared_ptr uplink_repo; + std::shared_ptr notifier; +}; + +} // namespace ofh +} // namespace srsran diff --git a/lib/ofh/receiver/ofh_message_receiver_task_dispatcher.h b/lib/ofh/receiver/ofh_message_receiver_task_dispatcher.h index 3db353af9e..81df17490b 100644 --- a/lib/ofh/receiver/ofh_message_receiver_task_dispatcher.h +++ b/lib/ofh/receiver/ofh_message_receiver_task_dispatcher.h @@ -11,6 +11,7 @@ #pragma once #include "ofh_message_receiver.h" +#include "srsran/srslog/srslog.h" #include "srsran/support/executors/task_executor.h" namespace srsran { diff --git a/lib/ofh/receiver/ofh_receiver_factories.cpp b/lib/ofh/receiver/ofh_receiver_factories.cpp index 169f76f61b..976a70c60d 100644 --- a/lib/ofh/receiver/ofh_receiver_factories.cpp +++ b/lib/ofh/receiver/ofh_receiver_factories.cpp @@ -105,8 +105,11 @@ resolve_receiver_dependencies(const receiver_config& { receiver_impl_dependencies dependencies; - dependencies.logger = &logger; - dependencies.executor = &uplink_executor; + dependencies.logger = &logger; + dependencies.executor = &uplink_executor; + dependencies.prach_repo = prach_context_repo; + dependencies.uplink_repo = ul_slot_context_repo; + dependencies.notifier = notifier; if (receiver_cfg.ignore_ecpri_payload_size_field) { dependencies.ecpri_decoder = ecpri::create_ecpri_packet_decoder_ignoring_payload_size(logger); diff --git a/lib/ofh/receiver/ofh_receiver_impl.cpp b/lib/ofh/receiver/ofh_receiver_impl.cpp index d1175505c9..5925c356ad 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.cpp +++ b/lib/ofh/receiver/ofh_receiver_impl.cpp @@ -32,8 +32,8 @@ static message_receiver_config get_message_receiver_configuration(const receiver return config; } -static message_receiver_dependencies get_message_receiver_dependencies(receiver_impl_dependencies&& rx_dependencies, - rx_window_checker& window_checker) +static message_receiver_dependencies get_message_receiver_dependencies(receiver_impl_dependencies& rx_dependencies, + rx_window_checker& window_checker) { message_receiver_dependencies dependencies; @@ -54,13 +54,58 @@ static message_receiver_dependencies get_message_receiver_dependencies(receiver_ return dependencies; } +static closed_rx_window_handler_config get_closed_rx_window_handler_config(const receiver_config& config) +{ + closed_rx_window_handler_config out_config; + out_config.warn_unreceived_ru_frames = config.warn_unreceived_ru_frames; + out_config.rx_timing_params = config.rx_timing_params; + // As it runs in the same executor, do not delay the reception window close. + out_config.nof_symbols_to_process_uplink = 0; + + return out_config; +} + +static closed_rx_window_handler_dependencies +get_closed_rx_window_handler_dependencies(receiver_impl_dependencies& dependencies) +{ + closed_rx_window_handler_dependencies out_dependencies; + out_dependencies.executor = dependencies.executor; + out_dependencies.logger = dependencies.logger; + out_dependencies.prach_repo = std::move(dependencies.prach_repo); + srsran_assert(out_dependencies.prach_repo, "Invalid PRACH context repository"); + out_dependencies.uplink_repo = std::move(dependencies.uplink_repo); + srsran_assert(out_dependencies.uplink_repo, "Invalid uplink context repository"); + out_dependencies.notifier = std::move(dependencies.notifier); + srsran_assert(out_dependencies.notifier, "Invalid OFH U-Plane notifier"); + + return out_dependencies; +} + +void ota_symbol_boundary_dispatcher::on_new_symbol(slot_symbol_point symbol_point) +{ + for (auto& handler : handlers) { + handler->on_new_symbol(symbol_point); + } +} + receiver_impl::receiver_impl(const receiver_config& config, receiver_impl_dependencies&& dependencies) : + closed_window_handler(get_closed_rx_window_handler_config(config), + get_closed_rx_window_handler_dependencies(dependencies)), window_checker(*dependencies.logger, config.rx_timing_params, std::chrono::duration( 1e6 / (get_nsymb_per_slot(config.cp) * get_nof_slots_per_subframe(config.scs)))), + symbol_boundary_dispatcher([](closed_rx_window_handler& handler, rx_window_checker& checker) { + std::vector handlers; + if (!checker.disabled()) { + handlers.push_back(&checker); + } + handlers.push_back(&handler); + + return handlers; + }(closed_window_handler, window_checker)), msg_receiver(get_message_receiver_configuration(config), - get_message_receiver_dependencies(std::move(dependencies), window_checker)), + get_message_receiver_dependencies(dependencies, window_checker)), rcv_task_dispatcher(msg_receiver, *dependencies.executor), ctrl(rcv_task_dispatcher) { @@ -68,7 +113,7 @@ receiver_impl::receiver_impl(const receiver_config& config, receiver_impl_depend ota_symbol_boundary_notifier* receiver_impl::get_ota_symbol_boundary_notifier() { - return window_checker.disabled() ? nullptr : &window_checker; + return &symbol_boundary_dispatcher; } controller& receiver_impl::get_controller() diff --git a/lib/ofh/receiver/ofh_receiver_impl.h b/lib/ofh/receiver/ofh_receiver_impl.h index 57b7d05809..83648a6364 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.h +++ b/lib/ofh/receiver/ofh_receiver_impl.h @@ -10,9 +10,8 @@ #pragma once -#include "../support/prach_context_repository.h" #include "../support/uplink_context_repository.h" -#include "../support/uplink_cplane_context_repository.h" +#include "ofh_closed_rx_window_handler.h" #include "ofh_message_receiver.h" #include "ofh_message_receiver_task_dispatcher.h" #include "ofh_receiver_controller.h" @@ -44,6 +43,26 @@ struct receiver_impl_dependencies { std::unique_ptr data_flow_prach; /// Sequence id checker. std::unique_ptr seq_id_checker; + /// PRACH context repository. + std::shared_ptr prach_repo; + /// Uplink context repository. + std::shared_ptr uplink_repo; + /// User-Plane received symbol notifier. + std::shared_ptr notifier; +}; + +/// OTA symbol boundary dispatcher for the receiver. +class ota_symbol_boundary_dispatcher : public ota_symbol_boundary_notifier +{ + std::vector handlers; + +public: + ota_symbol_boundary_dispatcher(std::vector handlers_) : handlers(std::move(handlers_)) + { + } + + // See interface for documentation + void on_new_symbol(slot_symbol_point symbol_point) override; }; /// \brief Open Fronthaul receiver. @@ -61,7 +80,9 @@ class receiver_impl : public receiver controller& get_controller() override; private: + closed_rx_window_handler closed_window_handler; rx_window_checker window_checker; + ota_symbol_boundary_dispatcher symbol_boundary_dispatcher; message_receiver_impl msg_receiver; ofh_message_receiver_task_dispatcher rcv_task_dispatcher; receiver_controller ctrl; diff --git a/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp b/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp index 4444b23290..0119e789cb 100644 --- a/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp +++ b/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp @@ -17,15 +17,12 @@ using namespace ofh; void uplane_prach_data_flow_notifier::notify_prach(slot_point slot) { expected context = - prach_context_repo->get(slot).try_getting_complete_prach_buffer(); + prach_context_repo->try_poping_complete_prach_buffer(slot); if (not context.has_value()) { return; } - // Clear the repository entry. - prach_context_repo->clear(slot); - const auto ctx_value = context.value(); notifier->on_new_prach_window_data(ctx_value.context, *ctx_value.buffer); diff --git a/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.h b/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.h index 62df58d277..2b46da8567 100644 --- a/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.h +++ b/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.h @@ -12,6 +12,7 @@ #include "../support/prach_context_repository.h" #include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" +#include "srsran/srslog/logger.h" namespace srsran { namespace ofh { diff --git a/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.h b/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.h index a20d71c398..b1a4fe91d9 100644 --- a/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.h +++ b/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.h @@ -11,6 +11,7 @@ #pragma once #include "../support/prach_context_repository.h" +#include "srsran/srslog/logger.h" namespace srsran { namespace ofh { diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp index a8c0db6713..5a0e41a4ea 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp @@ -17,15 +17,12 @@ using namespace ofh; void uplane_rx_symbol_data_flow_notifier::notify_received_symbol(slot_point slot, unsigned symbol) { expected context = - ul_context_repo->get(slot, symbol).try_getting_complete_resource_grid(); + ul_context_repo->try_poping_complete_resource_grid_symbol(slot, symbol); - if (not context.has_value()) { + if (!context.has_value()) { return; } - // Clear the repository entry. - ul_context_repo->clear(slot, symbol); - const auto ctx_value = context.value(); uplane_rx_symbol_context notification_context = {ctx_value.context.slot, symbol, ctx_value.context.sector}; notifier->on_new_uplink_symbol(notification_context, ctx_value.grid->get_reader()); diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.h b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.h index d69b465e97..6b123779e6 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.h +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.h @@ -12,6 +12,7 @@ #include "../support/uplink_context_repository.h" #include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" +#include "srsran/srslog/logger.h" namespace srsran { namespace ofh { diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.h b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.h index 2ccf6d7544..dc595fb4be 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.h +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.h @@ -11,6 +11,7 @@ #pragma once #include "../support/uplink_context_repository.h" +#include "srsran/srslog/logger.h" namespace srsran { namespace ofh { diff --git a/lib/ofh/support/prach_context_repository.h b/lib/ofh/support/prach_context_repository.h index 2e54e47723..c1606437f8 100644 --- a/lib/ofh/support/prach_context_repository.h +++ b/lib/ofh/support/prach_context_repository.h @@ -18,7 +18,6 @@ #include "srsran/ran/prach/prach_constants.h" #include "srsran/ran/prach/prach_frequency_mapping.h" #include "srsran/ran/prach/prach_preamble_information.h" -#include "srsran/srslog/srslog.h" #include "srsran/srsvec/copy.h" #include #include @@ -140,7 +139,7 @@ class prach_context /// Tries to get a complete PRACH buffer. A PRACH buffer is considered completed when all the PRBs for all the ports /// have been written. - expected try_getting_complete_prach_buffer() const + expected try_getting_complete_prach_buffer() { if (!context_info.buffer) { return make_unexpected(default_error_t{}); @@ -155,6 +154,9 @@ class prach_context return {context_info}; } + /// Returns the information of this PRACH context. + const prach_context_information& get_context_information() const { return context_info; } + private: /// PRACH context information prach_context_information context_info; @@ -176,7 +178,6 @@ class prach_context_repository /// System frame number maximum value in this repository. static constexpr unsigned SFN_MAX_VALUE = 1U << 8; - srslog::basic_logger* logger; std::vector buffer; //: TODO: make this lock free mutable std::mutex mutex; @@ -198,10 +199,7 @@ class prach_context_repository } public: - explicit prach_context_repository(unsigned size_, srslog::basic_logger* logger_ = nullptr) : - logger(logger_), buffer(size_) - { - } + explicit prach_context_repository(unsigned size_) : buffer(size_) {} /// Adds the given entry to the repository at slot. void add(const prach_buffer_context& context, @@ -213,14 +211,11 @@ class prach_context_repository slot_point current_slot = slot.value_or(context.slot); - if (logger) { - if (!entry(current_slot).empty()) { - const prach_buffer_context& previous_context = entry(current_slot).get_context(); - logger->warning("Missed incoming User-Plane PRACH messages for slot '{}' and sector#{}", - previous_context.slot, - previous_context.sector); - } - } + // Sanity check. As the context are notified on reception window close, the context should always be empty. + srsran_assert(entry(current_slot).empty(), + "Unnotified PRACH context for slot '{}' and sector '{}'", + entry(current_slot).get_context().slot, + entry(current_slot).get_context().sector); entry(current_slot) = prach_context(context, buffer_, start_symbol); } @@ -239,6 +234,41 @@ class prach_context_repository return entry(slot); } + /// \brief Tries to pop a complete PRACH buffer from the repository. + /// + /// A PRACH buffer is considered completed when all the PRBs for all the ports have been written. If the pop was a + /// success, clears the entry of the repository for that slot. + expected try_poping_complete_prach_buffer(slot_point slot) + { + std::lock_guard lock(mutex); + + const auto result = entry(slot).try_getting_complete_prach_buffer(); + + // Clear the entry if the pop was a success. + if (result.has_value()) { + entry(slot) = {}; + } + + return result; + } + + /// Pops a PRACH buffer from the repository. + expected pop_prach_buffer(slot_point slot) + { + std::lock_guard lock(mutex); + + auto& context = entry(slot); + + if (context.empty()) { + return make_unexpected(default_error_t()); + } + + const auto result = context.get_context_information(); + context = {}; + + return result; + } + /// Clears the given slot entry. void clear(slot_point slot) { diff --git a/lib/ofh/support/uplink_context_repository.h b/lib/ofh/support/uplink_context_repository.h index 35e8864a62..d0561e5efe 100644 --- a/lib/ofh/support/uplink_context_repository.h +++ b/lib/ofh/support/uplink_context_repository.h @@ -12,15 +12,12 @@ #include "srsran/adt/expected.h" #include "srsran/ofh/ofh_constants.h" -#include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" #include "srsran/phy/support/resource_grid.h" #include "srsran/phy/support/resource_grid_context.h" -#include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/support/resource_grid_writer.h" #include "srsran/ran/cyclic_prefix.h" #include "srsran/ran/resource_allocation/ofdm_symbol_range.h" #include "srsran/ran/resource_block.h" -#include "srsran/srslog/srslog.h" #include "srsran/srsvec/copy.h" #include @@ -94,6 +91,9 @@ class uplink_context return {grid}; } + /// Returns the context grid information. + const uplink_context_resource_grid_info& get_uplink_context_resource_grid_info() const { return grid; } + private: /// Returns true when all the REs for the current symbol have been written. bool have_all_prbs_been_written() const @@ -114,7 +114,6 @@ class uplink_context_repository /// System frame number maximum value in this repository. static constexpr unsigned SFN_MAX_VALUE = 1U << 8; - srslog::basic_logger* logger; std::vector> buffer; //: TODO: make this lock free mutable std::mutex mutex; @@ -140,35 +139,21 @@ class uplink_context_repository } public: - explicit uplink_context_repository(unsigned size_, srslog::basic_logger* logger_ = nullptr) : - logger(logger_), buffer(size_) - { - } + explicit uplink_context_repository(unsigned size_) : buffer(size_) {} /// Adds the given entry to the repository at slot. void add(const resource_grid_context& context, resource_grid& grid, const ofdm_symbol_range& symbol_range) { std::lock_guard lock(mutex); - // For logging purposes, check every symbol of the grid looking for existing contexts. - if (logger) { - for (unsigned symbol_id = 0, symbol_end = grid.get_reader().get_nof_symbols(); symbol_id != symbol_end; - ++symbol_id) { - if (auto& symbol_info = entry(context.slot, symbol_id); !symbol_info.empty()) { - const resource_grid_context& previous_context = symbol_info.get_grid_context(); - logger->warning("Missed incoming User-Plane uplink messages for slot '{}', symbol '{}' and sector#{}", - previous_context.slot, - symbol_id, - previous_context.sector); - - // Clear the stored context. - symbol_info = {}; - } - } - } - for (unsigned symbol_id = symbol_range.start(), symbol_end = symbol_range.stop(); symbol_id != symbol_end; ++symbol_id) { + // Sanity check. As the context are notified on reception window close, the context should always be empty. + srsran_assert(entry(context.slot, symbol_id).empty(), + "Unnotified PRACH context for slot '{}', symbol '{}' and sector '{}'", + entry(context.slot, symbol_id).get_grid_context().slot, + symbol_id, + entry(context.slot, symbol_id).get_grid_context().sector); entry(context.slot, symbol_id) = uplink_context(symbol_id, context, grid); } } @@ -187,6 +172,45 @@ class uplink_context_repository return entry(slot, symbol); } + /// \brief Tries to pop a complete resource grid for the given slot and symbol. + /// + /// A resource grid is considered completed when all the PRBs for all the ports have been written. + expected try_poping_complete_resource_grid_symbol(slot_point slot, + unsigned symbol) + { + std::lock_guard lock(mutex); + + const auto result = entry(slot, symbol).try_getting_complete_resource_grid(); + + // Symbol is complete or exists. Clear the context. + if (result.has_value()) { + entry(slot, symbol) = {}; + } + + return result; + } + + /// Pops a complete resource grid for the given slot and symbol. + expected pop_complete_resource_grid_symbol(slot_point slot, + unsigned symbol) + { + std::lock_guard lock(mutex); + + const auto& result = entry(slot, symbol); + + // Symbol does not exists. Do nothing. + if (result.empty()) { + return make_unexpected(default_error_t{}); + } + + const auto info = result.get_uplink_context_resource_grid_info(); + + // Clear the symbol. + entry(slot, symbol) = {}; + + return {info}; + } + /// Clears the repository entry for the given slot and symbol. void clear(slot_point slot, unsigned symbol) { diff --git a/lib/ofh/transmitter/ofh_data_flow_cplane_scheduling_commands_task_dispatcher.h b/lib/ofh/transmitter/ofh_data_flow_cplane_scheduling_commands_task_dispatcher.h index d2f68b5dc3..2813e8647d 100644 --- a/lib/ofh/transmitter/ofh_data_flow_cplane_scheduling_commands_task_dispatcher.h +++ b/lib/ofh/transmitter/ofh_data_flow_cplane_scheduling_commands_task_dispatcher.h @@ -11,8 +11,8 @@ #pragma once #include "ofh_data_flow_cplane_scheduling_commands.h" +#include "srsran/srslog/srslog.h" #include "srsran/support/executors/task_executor.h" -#include #include namespace srsran { diff --git a/lib/ofh/transmitter/ofh_transmitter_factories.h b/lib/ofh/transmitter/ofh_transmitter_factories.h index a06553f7af..b6ad0d97fc 100644 --- a/lib/ofh/transmitter/ofh_transmitter_factories.h +++ b/lib/ofh/transmitter/ofh_transmitter_factories.h @@ -15,6 +15,7 @@ #include "../support/uplink_cplane_context_repository.h" #include "srsran/ofh/transmitter/ofh_transmitter.h" #include "srsran/ofh/transmitter/ofh_transmitter_configuration.h" +#include "srsran/srslog/logger.h" namespace srsran { diff --git a/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp b/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp index 60f4a9bb62..9617e420fa 100644 --- a/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp @@ -8,9 +8,11 @@ * */ +#include "../../../../lib/ofh/receiver/ofh_closed_rx_window_handler.h" #include "../../../../lib/ofh/receiver/ofh_message_receiver.h" #include "../../../../lib/ofh/receiver/ofh_rx_window_checker.h" #include "../../../../lib/ofh/receiver/ofh_sequence_id_checker_dummy_impl.h" +#include "../../support/task_executor_test_doubles.h" #include "../compression/ofh_iq_decompressor_test_doubles.h" #include "srsran/ofh/ethernet/ethernet_unique_buffer.h" #include "srsran/ofh/ofh_factories.h" @@ -21,6 +23,15 @@ using namespace ofh; using namespace srsran::ofh::testing; namespace { + +/// Dummy User-Plane received symbol notifier. +class dummy_uplane_rx_symbol_notifier : public uplane_rx_symbol_notifier +{ +public: + void on_new_uplink_symbol(const uplane_rx_symbol_context& context, const resource_grid_reader& grid) override {} + void on_new_prach_window_data(const prach_buffer_context& context, const prach_buffer& buffer) override {} +}; + /// Dummy Ethernet receive buffer. class dummy_eth_rx_buffer : public ether::rx_buffer { @@ -124,6 +135,8 @@ class ofh_message_receiver_fixture : public ::testing::Test 0xaefe}; static_vector ul_prach_eaxc = {0, 1}; static_vector ul_eaxc = {4, 5}; + manual_task_worker_always_enqueue_tasks executor; + closed_rx_window_handler closed_window_handler; rx_window_checker window_checker; ecpri::packet_parameters ecpri_params; data_flow_uplane_uplink_data_spy* df_uplink; @@ -134,7 +147,15 @@ class ofh_message_receiver_fixture : public ::testing::Test public: ofh_message_receiver_fixture() : - window_checker(srslog::fetch_basic_logger("TEST"), {}, {}), ul_handler(generate_config(), generate_dependencies()) + executor(20), + closed_window_handler({}, + {&srslog::fetch_basic_logger("TEST"), + &executor, + std::make_shared(20), + std::make_shared(20), + std::make_shared()}), + window_checker(srslog::fetch_basic_logger("TEST"), {}, {}), + ul_handler(generate_config(), generate_dependencies()) { window_checker.on_new_symbol({{1, 0}, 0, 14}); } diff --git a/tests/unittests/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer_test.cpp b/tests/unittests/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer_test.cpp index 6b3d6d2758..b285cd3ad9 100644 --- a/tests/unittests/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer_test.cpp @@ -104,6 +104,7 @@ TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, decoded_prbs_outside_pr TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, decoded_prbs_before_prach_prbs_do_not_write) { + repo->clear(slot); buffer_context.pusch_scs = subcarrier_spacing::kHz60; buffer_context.format = prach_format_type::zero; unsigned nof_symbols_ = 1U; @@ -126,6 +127,7 @@ TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, decoded_prbs_before_pra TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, prbs_at_the_beginning_write_the_expected_re) { + repo->clear(slot); buffer_context.pusch_scs = subcarrier_spacing::kHz60; buffer_context.format = prach_format_type::zero; unsigned nof_symbols_ = 1U; @@ -148,6 +150,7 @@ TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, prbs_at_the_beginning_w TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, 60kHz_long_format_one_message) { + repo->clear(slot); buffer_context.pusch_scs = subcarrier_spacing::kHz60; buffer_context.format = prach_format_type::zero; preamble_length = 839; @@ -171,6 +174,7 @@ TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, 60kHz_long_format_one_m TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, 60kHz_long_format_one_message_all_prbs) { + repo->clear(slot); buffer_context.pusch_scs = subcarrier_spacing::kHz60; buffer_context.format = prach_format_type::zero; preamble_length = 839; @@ -215,6 +219,7 @@ TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, decoded_prbs_in_one_pac TEST_P(ofh_uplane_prach_symbol_data_flow_writer_fixture, decoded_prbs_with_start_symbol_offset_passes) { + repo->clear(slot); buffer = prach_buffer_dummy(nof_symbols, is_long_preamble(buffer_context.format)); // Offset the start symbol. buffer_context.start_symbol = 2; diff --git a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp index 7becd09f4e..41cfaac9e4 100644 --- a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp @@ -10,6 +10,7 @@ #include "../../../../lib/ofh/transmitter/ofh_uplink_request_handler_impl.h" #include "ofh_data_flow_cplane_scheduling_commands_test_doubles.h" +#include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" #include "srsran/phy/support/prach_buffer.h" #include "srsran/phy/support/resource_grid.h" #include "srsran/phy/support/resource_grid_mapper.h" From 1e7059d057fff53a8839850c01933a7374ff833f Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 1 Aug 2024 17:36:35 +0200 Subject: [PATCH 142/407] test: added t4a config to tests changed the rx executor for the ofh_integration test to locked MPMC. --- include/srsran/ofh/timing/slot_symbol_point.h | 18 ++++++++ lib/ofh/ethernet/ethernet_receiver_impl.cpp | 2 +- .../receiver/ofh_closed_rx_window_handler.cpp | 42 ++++++++----------- .../receiver/ofh_closed_rx_window_handler.h | 24 +++++++---- lib/ofh/receiver/ofh_message_receiver.h | 4 +- lib/ofh/receiver/ofh_receiver_factories.cpp | 30 +++++++------ lib/ofh/receiver/ofh_receiver_impl.cpp | 29 ++++--------- lib/ofh/receiver/ofh_receiver_impl.h | 41 +++++++++--------- .../ofh_uplane_prach_data_flow_notifier.cpp | 2 +- ...fh_uplane_rx_symbol_data_flow_notifier.cpp | 2 +- lib/ofh/support/prach_context_repository.h | 15 ++----- lib/ofh/support/uplink_context_repository.h | 17 +++----- tests/e2e/tests/viavi/test_declaration.yml | 2 +- .../ofh/ofh_integration_test.cpp | 8 ++-- 14 files changed, 119 insertions(+), 117 deletions(-) diff --git a/include/srsran/ofh/timing/slot_symbol_point.h b/include/srsran/ofh/timing/slot_symbol_point.h index 2c39cbbbe6..98f73aed4c 100644 --- a/include/srsran/ofh/timing/slot_symbol_point.h +++ b/include/srsran/ofh/timing/slot_symbol_point.h @@ -32,12 +32,30 @@ class slot_symbol_point srsran_assert(numerology < NOF_NUMEROLOGIES, "Invalid numerology idx={} passed", unsigned(numerology)); } + slot_symbol_point(const slot_symbol_point& symbol_point) : + nof_symbols(symbol_point.get_nof_symbols()), + numerology(symbol_point.get_numerology()), + count_val(symbol_point.to_uint()) + { + } + slot_symbol_point& operator=(const slot_symbol_point& symbol_point) + { + nof_symbols = symbol_point.get_nof_symbols(); + numerology = symbol_point.get_numerology(); + count_val = symbol_point.to_uint(); + + return *this; + } + /// Slot point. slot_point get_slot() const { return numerology < NOF_NUMEROLOGIES ? slot_point(numerology, count_val / nof_symbols) : slot_point(); } + /// Returns true if the slot symbol point is valid, false otherwise. + bool is_valid() const { return nof_symbols != 0 && numerology < NOF_NUMEROLOGIES; } + /// Symbol index in a slot. Value: (0..nof_symbols-1). unsigned get_symbol_index() const { return count_val % nof_symbols; } diff --git a/lib/ofh/ethernet/ethernet_receiver_impl.cpp b/lib/ofh/ethernet/ethernet_receiver_impl.cpp index 9b3a4a8ff0..784c40a46e 100644 --- a/lib/ofh/ethernet/ethernet_receiver_impl.cpp +++ b/lib/ofh/ethernet/ethernet_receiver_impl.cpp @@ -153,7 +153,7 @@ void receiver_impl::receive() trace_point tp = ofh_tracer.now(); auto exp_buffer = buffer_pool.reserve(); - if (not exp_buffer.has_value()) { + if (!exp_buffer.has_value()) { logger.warning("No buffer is available for receiving an Ethernet packet"); return; } diff --git a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp index 42c2d29707..42d63dd61a 100644 --- a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp +++ b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp @@ -14,8 +14,8 @@ using namespace srsran; using namespace ofh; -closed_rx_window_handler::closed_rx_window_handler(const closed_rx_window_handler_config& config, - closed_rx_window_handler_dependencies dependencies) : +closed_rx_window_handler::closed_rx_window_handler(const closed_rx_window_handler_config& config, + closed_rx_window_handler_dependencies&& dependencies) : notification_delay_in_symbols(config.nof_symbols_to_process_uplink + config.rx_timing_params.sym_end + 1), log_unreceived_messages(config.warn_unreceived_ru_frames), logger(*dependencies.logger), @@ -24,31 +24,26 @@ closed_rx_window_handler::closed_rx_window_handler(const closed_rx_window_handle uplink_repo(std::move(dependencies.uplink_repo)), notifier(std::move(dependencies.notifier)) { - srsran_assert(dependencies.logger, "Invalid logger"); - srsran_assert(dependencies.executor, "Invalid executor"); srsran_assert(prach_repo, "Invalid PRACH context repository"); srsran_assert(uplink_repo, "Invalid uplink context repository"); srsran_assert(notifier, "Invalid U-Plane received symbol notifier"); } -void closed_rx_window_handler::on_new_symbol(slot_symbol_point slot_symbol) +void closed_rx_window_handler::on_new_symbol(slot_symbol_point symbol_point) { - if (!executor.defer([slot_symbol, this]() { - // Use an internal slot symbol to decide the context to notify. - slot_symbol_point internal_slot = slot_symbol - notification_delay_in_symbols; - handle_uplink(internal_slot); - handle_prach(internal_slot); + if (!executor.defer([internal_slot = symbol_point - notification_delay_in_symbols, this]() { + handle_uplink_context(internal_slot); + handle_prach_context(internal_slot); })) { - logger.warning("Failed to dispatch checking for lost messages in reception for slot '{}' and symbol '{}'", - slot_symbol.get_slot(), - slot_symbol.get_symbol_index()); + logger.warning("Failed to dispatch task for checking for lost messages in reception for slot '{}' and symbol '{}'", + symbol_point.get_slot(), + symbol_point.get_symbol_index()); } } -void closed_rx_window_handler::handle_uplink(slot_symbol_point slot_symbol) +void closed_rx_window_handler::handle_uplink_context(slot_symbol_point symbol_point) { - const auto& context = - uplink_repo->pop_complete_resource_grid_symbol(slot_symbol.get_slot(), slot_symbol.get_symbol_index()); + const auto& context = uplink_repo->pop_resource_grid_symbol(symbol_point.get_slot(), symbol_point.get_symbol_index()); if (!context.has_value()) { return; @@ -56,14 +51,13 @@ void closed_rx_window_handler::handle_uplink(slot_symbol_point slot_symbol) const auto ctx_value = context.value(); uplane_rx_symbol_context notification_context = { - ctx_value.context.slot, slot_symbol.get_symbol_index(), ctx_value.context.sector}; + ctx_value.context.slot, symbol_point.get_symbol_index(), ctx_value.context.sector}; notifier->on_new_uplink_symbol(notification_context, ctx_value.grid->get_reader()); - // Log unreceived messages. if (log_unreceived_messages) { logger.warning("Missed incoming User-Plane uplink messages for slot '{}', symbol '{}' and sector#{}", ctx_value.context.slot, - slot_symbol.get_symbol_index(), + symbol_point.get_symbol_index(), ctx_value.context.sector); } @@ -73,14 +67,14 @@ void closed_rx_window_handler::handle_uplink(slot_symbol_point slot_symbol) notification_context.sector); } -void closed_rx_window_handler::handle_prach(slot_symbol_point slot_symbol) +void closed_rx_window_handler::handle_prach_context(slot_symbol_point symbol_point) { - // As the PRACH is send when all the symbols are received, wait until new slot to notify it PRACH buffer. - if (slot_symbol.get_symbol_index() != 0) { + // As the PRACH is sent when all the symbols are received, wait until new slot to notify it PRACH buffer. + if (symbol_point.get_symbol_index() != 0) { return; } - slot_point slot = slot_symbol.get_slot() - 1; + slot_point slot = symbol_point.get_slot() - 1; const auto& context = prach_repo->pop_prach_buffer(slot); // Nothing to do. @@ -99,4 +93,4 @@ void closed_rx_window_handler::handle_prach(slot_symbol_point slot_symbol) } logger.debug("Notifying PRACH in slot '{}' for sector#{}", ctx_value.context.slot, ctx_value.context.sector); -} \ No newline at end of file +} diff --git a/lib/ofh/receiver/ofh_closed_rx_window_handler.h b/lib/ofh/receiver/ofh_closed_rx_window_handler.h index f2b51c7334..da240d7d57 100644 --- a/lib/ofh/receiver/ofh_closed_rx_window_handler.h +++ b/lib/ofh/receiver/ofh_closed_rx_window_handler.h @@ -26,7 +26,8 @@ namespace ofh { /// Closed reception window handler configuration. struct closed_rx_window_handler_config { - /// Number of symbols that takes to decode an Open Fronthaul message. It delays closing the reception window. + /// Time in number of symbols that the decoder needs to process an Open Fronthaul message. It delays closing the + /// reception window. unsigned nof_symbols_to_process_uplink = 0; /// Open Fronthaul receive window parameters. rx_window_timing_parameters rx_timing_params; @@ -47,18 +48,27 @@ struct closed_rx_window_handler_dependencies { class closed_rx_window_handler : public ota_symbol_boundary_notifier { public: - closed_rx_window_handler(const closed_rx_window_handler_config& config, - closed_rx_window_handler_dependencies dependencies); + closed_rx_window_handler(const closed_rx_window_handler_config& config, + closed_rx_window_handler_dependencies&& dependencies); - void on_new_symbol(slot_symbol_point slot_symbol) override; + // See interface for documentation. + void on_new_symbol(slot_symbol_point symbol_point) override; private: - void handle_uplink(slot_symbol_point slot_symbol); + /// \brief Handles the uplink context for the closed reception window given by symbol point. + /// + /// Pops an uplink context from the uplink repository and when the context is valid, notifies it using the User-Plane + /// received symbol notifier. + void handle_uplink_context(slot_symbol_point symbol_point); - void handle_prach(slot_symbol_point slot_symbol); + /// \brief Handles the PRACH context for the closed reception window given by symbol point. + /// + /// Pops a PRACH context from the PRACH repository and when the context is valid, notifies it using the User-Plane + /// received symbol notifier. + void handle_prach_context(slot_symbol_point symbol_point); private: - /// \brief Notification delay of the resource grid or PRACH buffer in symbol unit. + /// \brief Notification delay of the resource grid or PRACH buffer in symbol units. /// /// This delay is calculated with the T4a_max parameter plus the number of symbols that takes to decode a received /// Open Fronthaul message. diff --git a/lib/ofh/receiver/ofh_message_receiver.h b/lib/ofh/receiver/ofh_message_receiver.h index 5df7100da2..2e57e85e5b 100644 --- a/lib/ofh/receiver/ofh_message_receiver.h +++ b/lib/ofh/receiver/ofh_message_receiver.h @@ -45,11 +45,11 @@ struct message_receiver_config { /// Message receiver dependencies. struct message_receiver_dependencies { /// Logger. - srslog::basic_logger* logger; + srslog::basic_logger* logger = nullptr; /// Ethernet receiver. std::unique_ptr eth_receiver; /// Reception window checker. - rx_window_checker* window_checker; + rx_window_checker* window_checker = nullptr; /// eCPRI packet decoder. std::unique_ptr ecpri_decoder; /// Ethernet frame decoder. diff --git a/lib/ofh/receiver/ofh_receiver_factories.cpp b/lib/ofh/receiver/ofh_receiver_factories.cpp index 976a70c60d..6bfff07d07 100644 --- a/lib/ofh/receiver/ofh_receiver_factories.cpp +++ b/lib/ofh/receiver/ofh_receiver_factories.cpp @@ -104,31 +104,37 @@ resolve_receiver_dependencies(const receiver_config& std::shared_ptr ul_cp_context_repo) { receiver_impl_dependencies dependencies; + dependencies.logger = &logger; + dependencies.executor = &uplink_executor; - dependencies.logger = &logger; - dependencies.executor = &uplink_executor; - dependencies.prach_repo = prach_context_repo; - dependencies.uplink_repo = ul_slot_context_repo; - dependencies.notifier = notifier; + auto& rx_window_handler_dependencies = dependencies.window_handler_dependencies; + rx_window_handler_dependencies.logger = &logger; + rx_window_handler_dependencies.executor = &uplink_executor; + rx_window_handler_dependencies.prach_repo = prach_context_repo; + rx_window_handler_dependencies.uplink_repo = ul_slot_context_repo; + rx_window_handler_dependencies.notifier = notifier; + + auto& msg_rx_dependencies = dependencies.msg_rx_dependencies; + msg_rx_dependencies.logger = &logger; if (receiver_cfg.ignore_ecpri_payload_size_field) { - dependencies.ecpri_decoder = ecpri::create_ecpri_packet_decoder_ignoring_payload_size(logger); + msg_rx_dependencies.ecpri_decoder = ecpri::create_ecpri_packet_decoder_ignoring_payload_size(logger); } else { - dependencies.ecpri_decoder = ecpri::create_ecpri_packet_decoder_using_payload_size(logger); + msg_rx_dependencies.ecpri_decoder = ecpri::create_ecpri_packet_decoder_using_payload_size(logger); } - dependencies.eth_frame_decoder = ether::create_vlan_frame_decoder(logger); + msg_rx_dependencies.eth_frame_decoder = ether::create_vlan_frame_decoder(logger); - dependencies.data_flow_uplink = + msg_rx_dependencies.data_flow_uplink = create_uplink_data_flow(receiver_cfg, logger, notifier, std::move(ul_slot_context_repo), ul_cp_context_repo); - dependencies.data_flow_prach = + msg_rx_dependencies.data_flow_prach = create_uplink_prach_data_flow(receiver_cfg, logger, notifier, std::move(prach_context_repo), ul_cp_context_repo); - dependencies.seq_id_checker = + msg_rx_dependencies.seq_id_checker = (receiver_cfg.ignore_ecpri_seq_id_field) ? static_cast>(std::make_unique()) : static_cast>(std::make_unique()); - dependencies.eth_receiver = std::move(eth_receiver); + msg_rx_dependencies.eth_receiver = std::move(eth_receiver); return dependencies; } diff --git a/lib/ofh/receiver/ofh_receiver_impl.cpp b/lib/ofh/receiver/ofh_receiver_impl.cpp index 5925c356ad..ce1bf0172f 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.cpp +++ b/lib/ofh/receiver/ofh_receiver_impl.cpp @@ -32,15 +32,16 @@ static message_receiver_config get_message_receiver_configuration(const receiver return config; } -static message_receiver_dependencies get_message_receiver_dependencies(receiver_impl_dependencies& rx_dependencies, - rx_window_checker& window_checker) +static message_receiver_dependencies +get_message_receiver_dependencies(receiver_impl_dependencies::message_rx_dependencies rx_dependencies, + rx_window_checker& window_checker) { message_receiver_dependencies dependencies; - dependencies.logger = rx_dependencies.logger; dependencies.window_checker = &window_checker; dependencies.eth_receiver = std::move(rx_dependencies.eth_receiver); - dependencies.ecpri_decoder = std::move(rx_dependencies.ecpri_decoder); + srsran_assert(dependencies.eth_receiver, "Invalid ethernet receiver"); + dependencies.ecpri_decoder = std::move(rx_dependencies.ecpri_decoder); srsran_assert(dependencies.ecpri_decoder, "Invalid eCPRI decoder"); dependencies.eth_frame_decoder = std::move(rx_dependencies.eth_frame_decoder); srsran_assert(dependencies.eth_frame_decoder, "Invalid Ethernet frame decoder"); @@ -65,22 +66,6 @@ static closed_rx_window_handler_config get_closed_rx_window_handler_config(const return out_config; } -static closed_rx_window_handler_dependencies -get_closed_rx_window_handler_dependencies(receiver_impl_dependencies& dependencies) -{ - closed_rx_window_handler_dependencies out_dependencies; - out_dependencies.executor = dependencies.executor; - out_dependencies.logger = dependencies.logger; - out_dependencies.prach_repo = std::move(dependencies.prach_repo); - srsran_assert(out_dependencies.prach_repo, "Invalid PRACH context repository"); - out_dependencies.uplink_repo = std::move(dependencies.uplink_repo); - srsran_assert(out_dependencies.uplink_repo, "Invalid uplink context repository"); - out_dependencies.notifier = std::move(dependencies.notifier); - srsran_assert(out_dependencies.notifier, "Invalid OFH U-Plane notifier"); - - return out_dependencies; -} - void ota_symbol_boundary_dispatcher::on_new_symbol(slot_symbol_point symbol_point) { for (auto& handler : handlers) { @@ -90,7 +75,7 @@ void ota_symbol_boundary_dispatcher::on_new_symbol(slot_symbol_point symbol_poin receiver_impl::receiver_impl(const receiver_config& config, receiver_impl_dependencies&& dependencies) : closed_window_handler(get_closed_rx_window_handler_config(config), - get_closed_rx_window_handler_dependencies(dependencies)), + std::move(dependencies.window_handler_dependencies)), window_checker(*dependencies.logger, config.rx_timing_params, std::chrono::duration( @@ -105,7 +90,7 @@ receiver_impl::receiver_impl(const receiver_config& config, receiver_impl_depend return handlers; }(closed_window_handler, window_checker)), msg_receiver(get_message_receiver_configuration(config), - get_message_receiver_dependencies(dependencies, window_checker)), + get_message_receiver_dependencies(std::move(dependencies.msg_rx_dependencies), window_checker)), rcv_task_dispatcher(msg_receiver, *dependencies.executor), ctrl(rcv_task_dispatcher) { diff --git a/lib/ofh/receiver/ofh_receiver_impl.h b/lib/ofh/receiver/ofh_receiver_impl.h index 83648a6364..0259303f9f 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.h +++ b/lib/ofh/receiver/ofh_receiver_impl.h @@ -27,28 +27,31 @@ namespace ofh { /// Open Fronthaul receiver implementation dependencies. struct receiver_impl_dependencies { + /// Message receiver dependencies. + struct message_rx_dependencies { + /// Logger. + srslog::basic_logger* logger = nullptr; + /// Ethernet receiver. + std::unique_ptr eth_receiver; + /// eCPRI packet decoder. + std::unique_ptr ecpri_decoder; + /// Ethernet frame decoder. + std::unique_ptr eth_frame_decoder; + /// User-Plane uplink data flow. + std::unique_ptr data_flow_uplink; + /// User-Plane uplink PRACH data flow. + std::unique_ptr data_flow_prach; + /// Sequence id checker. + std::unique_ptr seq_id_checker; + }; /// Logger. srslog::basic_logger* logger = nullptr; - /// Uplink task executor. + /// Task executor. task_executor* executor = nullptr; - /// Ethernet receiver. - std::unique_ptr eth_receiver; - /// eCPRI packet decoder. - std::unique_ptr ecpri_decoder; - /// Ethernet frame decoder. - std::unique_ptr eth_frame_decoder; - /// User-Plane uplink data flow. - std::unique_ptr data_flow_uplink; - /// User-Plane uplink PRACH data flow. - std::unique_ptr data_flow_prach; - /// Sequence id checker. - std::unique_ptr seq_id_checker; - /// PRACH context repository. - std::shared_ptr prach_repo; - /// Uplink context repository. - std::shared_ptr uplink_repo; - /// User-Plane received symbol notifier. - std::shared_ptr notifier; + /// Message receiver dependencies. + message_rx_dependencies msg_rx_dependencies; + /// Closed reception window handler dependencies. + closed_rx_window_handler_dependencies window_handler_dependencies; }; /// OTA symbol boundary dispatcher for the receiver. diff --git a/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp b/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp index 0119e789cb..b8c552a28a 100644 --- a/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp +++ b/lib/ofh/receiver/ofh_uplane_prach_data_flow_notifier.cpp @@ -19,7 +19,7 @@ void uplane_prach_data_flow_notifier::notify_prach(slot_point slot) expected context = prach_context_repo->try_poping_complete_prach_buffer(slot); - if (not context.has_value()) { + if (!context.has_value()) { return; } diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp index 5a0e41a4ea..521b3f2bc4 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp @@ -17,7 +17,7 @@ using namespace ofh; void uplane_rx_symbol_data_flow_notifier::notify_received_symbol(slot_point slot, unsigned symbol) { expected context = - ul_context_repo->try_poping_complete_resource_grid_symbol(slot, symbol); + ul_context_repo->try_popping_complete_resource_grid_symbol(slot, symbol); if (!context.has_value()) { return; diff --git a/lib/ofh/support/prach_context_repository.h b/lib/ofh/support/prach_context_repository.h index c1606437f8..210e23012c 100644 --- a/lib/ofh/support/prach_context_repository.h +++ b/lib/ofh/support/prach_context_repository.h @@ -139,7 +139,7 @@ class prach_context /// Tries to get a complete PRACH buffer. A PRACH buffer is considered completed when all the PRBs for all the ports /// have been written. - expected try_getting_complete_prach_buffer() + expected try_getting_complete_prach_buffer() const { if (!context_info.buffer) { return make_unexpected(default_error_t{}); @@ -210,14 +210,7 @@ class prach_context_repository std::lock_guard lock(mutex); slot_point current_slot = slot.value_or(context.slot); - - // Sanity check. As the context are notified on reception window close, the context should always be empty. - srsran_assert(entry(current_slot).empty(), - "Unnotified PRACH context for slot '{}' and sector '{}'", - entry(current_slot).get_context().slot, - entry(current_slot).get_context().sector); - - entry(current_slot) = prach_context(context, buffer_, start_symbol); + entry(current_slot) = prach_context(context, buffer_, start_symbol); } /// Function to write the uplink PRACH buffer. @@ -236,8 +229,8 @@ class prach_context_repository /// \brief Tries to pop a complete PRACH buffer from the repository. /// - /// A PRACH buffer is considered completed when all the PRBs for all the ports have been written. If the pop was a - /// success, clears the entry of the repository for that slot. + /// A PRACH buffer is considered completed when all the PRBs for all the ports have been written. If the pop is + /// successful it clears the entry of the repository for that slot. expected try_poping_complete_prach_buffer(slot_point slot) { std::lock_guard lock(mutex); diff --git a/lib/ofh/support/uplink_context_repository.h b/lib/ofh/support/uplink_context_repository.h index d0561e5efe..e299f3113a 100644 --- a/lib/ofh/support/uplink_context_repository.h +++ b/lib/ofh/support/uplink_context_repository.h @@ -148,12 +148,6 @@ class uplink_context_repository for (unsigned symbol_id = symbol_range.start(), symbol_end = symbol_range.stop(); symbol_id != symbol_end; ++symbol_id) { - // Sanity check. As the context are notified on reception window close, the context should always be empty. - srsran_assert(entry(context.slot, symbol_id).empty(), - "Unnotified PRACH context for slot '{}', symbol '{}' and sector '{}'", - entry(context.slot, symbol_id).get_grid_context().slot, - symbol_id, - entry(context.slot, symbol_id).get_grid_context().sector); entry(context.slot, symbol_id) = uplink_context(symbol_id, context, grid); } } @@ -174,9 +168,9 @@ class uplink_context_repository /// \brief Tries to pop a complete resource grid for the given slot and symbol. /// - /// A resource grid is considered completed when all the PRBs for all the ports have been written. - expected try_poping_complete_resource_grid_symbol(slot_point slot, - unsigned symbol) + /// A resource grid is considered completed when all the PRBs for all the ports have been written. + expected try_popping_complete_resource_grid_symbol(slot_point slot, + unsigned symbol) { std::lock_guard lock(mutex); @@ -190,9 +184,8 @@ class uplink_context_repository return result; } - /// Pops a complete resource grid for the given slot and symbol. - expected pop_complete_resource_grid_symbol(slot_point slot, - unsigned symbol) + /// Pops a resource grid for the given slot and symbol. + expected pop_resource_grid_symbol(slot_point slot, unsigned symbol) { std::lock_guard lock(mutex); diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index c9305c37db..a67796ba5a 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -20,7 +20,7 @@ # warning_as_errors: treat warnings as errors campaign_filename: &campaign_filename "C:\\ci\\CI 4x4 ORAN-FH-complete.xml" -gnb_extra_commands: &gnb_extra_commands "" +gnb_extra_commands: &gnb_extra_commands "ru_ofh --ta4_max 700 --ta4_min 10" expected_dl_bitrate_high: &expected_dl_bitrate_high 1200000000 expected_ul_bitrate_high: &expected_ul_bitrate_high 80000000 expected_dl_bitrate_low: &expected_dl_bitrate_low 14000 diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index e7a0eef0e8..a6b7620a77 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -49,8 +49,8 @@ unsigned T1a_min_cp_ul = 8; // 285us. unsigned T1a_max_up = 9; // 350us. unsigned T1a_min_up = 2; // 50us. /// Reception window parameters expressed in symbols, given the 30kHz scs. -unsigned Ta4_min = 1; // 150us. -unsigned Ta4_max = 5; // 25us. +unsigned Ta4_min = 1; // 35us. +unsigned Ta4_max = 28; // 1ms. static const tdd_ul_dl_pattern tdd_pattern_7d2u{10, 7, 0, 2, 0}; static const tdd_ul_dl_pattern tdd_pattern_6d3u{10, 6, 0, 3, 0}; @@ -921,9 +921,9 @@ struct worker_manager { const std::string exec_name = "ru_rx_exec"; const single_worker ru_worker{name, - {concurrent_queue_policy::lockfree_spsc, task_worker_queue_size}, + {concurrent_queue_policy::locking_mpmc, task_worker_queue_size}, {{exec_name}}, - std::chrono::microseconds{1}, + std::nullopt, os_thread_realtime_priority::max() - 1}; if (!exec_mng.add_execution_context(create_execution_context(ru_worker))) { report_fatal_error("Failed to instantiate {} execution context", ru_worker.name); From 420b665894808646abf71bdd9339e1cd13bd3d39 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 7 Aug 2024 12:05:38 +0200 Subject: [PATCH 143/407] phy: fix channel equalizer --- .../upper/equalization/modular_ch_est_list.h | 46 +++++++++---------- .../pusch/pusch_demodulator_impl.h | 1 - .../channel_equalizer_generic_impl.cpp | 5 +- .../equalization/channel_equalizer_test.cpp | 17 ++++++- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/include/srsran/phy/upper/equalization/modular_ch_est_list.h b/include/srsran/phy/upper/equalization/modular_ch_est_list.h index 8006355775..6daf86c818 100644 --- a/include/srsran/phy/upper/equalization/modular_ch_est_list.h +++ b/include/srsran/phy/upper/equalization/modular_ch_est_list.h @@ -20,18 +20,16 @@ template class modular_ch_est_list : public channel_equalizer::ch_est_list { public: + /// Default constructor - creates an empty modular channel estimate list. + modular_ch_est_list() = default; + /// \brief Creates a list of channel estimates from a maximum number of receive ports and layers. - /// \param[in] max_nof_rx_ports_ Maximum number of receive ports. - /// \param[in] max_nof_layers_ Maximum number of layers. - modular_ch_est_list(unsigned max_nof_rx_ports_, unsigned max_nof_layers_) : - max_nof_rx_ports(max_nof_rx_ports_), max_nof_layers(max_nof_layers_), data({max_nof_rx_ports, max_nof_layers}) + /// \param[in] nof_re_ Initial number of resource elements. + /// \param[in] nof_rx_ports Number of receive ports. + /// \param[in] nof_layers Number of layers. + modular_ch_est_list(unsigned nof_re_, unsigned nof_rx_ports, unsigned nof_layers) { - srsran_assert(max_nof_rx_ports * max_nof_layers <= MaxNofElements, - "The maximum number of layers (i.e., {}) times the maximum number of ports (i.e., {}) exceeds the " - "maximum number of elements (i.e., {})", - max_nof_layers, - max_nof_rx_ports, - MaxNofElements); + resize(nof_re_, nof_rx_ports, nof_layers); } /// \brief Sets the contents of a channel. @@ -50,18 +48,16 @@ class modular_ch_est_list : public channel_equalizer::ch_est_list /// \brief Resizes the channel estimates list. /// - /// \remark An assertion is triggered if the number of receive ports exceeds the maximum number of receive ports. - /// \remark An assertion is triggered if the number of layers exceeds the maximum number of layers. + /// \remark An assertion is triggered if the number of receive ports times the number of transmit layers exceeds the + /// maximum number of elements. void resize(unsigned nof_re_, unsigned nof_rx_ports, unsigned nof_layers) { - srsran_assert(nof_rx_ports <= max_nof_rx_ports, - "The number of receive ports (i.e., {}) exceeds the maximum number of receive ports (i.e., {}).", + srsran_assert(nof_rx_ports * nof_layers <= MaxNofElements, + "The number of receive ports (i.e., {}) times the number of layers exceeds the maximum number of " + "elements (i.e., {}).", nof_rx_ports, - max_nof_rx_ports); - srsran_assert(nof_layers <= max_nof_layers, - "The number of layers (i.e., {}) exceeds the maximum number of layers (i.e., {}).", - nof_rx_ports, - max_nof_layers); + nof_layers, + MaxNofElements); nof_re = nof_re_; data.resize({nof_rx_ports, nof_layers}); @@ -74,6 +70,14 @@ class modular_ch_est_list : public channel_equalizer::ch_est_list // See interface for documentation. span get_channel(unsigned i_rx_port, unsigned i_layer) const override { + srsran_assert(i_rx_port < data.get_dimension_size(ch_dims::rx_port), + "The receive port index (i.e., {}) exceeds the number of receive ports (i.e., {}).", + i_rx_port, + data.get_dimension_size(ch_dims::rx_port)); + srsran_assert(i_layer < data.get_dimension_size(ch_dims::tx_layer), + "The transmit layer index (i.e., {}) exceeds the number of transmit layers (i.e., {}).", + i_layer, + data.get_dimension_size(ch_dims::tx_layer)); return data[{i_rx_port, i_layer}]; } @@ -99,10 +103,6 @@ class modular_ch_est_list : public channel_equalizer::ch_est_list /// Number of resource elements. unsigned nof_re = 0; - /// Maximum number of receive ports. - unsigned max_nof_rx_ports; - /// Maximum number of layers. - unsigned max_nof_layers; /// Data storage as a tensor of views for each channel. static_tensor(ch_dims::nof_dims), span, MaxNofElements, ch_dims> data; }; diff --git a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h index 054024431e..d33564b4dc 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h @@ -49,7 +49,6 @@ class pusch_demodulator_impl : public pusch_demodulator temp_eq_re(max_nof_rb * NRE * pusch_constants::MAX_NOF_LAYERS), temp_eq_noise_vars(max_nof_rb * NRE * pusch_constants::MAX_NOF_LAYERS), ch_estimates_copy(max_nof_rb * NRE, pusch_constants::MAX_NOF_RX_PORTS, pusch_constants::MAX_NOF_LAYERS), - ch_estimates_view(pusch_constants::MAX_NOF_RX_PORTS, pusch_constants::MAX_NOF_LAYERS), compute_post_eq_sinr(compute_post_eq_sinr_) { srsran_assert(equalizer, "Invalid pointer to channel_equalizer object."); diff --git a/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp b/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp index 9446ce4a74..6cd4fdd16d 100644 --- a/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp +++ b/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp @@ -126,7 +126,8 @@ void equalize_zf_single_tx_layer_reduction(span span noise_var, float tx_scaling) { - unsigned nof_ports = noise_var.size(); + static constexpr unsigned nof_layers = 1; + unsigned nof_ports = noise_var.size(); // Function for checking if a noise variance is valid. const auto func_valid_noise_var = [](float nvar) { @@ -148,7 +149,7 @@ void equalize_zf_single_tx_layer_reduction(span // Reduce ports. static_vector reduced_noise_var(nof_valid_noise_var); modular_re_buffer_reader reduced_ch_symbols(nof_ports, ch_symbols.get_nof_re()); - modular_ch_est_list reduced_ch_estimates(nof_ports, ch_symbols.get_nof_re()); + modular_ch_est_list reduced_ch_estimates(ch_symbols.get_nof_re(), nof_ports, nof_layers); for (unsigned i_port = 0, i_reduced_port = 0; i_port != nof_ports; ++i_port) { if (func_valid_noise_var(noise_var[i_port])) { reduced_noise_var[i_reduced_port] = noise_var[i_port]; diff --git a/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp b/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp index 055cc217eb..1801abcd11 100644 --- a/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp +++ b/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp @@ -177,7 +177,7 @@ TEST_P(ChannelEqualizerFixture, ChannelEqualizerTest) ASSERT_EQ(span(eq_noise_vars_expected), span(eq_noise_vars_actual)); } -TEST_P(ChannelEqualizerFixture, ChannelEqualizerZeroNvar) +TEST_P(ChannelEqualizerFixture, ChannelEqualizerAllZeroNvar) { // Load the test case data. const test_case_t& t_case = GetParam(); @@ -198,6 +198,21 @@ TEST_P(ChannelEqualizerFixture, ChannelEqualizerZeroNvar) ASSERT_EQ(span(eq_noise_vars_expected), span(eq_noise_vars_actual)); } +TEST_P(ChannelEqualizerFixture, ChannelEqualizerOneZeroNvar) +{ + // Load the test case data. + const test_case_t& t_case = GetParam(); + + // Force noise variances set to zero. + test_noise_vars.front() = 0; + + // Equalize the symbols coming from the Rx ports using the modified noise variances. + test_equalizer->equalize( + eq_symbols_actual, eq_noise_vars_actual, rx_symbols, test_ch_estimates, test_noise_vars, t_case.context.scaling); + + // Skip assertions, the test shall not abort. +} + TEST_P(ChannelEqualizerFixture, ChannelEqualizerZeroEst) { // Load the test case data. From 1afbeb0d195312fc4b8d4be950af8eff9822e363 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 7 Aug 2024 16:24:14 +0200 Subject: [PATCH 144/407] PHY: Fix llr header doing a direct include of srsvec impl. Make type traits of srsvec public as they get used by user code. While there, minor comestic changes and fix a type punning error. --- .../srsran/phy/upper/log_likelihood_ratio.h | 17 ++++------- include/srsran/srsvec/binary.h | 29 +++++++------------ include/srsran/srsvec/circ_shift.h | 8 ++--- include/srsran/srsvec/compare.h | 6 ++-- include/srsran/srsvec/convolution.h | 10 +++---- include/srsran/srsvec/copy.h | 6 ++-- include/srsran/srsvec/dot_prod.h | 8 ++--- include/srsran/srsvec/fill.h | 4 +-- include/srsran/srsvec/mean.h | 4 +-- .../srsvec/{detail/traits.h => type_traits.h} | 21 +++++++------- include/srsran/srsvec/zero.h | 4 +-- lib/phy/upper/log_likelihood_ratio.cpp | 12 ++++---- 12 files changed, 57 insertions(+), 72 deletions(-) rename include/srsran/srsvec/{detail/traits.h => type_traits.h} (84%) diff --git a/include/srsran/phy/upper/log_likelihood_ratio.h b/include/srsran/phy/upper/log_likelihood_ratio.h index b3e59246e5..b49bb93d34 100644 --- a/include/srsran/phy/upper/log_likelihood_ratio.h +++ b/include/srsran/phy/upper/log_likelihood_ratio.h @@ -18,10 +18,9 @@ #include "srsran/adt/bit_buffer.h" #include "srsran/adt/span.h" -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/support/srsran_assert.h" #include "fmt/format.h" - #include namespace srsran { @@ -75,11 +74,7 @@ class log_likelihood_ratio ///@} /// Default assignment operator. - constexpr log_likelihood_ratio& operator=(const log_likelihood_ratio& other) - { - value = other.value; - return *this; - } + constexpr log_likelihood_ratio& operator=(const log_likelihood_ratio& other) = default; /// Negation (additive inverse). constexpr log_likelihood_ratio operator-() const { return -value; } @@ -172,7 +167,7 @@ class log_likelihood_ratio template static constexpr log_likelihood_ratio copysign(log_likelihood_ratio a, T b) { - static_assert(std::is_arithmetic::value, "Template type is not an arithmetic type."); + static_assert(std::is_arithmetic_v, "Template type is not an arithmetic type."); if (b < 0) { return -std::abs(a.value); } @@ -255,8 +250,8 @@ struct is_llr_span_compatible : std::false_type { /// Checks if \c T is compatible with a span of log_likelihood_ratios. template struct is_llr_span_compatible>::value || - std::is_convertible>::value>> + std::enable_if_t> || + std::is_convertible_v>>> : std::true_type { // Intentionally empty. }; @@ -282,7 +277,7 @@ template V log_likelihood_ratio::dot_prod(const T& x, const U& y, V init) { static_assert(detail::is_llr_span_compatible::value, "Template type is not compatible with a span of LLRs"); - static_assert(srsvec::detail::is_arithmetic_span_compatible::value, + static_assert(srsvec::is_arithmetic_span_compatible::value, "Template type is not compatible with a span of arithmetics"); srsran_assert(x.size() == y.size(), "Input spans must have identical sizes: '{}' vs '{}'", x.size(), y.size()); return std::inner_product( diff --git a/include/srsran/srsvec/binary.h b/include/srsran/srsvec/binary.h index f573553d0d..2ae8395af0 100644 --- a/include/srsran/srsvec/binary.h +++ b/include/srsran/srsvec/binary.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" namespace srsran { @@ -19,12 +19,9 @@ namespace srsvec { template void binary_xor(const T& x, const U& y, V&& z) { - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); srsran_srsvec_assert_size(x, y); srsran_srsvec_assert_size(x, z); @@ -36,12 +33,9 @@ void binary_xor(const T& x, const U& y, V&& z) template void binary_and(const T& x, const U& y, V&& z) { - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); srsran_srsvec_assert_size(x, y); srsran_srsvec_assert_size(x, z); @@ -53,12 +47,9 @@ void binary_and(const T& x, const U& y, V&& z) template void binary_or(const T& x, const U& y, V&& z) { - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); - static_assert(detail::is_integral_span_compatible::value, - "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); + static_assert(is_integral_span_compatible::value, "Template type is not compatible with a span of integers"); srsran_srsvec_assert_size(x, y); srsran_srsvec_assert_size(x, z); diff --git a/include/srsran/srsvec/circ_shift.h b/include/srsran/srsvec/circ_shift.h index 2b24954423..49393cb35e 100644 --- a/include/srsran/srsvec/circ_shift.h +++ b/include/srsran/srsvec/circ_shift.h @@ -30,8 +30,8 @@ namespace srsvec { template void circ_shift_forward(T&& out, const U& in, unsigned shift) { - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); srsran_srsvec_assert_size(out, in); unsigned length = out.size(); @@ -52,8 +52,8 @@ void circ_shift_forward(T&& out, const U& in, unsigned shift) template void circ_shift_backward(T&& out, const U& in, unsigned shift) { - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); srsran_srsvec_assert_size(out, in); unsigned length = out.size(); diff --git a/include/srsran/srsvec/compare.h b/include/srsran/srsvec/compare.h index 1ba59d6010..79755fa73a 100644 --- a/include/srsran/srsvec/compare.h +++ b/include/srsran/srsvec/compare.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" namespace srsran { @@ -23,8 +23,8 @@ const char* find(span input, const char* value); template bool equal(const T1& s1, const T2& s2) { - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); srsran_srsvec_assert_size(s1, s2); return std::equal(s1.begin(), s1.end(), s2.begin(), s2.end()); diff --git a/include/srsran/srsvec/convolution.h b/include/srsran/srsvec/convolution.h index d6eb6ed442..6f54d936fb 100644 --- a/include/srsran/srsvec/convolution.h +++ b/include/srsran/srsvec/convolution.h @@ -13,9 +13,9 @@ #pragma once -#include "zero.h" -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" +#include "srsran/srsvec/zero.h" #include namespace srsran { @@ -68,11 +68,11 @@ void multiply_and_accumulate(span out, span x, span void convolution_same(V&& out, const T& x_v, const U& y_v) { - static_assert((detail::is_arithmetic_span_compatible::value || detail::is_complex_span_compatible::value), + static_assert((is_arithmetic_span_compatible::value || is_complex_span_compatible::value), "Template type is not compatible with a span of arithmetics or complex floats."); - static_assert((detail::is_arithmetic_span_compatible::value || detail::is_complex_span_compatible::value), + static_assert((is_arithmetic_span_compatible::value || is_complex_span_compatible::value), "Template type is not compatible with a span of arithmetics or complex floats."); - static_assert((detail::is_arithmetic_span_compatible::value || detail::is_complex_span_compatible::value), + static_assert((is_arithmetic_span_compatible::value || is_complex_span_compatible::value), "Template type is not compatible with a span of arithmetics or complex floats."); srsran_srsvec_assert_size(out, x_v); diff --git a/include/srsran/srsvec/copy.h b/include/srsran/srsvec/copy.h index 41002ba494..bb796467f2 100644 --- a/include/srsran/srsvec/copy.h +++ b/include/srsran/srsvec/copy.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" namespace srsran { @@ -19,8 +19,8 @@ namespace srsvec { template void copy(T&& dst, const U& src) { - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); srsran_srsvec_assert_size(dst, src); std::copy(src.begin(), src.end(), dst.begin()); diff --git a/include/srsran/srsvec/dot_prod.h b/include/srsran/srsvec/dot_prod.h index c496378b82..80673d311c 100644 --- a/include/srsran/srsvec/dot_prod.h +++ b/include/srsran/srsvec/dot_prod.h @@ -14,7 +14,7 @@ #pragma once #include "srsran/adt/span.h" -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" #include "srsran/support/srsran_assert.h" #include @@ -38,10 +38,8 @@ namespace srsvec { template inline V dot_prod(const T& x, const U& y, V init) { - static_assert(detail::is_arithmetic_span_compatible::value, - "Template type is not compatible with a span of arithmetics"); - static_assert(detail::is_arithmetic_span_compatible::value, - "Template type is not compatible with a span of arithmetics"); + static_assert(is_arithmetic_span_compatible::value, "Template type is not compatible with a span of arithmetics"); + static_assert(is_arithmetic_span_compatible::value, "Template type is not compatible with a span of arithmetics"); srsran_srsvec_assert_size(x, y); return std::inner_product(x.begin(), x.end(), y.begin(), init); } diff --git a/include/srsran/srsvec/fill.h b/include/srsran/srsvec/fill.h index b8fd65026d..7a063bf7f7 100644 --- a/include/srsran/srsvec/fill.h +++ b/include/srsran/srsvec/fill.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" namespace srsran { @@ -24,7 +24,7 @@ namespace srsvec { template void fill(T&& x, detail::value_type_of_t value) { - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span"); + static_assert(is_span_compatible::value, "Template type is not compatible with a span"); std::fill(x.begin(), x.end(), value); } diff --git a/include/srsran/srsvec/mean.h b/include/srsran/srsvec/mean.h index 4bc52f4b32..33b61fd933 100644 --- a/include/srsran/srsvec/mean.h +++ b/include/srsran/srsvec/mean.h @@ -11,7 +11,7 @@ #pragma once #include "srsran/adt/complex.h" -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/support/srsran_assert.h" #include @@ -28,7 +28,7 @@ namespace srsvec { template auto mean(const T& x) { - static_assert(detail::is_arithmetic_span_compatible::value || detail::is_complex_span_compatible::value, + static_assert(is_arithmetic_span_compatible::value || is_complex_span_compatible::value, "The input type is not compatible with a span of arithmetic/cf_t values."); using DataType = typename T::value_type; diff --git a/include/srsran/srsvec/detail/traits.h b/include/srsran/srsvec/type_traits.h similarity index 84% rename from include/srsran/srsvec/detail/traits.h rename to include/srsran/srsvec/type_traits.h index 857aa31940..4e1856a7b6 100644 --- a/include/srsran/srsvec/detail/traits.h +++ b/include/srsran/srsvec/type_traits.h @@ -55,6 +55,8 @@ struct value_type_of_impl { template using value_type_of_t = typename value_type_of_impl::type; +} // namespace detail + /// Checks if T is compatible with a span of integer types. template struct is_integral_span_compatible : std::false_type { @@ -62,8 +64,8 @@ struct is_integral_span_compatible : std::false_type { template struct is_integral_span_compatible>>::value && - std::is_integral>::value>> : std::true_type { + std::enable_if_t>> && + std::is_integral_v>>> : std::true_type { }; /// Checks if T is compatible with a span of arithmetic types. @@ -73,8 +75,9 @@ struct is_arithmetic_span_compatible : std::false_type { template struct is_arithmetic_span_compatible>>::value && - std::is_arithmetic>::value>> : std::true_type { + std::enable_if_t>> && + std::is_arithmetic_v>>> + : std::true_type { }; /// Checks if T is compatible with a span of complex floating points (which are not arithmetic types). @@ -83,10 +86,9 @@ struct is_complex_span_compatible : std::false_type { }; template -struct is_complex_span_compatible< - T, - std::enable_if_t>>::value && is_complex>::value>> - : std::true_type { +struct is_complex_span_compatible>> && + is_complex>::value>> : std::true_type { }; /// Checks if T is compatible with a span. @@ -95,10 +97,9 @@ struct is_span_compatible : std::false_type { }; template -struct is_span_compatible>>::value>> +struct is_span_compatible>>>> : std::true_type { }; -} // namespace detail } // namespace srsvec } // namespace srsran diff --git a/include/srsran/srsvec/zero.h b/include/srsran/srsvec/zero.h index 1b34be5517..057b2b90f0 100644 --- a/include/srsran/srsvec/zero.h +++ b/include/srsran/srsvec/zero.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/srsvec/detail/traits.h" +#include "srsran/srsvec/type_traits.h" #include "srsran/srsvec/types.h" namespace srsran { @@ -23,7 +23,7 @@ namespace srsvec { template void zero(T&& x) { - static_assert(detail::is_span_compatible::value, "Template type is not compatible with a span."); + static_assert(is_span_compatible::value, "Template type is not compatible with a span."); std::fill(x.begin(), x.end(), 0); } diff --git a/lib/phy/upper/log_likelihood_ratio.cpp b/lib/phy/upper/log_likelihood_ratio.cpp index 763ed7f6a1..65aa0e7661 100644 --- a/lib/phy/upper/log_likelihood_ratio.cpp +++ b/lib/phy/upper/log_likelihood_ratio.cpp @@ -9,7 +9,6 @@ */ #include "srsran/phy/upper/log_likelihood_ratio.h" -#include "../lib/srsvec/simd.h" #include "srsran/adt/optional.h" #include "srsran/srsvec/compare.h" #include @@ -23,8 +22,8 @@ using namespace srsran; -// Computes the sum when at least one of the summands is plus/minus infinity. -// Note that also the indeterminate case +LLR_INFTY + (-LLR_INFTY) is set to zero. +/// Computes the sum when at least one of the summands is plus/minus infinity. +/// Note that also the indeterminate case +LLR_INFTY + (-LLR_INFTY) is set to zero. static std::optional tackle_special_sums(log_likelihood_ratio val_a, log_likelihood_ratio val_b) { if (val_a == -val_b) { @@ -39,7 +38,8 @@ static std::optional tackle_special_sums(log_likelihood_ra if (log_likelihood_ratio::isinf(val_b)) { return val_b; } - return {}; + + return std::nullopt; } log_likelihood_ratio log_likelihood_ratio::operator+=(log_likelihood_ratio rhs) @@ -99,7 +99,7 @@ static void hard_decision_simd(bit_buffer& hard_bits, const int8_t* soft_bits, u for (unsigned max_bit = (len / AVX2_B_SIZE) * AVX2_B_SIZE; i_bit != max_bit; i_bit += AVX2_B_SIZE) { // Load AVX2_B_SIZE LLRs. - __m256i soft_epi8 = _mm256_loadu_si256((__m256i*)(&soft_bits[i_bit])); + __m256i soft_epi8 = _mm256_loadu_si256(reinterpret_cast(soft_bits + i_bit)); // Shuffle soft_epi8: the soft bits are taken in groups of 8 and, inside each group, we reverse their order (this is // because, once we convert the soft bits into hard bits, the hard bits forming a byte need to be reversed before @@ -147,7 +147,7 @@ static void hard_decision_simd(bit_buffer& hard_bits, const int8_t* soft_bits, u uint32_t bytes = _mm256_movemask_epi8(soft_epi8); // Write the packed bits into 4 bytes of the internal buffer. - *(reinterpret_cast(packed_buffer.begin())) = bytes; + std::memcpy(packed_buffer.begin(), &bytes, sizeof(uint32_t)); // Advance buffer. packed_buffer = packed_buffer.last(packed_buffer.size() - (AVX2_B_SIZE / 8)); From 98e344b5ad20b8c023f6298f1a83a78e25457ff2 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 20 Jun 2024 18:10:36 +0200 Subject: [PATCH 145/407] services: added prototype for metrics service --- apps/cu/cu.cpp | 4 - apps/du/du.cpp | 40 +- apps/gnb/gnb.cpp | 71 ++-- apps/gnb/gnb_appconfig_cli11_schema.cpp | 4 +- apps/services/CMakeLists.txt | 5 - apps/services/metrics/metrics_config.h | 49 +++ apps/services/metrics/metrics_consumer.h | 33 ++ apps/services/metrics/metrics_manager.h | 81 +++++ apps/services/metrics/metrics_notifier.h | 30 ++ .../services/metrics/metrics_notifier_proxy.h | 38 ++ apps/services/metrics/metrics_producer.h | 29 ++ apps/services/metrics/metrics_properties.h | 30 ++ apps/services/metrics/metrics_set.h | 30 ++ apps/services/metrics_hub.cpp | 92 ----- apps/services/metrics_hub.h | 89 ----- apps/services/metrics_log_helper.cpp | 128 ------- apps/services/metrics_log_helper.h | 37 -- apps/services/metrics_plotter_json.cpp | 127 ------- apps/services/metrics_plotter_json.h | 30 -- apps/services/metrics_plotter_stdout.cpp | 127 ------- apps/services/metrics_plotter_stdout.h | 34 -- apps/services/rlc_metrics_plotter_json.h | 30 -- apps/units/flexible_du/du_high/CMakeLists.txt | 4 +- .../flexible_du/du_high/du_high_commands.h | 6 +- .../flexible_du/du_high/du_high_config.h | 16 +- .../du_high/du_high_config_cli11_schema.cpp | 19 + .../du_high/du_high_wrapper_config_helper.cpp | 190 ++++++---- .../du_high/du_high_wrapper_config_helper.h | 46 ++- .../du_high/metrics/CMakeLists.txt | 16 + .../du_high/metrics/du_high_rlc_metrics.h | 58 +++ .../du_high_rlc_metrics_consumers.cpp} | 29 +- .../metrics/du_high_rlc_metrics_consumers.h | 58 +++ .../metrics/du_high_rlc_metrics_producer.cpp | 19 + .../metrics/du_high_rlc_metrics_producer.h | 32 ++ .../metrics/du_high_scheduler_cell_metrics.h | 41 +++ ..._high_scheduler_cell_metrics_consumers.cpp | 343 ++++++++++++++++++ ...du_high_scheduler_cell_metrics_consumers.h | 76 ++++ ...u_high_scheduler_cell_metrics_producer.cpp | 42 +++ .../du_high_scheduler_cell_metrics_producer.h | 44 +++ .../split_dynamic/dynamic_du_factory.cpp | 97 +++-- .../split_dynamic/dynamic_du_factory.h | 32 +- tests/unittests/apps/CMakeLists.txt | 2 +- tests/unittests/apps/services/CMakeLists.txt | 12 - tests/unittests/apps/units/CMakeLists.txt | 9 + .../apps/units/flexible_du/CMakeLists.txt | 9 + .../units/flexible_du/du_high/CMakeLists.txt | 9 + .../du_high/metrics/CMakeLists.txt | 12 + ...ler_cell_metrics_consumer_stdout_test.cpp} | 6 +- 48 files changed, 1420 insertions(+), 945 deletions(-) create mode 100644 apps/services/metrics/metrics_config.h create mode 100644 apps/services/metrics/metrics_consumer.h create mode 100644 apps/services/metrics/metrics_manager.h create mode 100644 apps/services/metrics/metrics_notifier.h create mode 100644 apps/services/metrics/metrics_notifier_proxy.h create mode 100644 apps/services/metrics/metrics_producer.h create mode 100644 apps/services/metrics/metrics_properties.h create mode 100644 apps/services/metrics/metrics_set.h delete mode 100644 apps/services/metrics_hub.cpp delete mode 100644 apps/services/metrics_hub.h delete mode 100644 apps/services/metrics_log_helper.cpp delete mode 100644 apps/services/metrics_log_helper.h delete mode 100644 apps/services/metrics_plotter_json.cpp delete mode 100644 apps/services/metrics_plotter_json.h delete mode 100644 apps/services/metrics_plotter_stdout.cpp delete mode 100644 apps/services/metrics_plotter_stdout.h delete mode 100644 apps/services/rlc_metrics_plotter_json.h create mode 100644 apps/units/flexible_du/du_high/metrics/CMakeLists.txt create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics.h rename apps/{services/rlc_metrics_plotter_json.cpp => units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.cpp} (78%) create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.h create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.cpp create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.h create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics.h create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.h create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp create mode 100644 apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.h delete mode 100644 tests/unittests/apps/services/CMakeLists.txt create mode 100644 tests/unittests/apps/units/CMakeLists.txt create mode 100644 tests/unittests/apps/units/flexible_du/CMakeLists.txt create mode 100644 tests/unittests/apps/units/flexible_du/du_high/CMakeLists.txt create mode 100644 tests/unittests/apps/units/flexible_du/du_high/metrics/CMakeLists.txt rename tests/unittests/apps/{services/metrics_plotter_stdout_test.cpp => units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumer_stdout_test.cpp} (83%) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index bf04b61b87..ab9cbba566 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -33,7 +33,6 @@ #include "apps/cu/cu_appconfig_cli11_schema.h" #include "apps/cu/cu_worker_manager.h" -#include "apps/services/metrics_log_helper.h" #include "apps/units/cu_cp/cu_cp_builder.h" #include "apps/units/cu_cp/cu_cp_config_translators.h" #include "apps/units/cu_cp/cu_cp_logger_registrator.h" @@ -330,9 +329,6 @@ int main(int argc, char** argv) // Create console helper object for commands and metrics printing. app_services::stdin_command_dispatcher command_parser(*epoll_broker, cu_cp_obj_and_cmds.commands); - // Create metrics log helper. - metrics_log_helper metrics_logger(srslog::fetch_basic_logger("METRICS")); - // Connect E1AP to CU-CP. e1_gw->attach_cu_cp(cu_cp_obj.get_e1_handler()); diff --git a/apps/du/du.cpp b/apps/du/du.cpp index b59d0e7c72..e2f4263764 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -30,10 +30,6 @@ #include "du_appconfig_validators.h" #include "apps/services/worker_manager.h" - -#include "apps/services/metrics_log_helper.h" -#include "apps/services/rlc_metrics_plotter_json.h" - #include "apps/units/flexible_du/split_dynamic/dynamic_du_factory.h" #include "apps/gnb/adapters/e2_gateway_remote_connector.h" @@ -51,8 +47,8 @@ #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/metrics_plotter_json.h" -#include "apps/services/metrics_plotter_stdout.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/du_high/pcap_factory.h" #include "apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.h" @@ -292,16 +288,8 @@ int main(int argc, char** argv) // Set up the JSON log channel used by metrics. srslog::sink& json_sink = srslog::fetch_udp_sink(du_cfg.metrics_cfg.addr, du_cfg.metrics_cfg.port, srslog::create_json_formatter()); - srslog::log_channel& json_channel = srslog::fetch_log_channel("JSON_channel", json_sink, {}); - json_channel.set_enabled(du_cfg.metrics_cfg.enable_json_metrics); - // Set up RLC JSON log channel used by metrics. - srslog::log_channel& rlc_json_channel = srslog::fetch_log_channel("JSON_RLC_channel", json_sink, {}); - rlc_json_channel.set_enabled(du_unit_cfg.du_high_cfg.config.metrics.rlc.json_enabled); - rlc_metrics_plotter_json rlc_json_plotter(rlc_json_channel); - - std::unique_ptr hub = std::make_unique(*workers.metrics_hub_exec); - e2_metric_connector_manager e2_metric_connectors(du_unit_cfg.du_high_cfg.config.cells_cfg.size()); + e2_metric_connector_manager e2_metric_connectors(du_unit_cfg.du_high_cfg.config.cells_cfg.size()); // E2AP configuration. srsran::sctp_network_connector_config e2_du_nw_config = generate_e2ap_nw_config(du_cfg, E2_DU_PPID); @@ -309,26 +297,24 @@ int main(int argc, char** argv) // Create E2AP GW remote connector. e2_gateway_remote_connector e2_gw{*epoll_broker, e2_du_nw_config, *du_pcaps.e2ap}; - // Create metrics log helper. - metrics_log_helper metrics_logger(srslog::fetch_basic_logger("METRICS")); - - // Instantiate one DU. - metrics_plotter_stdout metrics_stdout(false); - metrics_plotter_json metrics_json(json_channel); - auto du_inst_and_cmds = create_du(du_unit_cfg, + app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder; + auto du_inst_and_cmds = create_du(du_unit_cfg, workers, *f1c_gw, *du_f1u_conn, app_timers, *du_pcaps.mac, *du_pcaps.rlc, - metrics_stdout, - metrics_json, - metrics_logger, e2_gw, e2_metric_connectors, - rlc_json_plotter, - *hub); + json_sink, + metrics_notifier_forwarder); + + // Only DU has metrics now. + app_services::metrics_manager metrics_mngr( + srslog::fetch_basic_logger("GNB"), *workers.metrics_hub_exec, du_inst_and_cmds.metrics); + // Connect the forwarder to the metrics manager. + metrics_notifier_forwarder.connect(metrics_mngr); du& du_inst = *du_inst_and_cmds.unit; diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 8664a961e1..3f1d2df49d 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -33,9 +33,6 @@ #include "apps/services/worker_manager.h" #include "apps/services/application_tracer.h" -#include "apps/services/metrics_hub.h" -#include "apps/services/metrics_log_helper.h" -#include "apps/services/rlc_metrics_plotter_json.h" #include "apps/services/stdin_command_dispatcher.h" #include "apps/units/flexible_du/split_dynamic/dynamic_du_factory.h" @@ -62,8 +59,8 @@ #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_plotter_json.h" -#include "apps/services/metrics_plotter_stdout.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/pcap_factory.h" @@ -372,16 +369,8 @@ int main(int argc, char** argv) // Set up the JSON log channel used by metrics. srslog::sink& json_sink = srslog::fetch_udp_sink(gnb_cfg.metrics_cfg.addr, gnb_cfg.metrics_cfg.port, srslog::create_json_formatter()); - srslog::log_channel& json_channel = srslog::fetch_log_channel("JSON_channel", json_sink, {}); - json_channel.set_enabled(gnb_cfg.metrics_cfg.enable_json_metrics); - // Set up RLC JSON log channel used by metrics. - srslog::log_channel& rlc_json_channel = srslog::fetch_log_channel("JSON_RLC_channel", json_sink, {}); - rlc_json_channel.set_enabled(du_unit_cfg.du_high_cfg.config.metrics.rlc.json_enabled); - rlc_metrics_plotter_json rlc_json_plotter(rlc_json_channel); - - std::unique_ptr hub = std::make_unique(*workers.metrics_hub_exec); - e2_metric_connector_manager e2_metric_connectors(du_unit_cfg.du_high_cfg.config.cells_cfg.size()); + e2_metric_connector_manager e2_metric_connectors(du_unit_cfg.du_high_cfg.config.cells_cfg.size()); // Create N2 Gateway. std::unique_ptr n2_client = srs_cu_cp::create_n2_connection_client( @@ -405,24 +394,6 @@ int main(int argc, char** argv) srs_cu_cp::cu_cp& cu_cp_obj = *cu_cp_obj_and_cmds.unit; - // Create metrics log helper. - metrics_log_helper metrics_logger(srslog::fetch_basic_logger("METRICS")); - - // Connect E1AP to CU-CP. - e1_gw->attach_cu_cp(cu_cp_obj.get_e1_handler()); - - // start CU-CP - gnb_logger.info("Starting CU-CP..."); - cu_cp_obj.start(); - gnb_logger.info("CU-CP started successfully"); - - if (not cu_cp_obj.get_ng_handler().amf_is_connected()) { - report_error("CU-CP failed to connect to AMF"); - } - - // Connect F1-C to CU-CP and start listening for new F1-C connection requests. - f1c_gw->attach_cu_cp(cu_cp_obj.get_f1c_handler()); - // Create and start CU-UP std::unique_ptr cu_up_obj = build_cu_up(cu_up_config, workers, @@ -431,28 +402,29 @@ int main(int argc, char** argv) *cu_up_dlt_pcaps.n3, *cu_timers, *epoll_broker); - cu_up_obj->start(); // Instantiate one DU. - metrics_plotter_stdout metrics_stdout(gnb_cfg.metrics_cfg.autostart_stdout_metrics); - metrics_plotter_json metrics_json(json_channel); - auto du_inst_and_cmds = create_du(du_unit_cfg, + app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder; + auto du_inst_and_cmds = create_du(du_unit_cfg, workers, *f1c_gw, *f1u_conn->get_f1u_du_gateway(), app_timers, *du_pcaps.mac, *du_pcaps.rlc, - metrics_stdout, - metrics_json, - metrics_logger, e2_gw, e2_metric_connectors, - rlc_json_plotter, - *hub); + json_sink, + metrics_notifier_forwarder); du& du_inst = *du_inst_and_cmds.unit; + // Only DU has metrics now. When CU returns metrics, create the vector of metrics as it is done for the commands. + app_services::metrics_manager metrics_mngr( + srslog::fetch_basic_logger("GNB"), *workers.metrics_hub_exec, du_inst_and_cmds.metrics); + // Connect the forwarder to the metrics manager. + metrics_notifier_forwarder.connect(metrics_mngr); + std::vector> commands; for (auto& cmd : cu_cp_obj_and_cmds.commands) { commands.push_back(std::move(cmd)); @@ -463,6 +435,23 @@ int main(int argc, char** argv) app_services::stdin_command_dispatcher command_parser(*epoll_broker, commands); + // Connect E1AP to CU-CP. + e1_gw->attach_cu_cp(cu_cp_obj.get_e1_handler()); + + // start CU-CP + gnb_logger.info("Starting CU-CP..."); + cu_cp_obj.start(); + gnb_logger.info("CU-CP started successfully"); + + if (not cu_cp_obj.get_ng_handler().amf_is_connected()) { + report_error("CU-CP failed to connect to AMF"); + } + + // Connect F1-C to CU-CP and start listening for new F1-C connection requests. + f1c_gw->attach_cu_cp(cu_cp_obj.get_f1c_handler()); + + cu_up_obj->start(); + // Start processing. du_inst.start(); diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 9ba7c98f1b..4101cabaa6 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -44,8 +44,8 @@ static void configure_cli11_metrics_args(CLI::App& app, metrics_appconfig& metri ->capture_default_str() ->check(CLI::Range(0, 65535)); - app.add_option( - "--autostart_stdout_metrics", metrics_params.autostart_stdout_metrics, "Autostart stdout metrics reporting") + add_option( + app, "--autostart_stdout_metrics", metrics_params.autostart_stdout_metrics, "Autostart stdout metrics reporting") ->capture_default_str(); add_option(app, diff --git a/apps/services/CMakeLists.txt b/apps/services/CMakeLists.txt index 406c0bde0f..facdaeb2eb 100644 --- a/apps/services/CMakeLists.txt +++ b/apps/services/CMakeLists.txt @@ -10,12 +10,7 @@ add_subdirectory(buffer_pool) add_subdirectory(logger) set(SOURCES - metrics_log_helper.cpp e2_metric_connector_manager.cpp - metrics_hub.cpp - metrics_plotter_json.cpp - metrics_plotter_stdout.cpp - rlc_metrics_plotter_json.cpp stdin_command_dispatcher.cpp worker_manager.cpp) diff --git a/apps/services/metrics/metrics_config.h b/apps/services/metrics/metrics_config.h new file mode 100644 index 0000000000..a94e872401 --- /dev/null +++ b/apps/services/metrics/metrics_config.h @@ -0,0 +1,49 @@ +/* + * + * 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/metrics/metrics_consumer.h" +#include "apps/services/metrics/metrics_producer.h" +#include "srsran/adt/span.h" +#include "srsran/srslog/srslog.h" +#include +#include +#include + +namespace srsran { + +class task_executor; + +namespace app_services { + +/// \brief Metrics callback. +/// +/// This callback is used to notify metrics to the given metrics consumer running in a different execution context +/// defined by the given task executor. The implementation of the callback must make sure that the metrics object lives +/// longer than the handling of the metrics by the consumer. +using metrics_callback = + std::function, task_executor&, srslog::basic_logger&)>; + +/// Metrics configuration. +struct metrics_config { + /// Metric name. + std::string metric_name; + /// Callback to be executed when received this type of metrics. This callback is used to notify the consumers of new + /// metrics using a different execution context. + metrics_callback callback; + /// Metric producer. + std::vector> producers; + /// Metric consumer. + std::vector> consumers; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_consumer.h b/apps/services/metrics/metrics_consumer.h new file mode 100644 index 0000000000..bc246aabc5 --- /dev/null +++ b/apps/services/metrics/metrics_consumer.h @@ -0,0 +1,33 @@ +/* + * + * 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 { +namespace app_services { + +class metrics_set; +class metrics_properties; + +/// \brief Metrics subscriber. +/// +/// A subscriber will listen to a configured metric. +class metrics_consumer +{ +public: + /// Default destructor. + virtual ~metrics_consumer() = default; + + /// Handles the given metrics. + virtual void handle_metric(const metrics_set& metric) = 0; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_manager.h b/apps/services/metrics/metrics_manager.h new file mode 100644 index 0000000000..687867a6a1 --- /dev/null +++ b/apps/services/metrics/metrics_manager.h @@ -0,0 +1,81 @@ +/* + * + * 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/metrics/metrics_config.h" +#include "apps/services/metrics/metrics_notifier.h" +#include "apps/services/metrics/metrics_set.h" +#include "metrics_properties.h" +#include "srsran/support/executors/task_executor.h" + +namespace srsran { +namespace app_services { + +/// \brief Metrics manager application service. +/// +/// The manager allows to register metrics, metrics producers and metrics consumers in the service. +class metrics_manager : public metrics_notifier +{ + /// Helper struct to store the information related to a metric. + struct metrics_entry { + /// Metric name. + std::string metric_name; + /// Callback to be executed when received this type of metrics. + metrics_callback callback; + /// Metric producer. + std::vector> producers; + /// Metric consumer. + std::vector> consumers; + /// Helper vector to store the pointers to the consumers. + std::vector consumers_helper; + }; + +public: + metrics_manager(srslog::basic_logger& logger_, task_executor& executor_, span metrics_info) : + logger(logger_), executor(executor_) + { + for (auto& info : metrics_info) { + metrics_entry entry; + entry.metric_name = info.metric_name; + entry.callback = std::move(info.callback); + entry.producers = std::move(info.producers); + entry.consumers = std::move(info.consumers); + for (const auto& con : entry.consumers) { + entry.consumers_helper.push_back(con.get()); + } + supported_metrics.push_back(std::move(entry)); + } + } + + /// Fowards the given metric to the subscribers. + void on_new_metric(const metrics_set& metric) override + { + std::string_view metrics_name = metric.get_properties().name(); + auto iter = std::find_if( + supported_metrics.begin(), supported_metrics.end(), [&metrics_name](const metrics_entry& supported_metric) { + return supported_metric.metric_name == metrics_name; + }); + + srsran_assert(iter != supported_metrics.end(), "Received unregistered metrics '{}'", metrics_name); + + if (!iter->consumers_helper.empty()) { + iter->callback(metric, iter->consumers_helper, executor, logger); + } + } + +private: + srslog::basic_logger& logger; + task_executor& executor; + std::vector supported_metrics; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_notifier.h b/apps/services/metrics/metrics_notifier.h new file mode 100644 index 0000000000..e7fbacd697 --- /dev/null +++ b/apps/services/metrics/metrics_notifier.h @@ -0,0 +1,30 @@ +/* + * + * 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 { +namespace app_services { + +class metrics_set; + +/// Notifies new metrics. +class metrics_notifier +{ +public: + /// Default destructor. + virtual ~metrics_notifier() = default; + + /// Notifies the given metrics. + virtual void on_new_metric(const metrics_set& metric) = 0; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_notifier_proxy.h b/apps/services/metrics/metrics_notifier_proxy.h new file mode 100644 index 0000000000..acebcd19d6 --- /dev/null +++ b/apps/services/metrics/metrics_notifier_proxy.h @@ -0,0 +1,38 @@ +/* + * + * 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/metrics/metrics_notifier.h" + +namespace srsran { +namespace app_services { + +class metrics_set; + +/// Metrics notifier proxy implementation. +class metrics_notifier_proxy_impl : public metrics_notifier +{ + metrics_notifier* proxy = nullptr; + +public: + // See interface for documentation. + void on_new_metric(const metrics_set& metric) override + { + if (proxy) { + proxy->on_new_metric(metric); + } + } + + void connect(metrics_notifier& notifier) { proxy = ¬ifier; } +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_producer.h b/apps/services/metrics/metrics_producer.h new file mode 100644 index 0000000000..0b38759d77 --- /dev/null +++ b/apps/services/metrics/metrics_producer.h @@ -0,0 +1,29 @@ +/* + * + * 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 { +namespace app_services { + +class metrics_properties; + +/// \brief Metrics producer. +/// +/// Produces metrics that will be consumed by the corresponding metrics consumers. +class metrics_producer +{ +public: + /// Default destructor. + virtual ~metrics_producer() = default; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_properties.h b/apps/services/metrics/metrics_properties.h new file mode 100644 index 0000000000..cd4511f7b7 --- /dev/null +++ b/apps/services/metrics/metrics_properties.h @@ -0,0 +1,30 @@ +/* + * + * 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 + +namespace srsran { +namespace app_services { + +/// Metrics properties. +class metrics_properties +{ +public: + /// Default destructor. + virtual ~metrics_properties() = default; + + /// Returns the metrics name. + virtual std::string_view name() const = 0; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics/metrics_set.h b/apps/services/metrics/metrics_set.h new file mode 100644 index 0000000000..dc764e70ca --- /dev/null +++ b/apps/services/metrics/metrics_set.h @@ -0,0 +1,30 @@ +/* + * + * 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 { +namespace app_services { + +class metrics_properties; + +/// General purpouse metrics set. +class metrics_set +{ +public: + /// Default destructor. + virtual ~metrics_set() = default; + + /// Returns this metrics properties. + virtual const metrics_properties& get_properties() const = 0; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/metrics_hub.cpp b/apps/services/metrics_hub.cpp deleted file mode 100644 index d3ecd9a40c..0000000000 --- a/apps/services/metrics_hub.cpp +++ /dev/null @@ -1,92 +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 "metrics_hub.h" -#include "srsran/srslog/srslog.h" - -using namespace srsran; - -metrics_hub::metrics_hub(task_executor& executor_) : - logger(srslog::fetch_basic_logger("METRICS HUB")), executor(executor_) -{ -} - -void metrics_hub::add_source(std::unique_ptr source) -{ - source->set_task_executor(&executor); - sources.push_back(std::move(source)); -} - -scheduler_ue_metrics_source* metrics_hub::get_scheduler_ue_metrics_source(std::string source_name_) -{ - for (auto& source : sources) { - if (source->source_name == source_name_) { - return dynamic_cast(source.get()); - } - } - return nullptr; -} - -rlc_metrics_source* metrics_hub::get_rlc_metrics_source(std::string source_name_) -{ - for (auto& source : sources) { - if (source->source_name == source_name_) { - return dynamic_cast(source.get()); - } - } - return nullptr; -} - -scheduler_ue_metrics_source::scheduler_ue_metrics_source(std::string source_name_) : - metrics_hub_source(source_name_), - logger(srslog::fetch_basic_logger("ALL")), - metrics_pool(metric_pool_initial_capacity) -{ -} - -void scheduler_ue_metrics_source::report_metrics(const scheduler_cell_metrics& metrics) -{ - srsran_assert(executor != nullptr, "Task executor must not be nullptr"); - - // Fetch a metrics report object from the pool. - // Note: We are trying to reuse the pre-existing allocated memory in the cached_metrics object. - auto cached_metrics = metrics_pool.get(); - *cached_metrics = metrics; - - if (not executor->execute([this, cached_metrics = std::move(cached_metrics)]() { - for (auto& subscriber : subscribers) { - subscriber->report_metrics(*cached_metrics); - } - })) { - logger.warning("Failed to dispatch scheduler UE metrics"); - } -} - -void scheduler_ue_metrics_source::add_subscriber(scheduler_metrics_notifier& subscriber) -{ - subscribers.push_back(&subscriber); -} - -void rlc_metrics_source::report_metrics(const rlc_metrics& metrics) -{ - srsran_assert(executor != nullptr, "Task executor must not be nullptr"); - if (not executor->execute([this, metrics]() { - for (auto& subscriber : subscribers) { - subscriber->report_metrics(metrics); - } - })) { - srslog::fetch_basic_logger("ALL").warning("Failed to dispatch RLC metrics"); - } -} - -void rlc_metrics_source::add_subscriber(rlc_metrics_notifier& subscriber) -{ - subscribers.push_back(&subscriber); -} diff --git a/apps/services/metrics_hub.h b/apps/services/metrics_hub.h deleted file mode 100644 index 72f47c97fc..0000000000 --- a/apps/services/metrics_hub.h +++ /dev/null @@ -1,89 +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 "srsran/rlc/rlc_metrics.h" -#include "srsran/scheduler/scheduler_metrics.h" -#include "srsran/support/executors/task_executor.h" -#include "srsran/support/memory_pool/unbounded_object_pool.h" - -namespace srsran { - -/// This class is used to create a source object in the metrics hub to which one or more subscribers can be connected. -class metrics_hub_source -{ -public: - metrics_hub_source(std::string source_name_) : source_name(source_name_){}; - virtual ~metrics_hub_source() = default; - - void set_task_executor(task_executor* executor_) { executor = executor_; }; - - std::string source_name; - task_executor* executor; -}; - -class scheduler_ue_metrics_source : public metrics_hub_source, public scheduler_metrics_notifier -{ -public: - scheduler_ue_metrics_source(std::string source_name_); - void report_metrics(const scheduler_cell_metrics& metrics) override; - void add_subscriber(scheduler_metrics_notifier& subscriber); - -private: - static constexpr size_t metric_pool_initial_capacity = 3; - - srslog::basic_logger& logger; - - std::vector subscribers; - - // We use the metrics pool to cache and avoid allocating memory for each report in a RT thread. - unbounded_object_pool metrics_pool; -}; - -class rlc_metrics_source : public metrics_hub_source, public rlc_metrics_notifier -{ -public: - rlc_metrics_source(std::string source_name_) : metrics_hub_source(source_name_) {} - ~rlc_metrics_source() = default; - void report_metrics(const rlc_metrics& metrics) override; - void add_subscriber(rlc_metrics_notifier& subscriber); - -private: - std::vector subscribers; -}; - -class metrics_hub -{ -public: - metrics_hub(task_executor& executor_); - - /// \brief moves the new source object to the metrics hub. - /// \param[in] metrics_hub_source object. - void add_source(std::unique_ptr source); - - /// \brief retrieves a pointer to the Scheduler UE metric source with the given name. - /// \param[in] name of desired Scheduler UE metric source. - /// \return returns a pointer to the Scheduler UE metric source. - scheduler_ue_metrics_source* get_scheduler_ue_metrics_source(std::string source_name_); - - /// \brief retrieves a pointer to the RLC metric source with the given name. - /// \param[in] name of desired RLC metric source. - /// \return returns a pointer to the RLC metric source. - rlc_metrics_source* get_rlc_metrics_source(std::string source_name_); - -private: - std::vector> sources; - srslog::basic_logger& logger; - task_executor& executor; -}; - -} // namespace srsran diff --git a/apps/services/metrics_log_helper.cpp b/apps/services/metrics_log_helper.cpp deleted file mode 100644 index fa9b0b2b79..0000000000 --- a/apps/services/metrics_log_helper.cpp +++ /dev/null @@ -1,128 +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 "metrics_log_helper.h" -#include "srsran/support/format_utils.h" -#include -#include -#include - -using namespace srsran; - -void metrics_log_helper::report_metrics(const scheduler_cell_metrics& metrics) -{ - fmt::memory_buffer buffer; - - // log cell-wide metrics - fmt::format_to(buffer, "Cell Scheduler Metrics:"); - fmt::format_to(buffer, - " error_indications={} mean_latency={}usec latency_hist=[{}]", - metrics.nof_error_indications, - metrics.average_decision_latency.count(), - fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); - logger.info("{}", to_c_str(buffer)); - buffer.clear(); - - // log ue-specific metrics - for (const auto& ue : metrics.ue_metrics) { - fmt::format_to(buffer, "Scheduler UE Metrics:"); - fmt::format_to(buffer, " pci={}", ue.pci); - fmt::format_to(buffer, " rnti={:x}", to_value(ue.rnti)); - if (ue.cqi_stats.get_nof_observations() > 0) { - fmt::format_to(buffer, " cqi={}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); - } else { - fmt::format_to(buffer, " cqi=n/a"); - } - - if (ue.ri_stats.get_nof_observations() > 0) { - fmt::format_to(buffer, " ri={:.1f}", ue.ri_stats.get_mean()); - } else { - fmt::format_to(buffer, " ri=n/a"); - } - - fmt::format_to(buffer, " dl_mcs={}", int(ue.dl_mcs.to_uint())); - if (ue.dl_brate_kbps > 0) { - fmt::format_to(buffer, " dl_brate_kbps={}", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, false)); - } else { - fmt::format_to(buffer, " dl_brate_kbps={}", 0); - } - fmt::format_to(buffer, " dl_nof_ok={}", ue.dl_nof_ok); - fmt::format_to(buffer, " dl_nof_nok={}", ue.dl_nof_nok); - unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; - if (dl_total > 0) { - fmt::format_to(buffer, " dl_error_rate={}%", int((float)100 * ue.dl_nof_nok / dl_total)); - } else { - fmt::format_to(buffer, " dl_error_rate={}%", 0); - } - fmt::format_to(buffer, " dl_bs={}", scaled_fmt_integer(ue.dl_bs, false)); - - if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { - fmt::format_to(buffer, " pusch_snr_db={:.1f}", std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); - } else { - fmt::format_to(buffer, " pusch_snr_db=n/a"); - } - - if (!std::isinf(ue.pusch_rsrp_db) && !std::isnan(ue.pusch_rsrp_db)) { - if (ue.pusch_rsrp_db >= 0.0F) { - fmt::format_to(buffer, " pusch_rsrp_db=ovl"); - } else { - fmt::format_to(buffer, " pusch_rsrp_db={:.1f}", std::clamp(ue.pusch_rsrp_db, -99.9F, 0.0F)); - } - } else { - fmt::format_to(buffer, " pusch_rsrp_db=n/a"); - } - - fmt::format_to(buffer, " ul_mcs={}", ue.ul_mcs.to_uint()); - if (ue.ul_brate_kbps > 0) { - fmt::format_to(buffer, " ul_brate_kbps={}", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, false)); - } else { - fmt::format_to(buffer, " ul_brate_kbps={}", 0); - } - fmt::format_to(buffer, " ul_nof_ok={}", ue.ul_nof_ok); - fmt::format_to(buffer, " ul_nof_nok={}", ue.ul_nof_nok); - - unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; - if (ul_total > 0) { - fmt::format_to(buffer, " ul_error_rate={}%", int((float)100 * ue.ul_nof_nok / ul_total)); - } else { - fmt::format_to(buffer, " ul_error_rate={}%", 0); - } - fmt::format_to(buffer, " bsr={}", scaled_fmt_integer(ue.bsr, false)); - if (ue.last_ta.has_value()) { - fmt::format_to(buffer, " last_ta={}s", float_to_eng_string(ue.last_ta->to_seconds(), 0, false)); - } else { - fmt::format_to(buffer, " last_ta=n/a"); - } - if (ue.last_phr.has_value()) { - fmt::format_to(buffer, " last_phr={}", ue.last_phr.value()); - } else { - fmt::format_to(buffer, " last_phr=n/a"); - } - - logger.info("{}", to_c_str(buffer)); - buffer.clear(); - } -} - -void metrics_log_helper::report_metrics(const rlc_metrics& metrics) -{ - if (!logger.debug.enabled()) { - return; - } - fmt::memory_buffer buffer; - fmt::format_to(buffer, "RLC Metrics:"); - fmt::format_to(buffer, " du={}", metrics.du_index); - fmt::format_to(buffer, " ue={}", metrics.ue_index); - fmt::format_to(buffer, " rb={}", metrics.rb_id); - fmt::format_to(buffer, " mode={}", metrics.rx.mode); - fmt::format_to(buffer, " TX=[{}]", format_rlc_tx_metrics(metrics.metrics_period, metrics.tx)); - fmt::format_to(buffer, " RX=[{}] ", format_rlc_rx_metrics(metrics.metrics_period, metrics.rx)); - logger.debug("{}", to_c_str(buffer)); -} diff --git a/apps/services/metrics_log_helper.h b/apps/services/metrics_log_helper.h deleted file mode 100644 index fd5e1708d5..0000000000 --- a/apps/services/metrics_log_helper.h +++ /dev/null @@ -1,37 +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/rlc/rlc_metrics.h" -#include "srsran/scheduler/scheduler_metrics.h" - -namespace srsran { - -/// Class used to receive metrics reports and write them into a log file. -class metrics_log_helper : public scheduler_metrics_notifier, public rlc_metrics_notifier -{ -public: - explicit metrics_log_helper(srslog::basic_logger& logger_) : logger(logger_) {} - - /// Returns true if the metric logger is enabled, otherwise false. - bool is_enabled() const { return (logger.info.enabled() or logger.debug.enabled()); }; - - /// Notifier for the scheduler metrics. - void report_metrics(const scheduler_cell_metrics& metrics) override; - - /// Notifier for the RLC metrics. - void report_metrics(const rlc_metrics& metrics) override; - -private: - srslog::basic_logger& logger; -}; - -} // namespace srsran diff --git a/apps/services/metrics_plotter_json.cpp b/apps/services/metrics_plotter_json.cpp deleted file mode 100644 index 80a2994af9..0000000000 --- a/apps/services/metrics_plotter_json.cpp +++ /dev/null @@ -1,127 +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 "metrics_plotter_json.h" -#include "srsran/support/math_utils.h" - -using namespace srsran; - -namespace { - -/// UE container metrics. -DECLARE_METRIC("pci", metric_pci, pci_t, ""); -DECLARE_METRIC("rnti", metric_rnti, uint16_t, ""); -DECLARE_METRIC("cqi", metric_cqi, uint8_t, ""); -DECLARE_METRIC("ri", metric_ri, float, ""); -DECLARE_METRIC("dl_mcs", metric_dl_mcs, uint8_t, ""); -DECLARE_METRIC("dl_brate", metric_dl_brate, double, ""); -DECLARE_METRIC("dl_nof_ok", metric_dl_nof_ok, unsigned, ""); -DECLARE_METRIC("dl_nof_nok", metric_dl_nof_nok, unsigned, ""); -DECLARE_METRIC("dl_bs", metric_dl_bs, unsigned, ""); -DECLARE_METRIC("pusch_snr_db", metric_pusch_snr_db, float, ""); -DECLARE_METRIC("ul_mcs", metric_ul_mcs, uint8_t, ""); -DECLARE_METRIC("ul_brate", metric_ul_brate, double, ""); -DECLARE_METRIC("ul_nof_ok", metric_ul_nof_ok, unsigned, ""); -DECLARE_METRIC("ul_nof_nok", metric_ul_nof_nok, unsigned, ""); -DECLARE_METRIC("bsr", metric_bsr, unsigned, ""); -DECLARE_METRIC_SET("ue_container", - mset_ue_container, - metric_pci, - metric_rnti, - metric_cqi, - metric_ri, - metric_dl_mcs, - metric_dl_brate, - metric_dl_nof_ok, - metric_dl_nof_nok, - metric_dl_bs, - metric_pusch_snr_db, - metric_ul_mcs, - metric_ul_brate, - metric_ul_nof_ok, - metric_ul_nof_nok, - metric_bsr); - -/// cell-wide metrics. -DECLARE_METRIC("error_indication_count", metric_error_indication_count, unsigned, ""); -DECLARE_METRIC("average_latency", metric_average_latency, unsigned, ""); -DECLARE_METRIC("latency_bin_start_usec", latency_bin_start_usec, unsigned, ""); -DECLARE_METRIC("latency_bin_count", latency_bin_count, unsigned, ""); -DECLARE_METRIC_SET("latency_bin", latency_bin, latency_bin_start_usec, latency_bin_count); -DECLARE_METRIC_LIST("latency_histogram", latency_histogram, std::vector); -DECLARE_METRIC_SET("cell_metrics", - cell_metrics, - metric_error_indication_count, - metric_average_latency, - latency_histogram); - -/// Metrics root object. -DECLARE_METRIC("timestamp", metric_timestamp_tag, double, ""); -DECLARE_METRIC_LIST("ue_list", mlist_ues, std::vector); - -/// Metrics context. -using metric_context_t = srslog::build_context_type; - -} // namespace - -/// Returns the current time in seconds with ms precision since UNIX epoch. -static double get_time_stamp() -{ - auto tp = std::chrono::system_clock::now().time_since_epoch(); - return std::chrono::duration_cast(tp).count() * 1e-3; -} - -void metrics_plotter_json::report_metrics(const scheduler_cell_metrics& metrics) -{ - metric_context_t ctx("JSON Metrics"); - - for (const auto& ue : metrics.ue_metrics) { - ctx.get().emplace_back(); - auto& output = ctx.get().back(); - - output.write(ue.pci); - output.write(to_value(ue.rnti)); - if (ue.cqi_stats.get_nof_observations() > 0) { - output.write(static_cast(std::roundf(ue.cqi_stats.get_mean()))); - } - if (ue.ri_stats.get_nof_observations() > 0) { - output.write(ue.ri_stats.get_mean()); - } - output.write(ue.dl_mcs.to_uint()); - output.write(ue.dl_brate_kbps * 1e3); - output.write(ue.dl_nof_ok); - output.write(ue.dl_nof_nok); - output.write(ue.dl_bs); - if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { - output.write(std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); - } - output.write(ue.ul_mcs.to_uint()); - output.write(ue.ul_brate_kbps * 1e3); - output.write(ue.ul_nof_ok); - output.write(ue.ul_nof_nok); - output.write(ue.bsr); - } - - auto& cell_output = ctx.get(); - cell_output.write(metrics.nof_error_indications); - cell_output.write(metrics.average_decision_latency.count()); - unsigned bin_idx = 0; - for (unsigned bin_count : metrics.latency_histogram) { - cell_output.get().emplace_back(); - auto& elem = cell_output.get().back(); - elem.write(bin_idx * scheduler_cell_metrics::nof_usec_per_bin); - elem.write(bin_count); - bin_idx++; - } - - // Log the context. - ctx.write(get_time_stamp()); - log_chan(ctx); -} diff --git a/apps/services/metrics_plotter_json.h b/apps/services/metrics_plotter_json.h deleted file mode 100644 index 9a19d8768a..0000000000 --- a/apps/services/metrics_plotter_json.h +++ /dev/null @@ -1,30 +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/scheduler/scheduler_metrics.h" - -namespace srsran { - -/// Class used to receive metrics reports from scheduler and format them into a JSON file. -class metrics_plotter_json : public scheduler_metrics_notifier -{ -public: - explicit metrics_plotter_json(srslog::log_channel& log_chan_) : log_chan(log_chan_) {} - - /// Notifier called from the scheduler. - void report_metrics(const scheduler_cell_metrics& metrics) override; - -private: - srslog::log_channel& log_chan; -}; - -} // namespace srsran diff --git a/apps/services/metrics_plotter_stdout.cpp b/apps/services/metrics_plotter_stdout.cpp deleted file mode 100644 index 0825df800f..0000000000 --- a/apps/services/metrics_plotter_stdout.cpp +++ /dev/null @@ -1,127 +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 "metrics_plotter_stdout.h" -#include "srsran/support/engineering_notation.h" -#include "srsran/support/math_utils.h" -#include -#include -#include - -using namespace srsran; - -static void print_header() -{ - fmt::print("\n"); - fmt::print( - " " - "|--------------------DL---------------------|-------------------------UL------------------------------\n"); - fmt::print(" pci rnti | cqi ri mcs brate ok nok (%) dl_bs | pusch rsrp mcs brate ok nok (%) bsr " - " ta phr\n"); -} - -void metrics_plotter_stdout::report_metrics(const scheduler_cell_metrics& metrics) -{ - if (!print_metrics) { - return; - } - - if (metrics.ue_metrics.size() > 10) { - print_header(); - } else if (++nof_lines > 10 && !metrics.ue_metrics.empty()) { - nof_lines = 0; - print_header(); - } - - for (const auto& ue : metrics.ue_metrics) { - fmt::print("{:>4}", ue.pci); - fmt::print("{:>5x}", to_value(ue.rnti)); - - if (ue.cqi_stats.get_nof_observations() > 0) { - fmt::print(" | {:>3}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); - } else { - fmt::print(" | {:>3.3}", "n/a"); - } - - if (ue.ri_stats.get_nof_observations() > 0) { - fmt::print(" {:>3.1f}", ue.ri_stats.get_mean()); - } else { - fmt::print(" {:>3.3}", "n/a"); - } - - fmt::print(" {:>2}", int(ue.dl_mcs.to_uint())); - if (ue.dl_brate_kbps > 0) { - fmt::print(" {:>6.6}", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, true)); - } else { - fmt::print(" {:>6}", 0); - } - fmt::print(" {:>4}", ue.dl_nof_ok); - fmt::print(" {:>4}", ue.dl_nof_nok); - unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; - if (dl_total > 0) { - fmt::print(" {:>3}%", int((float)100 * ue.dl_nof_nok / dl_total)); - } else { - fmt::print(" {:>3}%", 0); - } - fmt::print(" {}", scaled_fmt_integer(ue.dl_bs, true)); - - fmt::print(" |"); - - if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { - fmt::print(" {:>5.1f}", std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); - } else { - fmt::print(" {:>5.5}", "n/a"); - } - - if (!std::isinf(ue.pusch_rsrp_db) && !std::isnan(ue.pusch_rsrp_db)) { - if (ue.pusch_rsrp_db >= 0.0F) { - fmt::print(" {:>5.5}", "ovl"); - } else { - fmt::print(" {:>5.1f}", std::clamp(ue.pusch_rsrp_db, -99.9F, 0.0F)); - } - } else { - fmt::print(" {:>5.5}", "n/a"); - } - - fmt::print(" {:>2}", ue.ul_mcs.to_uint()); - if (ue.ul_brate_kbps > 0) { - fmt::print(" {:>6.6}", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, true)); - } else { - fmt::print(" {:>6}", 0); - } - fmt::print(" {:>4}", ue.ul_nof_ok); - fmt::print(" {:>4}", ue.ul_nof_nok); - - unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; - if (ul_total > 0) { - fmt::print(" {:>3}%", int((float)100 * ue.ul_nof_nok / ul_total)); - } else { - fmt::print(" {:>3}%", 0); - } - fmt::print(" {}", scaled_fmt_integer(ue.bsr, true)); - if (ue.last_ta.has_value()) { - fmt::print(" {}", float_to_eng_string(ue.last_ta->to_seconds(), 0, true)); - } else { - fmt::print(" n/a"); - } - if (ue.last_phr.has_value()) { - fmt::print(" {:>4}", ue.last_phr.value()); - } else { - fmt::print(" n/a"); - } - - fmt::print("\n"); - } -} - -void metrics_plotter_stdout::toggle_print() -{ - print_metrics = !print_metrics; -} diff --git a/apps/services/metrics_plotter_stdout.h b/apps/services/metrics_plotter_stdout.h deleted file mode 100644 index 111fb4a4c2..0000000000 --- a/apps/services/metrics_plotter_stdout.h +++ /dev/null @@ -1,34 +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/scheduler/scheduler_metrics.h" - -namespace srsran { - -/// Class used to receive metrics reports from scheduler and pretty-print them to the console. -class metrics_plotter_stdout : public scheduler_metrics_notifier -{ -public: - explicit metrics_plotter_stdout(bool print_metrics_) : print_metrics(print_metrics_) {} - - /// Notifier called from the scheduler. - void report_metrics(const scheduler_cell_metrics& metrics) override; - - /// This can be called from another execution context to turn on/off the actual plotting. - void toggle_print(); - -private: - unsigned nof_lines = 10; - std::atomic print_metrics = {false}; -}; - -} // namespace srsran diff --git a/apps/services/rlc_metrics_plotter_json.h b/apps/services/rlc_metrics_plotter_json.h deleted file mode 100644 index 249f3b5eed..0000000000 --- a/apps/services/rlc_metrics_plotter_json.h +++ /dev/null @@ -1,30 +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/rlc/rlc_metrics.h" - -namespace srsran { - -/// Class used to receive metrics reports from scheduler and format them into a JSON file. -class rlc_metrics_plotter_json : public rlc_metrics_notifier -{ -public: - explicit rlc_metrics_plotter_json(srslog::log_channel& log_chan_) : log_chan(log_chan_) {} - - /// Notifier called from the scheduler. - void report_metrics(const rlc_metrics& metrics) override; - -private: - srslog::log_channel& log_chan; -}; - -} // namespace srsran diff --git a/apps/units/flexible_du/du_high/CMakeLists.txt b/apps/units/flexible_du/du_high/CMakeLists.txt index c15ca7c2d9..1140a4657d 100644 --- a/apps/units/flexible_du/du_high/CMakeLists.txt +++ b/apps/units/flexible_du/du_high/CMakeLists.txt @@ -6,6 +6,8 @@ # the distribution. # +add_subdirectory(metrics) + set(SOURCES du_high_config_cli11_schema.cpp du_high_config_translators.cpp @@ -15,4 +17,4 @@ set(SOURCES add_library(srsran_du_high_unit_helpers STATIC ${SOURCES}) target_include_directories(srsran_du_high_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_du_high_unit_helpers sched_config) +target_link_libraries(srsran_du_high_unit_helpers sched_config srsran_du_high_unit_metrics_helpers) diff --git a/apps/units/flexible_du/du_high/du_high_commands.h b/apps/units/flexible_du/du_high/du_high_commands.h index fb560f0553..812a1c9771 100644 --- a/apps/units/flexible_du/du_high/du_high_commands.h +++ b/apps/units/flexible_du/du_high/du_high_commands.h @@ -11,17 +11,17 @@ #pragma once #include "apps/services/application_command.h" -#include "apps/services/metrics_plotter_stdout.h" +#include "metrics/du_high_scheduler_cell_metrics_consumers.h" namespace srsran { /// Application command to display/hide the DU high metrics in STDOUT. class toggle_stdout_metrics_app_command : public app_services::application_command { - metrics_plotter_stdout& printer; + scheduler_cell_metrics_consumer_stdout& printer; public: - explicit toggle_stdout_metrics_app_command(metrics_plotter_stdout& printer_) : printer(printer_) {} + explicit toggle_stdout_metrics_app_command(scheduler_cell_metrics_consumer_stdout& printer_) : printer(printer_) {} // See interface for documentation. std::string_view get_name() const override { return "t"; } 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 b21460878e..eec64f7079 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -41,11 +41,12 @@ namespace srsran { /// DU high logging functionalities. struct du_high_unit_logger_config { - srslog::basic_levels du_level = srslog::basic_levels::warning; - srslog::basic_levels mac_level = srslog::basic_levels::warning; - srslog::basic_levels rlc_level = srslog::basic_levels::warning; - srslog::basic_levels f1ap_level = srslog::basic_levels::warning; - srslog::basic_levels f1u_level = srslog::basic_levels::warning; + srslog::basic_levels du_level = srslog::basic_levels::warning; + srslog::basic_levels mac_level = srslog::basic_levels::warning; + srslog::basic_levels rlc_level = srslog::basic_levels::warning; + srslog::basic_levels f1ap_level = srslog::basic_levels::warning; + srslog::basic_levels f1u_level = srslog::basic_levels::warning; + srslog::basic_levels metrics_level = srslog::basic_levels::none; /// Maximum number of bytes to write when dumping hex arrays. int hex_max_size = 0; @@ -604,8 +605,9 @@ struct du_high_unit_metrics_config { unsigned report_period = 0; // RLC report period in ms bool json_enabled = false; } rlc; - bool enable_json_metrics = false; - unsigned stdout_metrics_period = 1000; // Statistics report period in milliseconds + bool enable_json_metrics = false; + unsigned stdout_metrics_period = 1000; // Statistics report period in milliseconds + bool autostart_stdout_metrics = false; }; struct du_high_unit_pcap_config { 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 a0319abc8f..94c222f653 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 @@ -62,6 +62,21 @@ static void configure_cli11_log_args(CLI::App& app, du_high_unit_logger_config& app_services::add_log_option(app, log_params.f1u_level, "--f1u_level", "F1-U log level"); app_services::add_log_option(app, log_params.du_level, "--du_level", "Log level for the DU"); + auto metric_level_check = [](const std::string& value) -> std::string { + if (auto level = srslog::str_to_basic_level(value); !level.has_value() || + level.value() == srslog::basic_levels::error || + level.value() == srslog::basic_levels::warning) { + return "Log level value not supported. Accepted values [none,info,debug]"; + } + + return {}; + }; + + add_option_function( + app, "--metrics_level", app_services::capture_log_level_function(log_params.metrics_level), "Metrics log level") + ->default_str(srslog::basic_level_to_string(log_params.metrics_level)) + ->check(metric_level_check); + add_option( app, "--hex_max_size", log_params.hex_max_size, "Maximum number of bytes to print in hex (zero for no hex dumps)") ->capture_default_str() @@ -1378,6 +1393,10 @@ static void configure_cli11_metrics_args(CLI::App& app, du_high_unit_metrics_con add_option(app, "--enable_json_metrics", metrics_params.enable_json_metrics, "Enable JSON metrics reporting") ->always_capture_default(); + add_option( + app, "--autostart_stdout_metrics", metrics_params.autostart_stdout_metrics, "Autostart stdout metrics reporting") + ->capture_default_str(); + add_option(app, "--stdout_metrics_period", metrics_params.stdout_metrics_period, diff --git a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp index 4f01ff4d7c..6a36ac0bc0 100644 --- a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp +++ b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp @@ -9,24 +9,20 @@ */ #include "du_high_wrapper_config_helper.h" + #include "apps/services/e2_metric_connector_manager.h" -#include "apps/services/metrics_hub.h" -#include "apps/services/metrics_log_helper.h" -#include "apps/services/metrics_plotter_json.h" -#include "apps/services/metrics_plotter_stdout.h" +#include "du_high_commands.h" #include "du_high_config.h" #include "du_high_config_translators.h" +#include "metrics/du_high_rlc_metrics_consumers.h" +#include "metrics/du_high_rlc_metrics_producer.h" +#include "metrics/du_high_scheduler_cell_metrics_consumers.h" +#include "metrics/du_high_scheduler_cell_metrics_producer.h" #include "srsran/du/du_high_wrapper_factory.h" using namespace srsran; -void srsran::configure_du_high_metrics(const du_high_unit_config& du_high_unit_cfg, - metrics_plotter_stdout& metrics_stdout, - metrics_log_helper& metrics_logger, - metrics_plotter_json& metrics_json, - rlc_metrics_notifier& rlc_json_metrics, - e2_metric_connector_manager& e2_metric_connectors, - metrics_hub& metrics_hub) +void srsran::announce_du_high_cells(const du_high_unit_config& du_high_unit_cfg) { // Generate DU cells. auto cells = generate_du_cell_config(du_high_unit_cfg); @@ -43,69 +39,109 @@ void srsran::configure_du_high_metrics(const du_high_unit_config& du_high_unit cell.dl_cfg_common.freq_info_dl.absolute_frequency_ssb, srsran::band_helper::nr_arfcn_to_freq(cell.ul_carrier.arfcn) / 1e6); } + fmt::print("\n"); +} + +static scheduler_metrics_notifier* +build_scheduler_du_metrics(std::pair, + std::vector>>& du_services_cfg, + app_services::metrics_notifier& metrics_notifier, + const du_high_unit_config& du_high_unit_cfg, + srslog::sink& json_sink, + e2_du_metrics_notifier& e2_notifier) +{ + // Scheduler cell metrics. + auto sched_cell_metrics_gen = std::make_unique(metrics_notifier); + scheduler_metrics_notifier* out = &(*sched_cell_metrics_gen); + app_services::metrics_config& sched_metrics_cfg = du_services_cfg.first.emplace_back(); + sched_metrics_cfg.metric_name = scheduler_cell_metrics_property_impl().name(); + sched_metrics_cfg.callback = sched_cell_metrics_gen->get_callback(); + sched_metrics_cfg.producers.push_back(std::move(sched_cell_metrics_gen)); + + // Create the consumer for STDOUT. Also create the command for toogle the metrics. + auto metrics_stdout = + std::make_unique(du_high_unit_cfg.metrics.autostart_stdout_metrics); + du_services_cfg.second.push_back(std::make_unique(*metrics_stdout)); + sched_metrics_cfg.consumers.push_back(std::move(metrics_stdout)); - // Set up sources for the DU Scheruler UE metrics and add them to metric hub. - for (unsigned i = 0; i != cells.size(); i++) { - std::string source_name = "DU " + std::to_string(i); - auto source = std::make_unique(source_name); + if (du_high_unit_cfg.loggers.metrics_level == srslog::basic_levels::info || + du_high_unit_cfg.loggers.metrics_level == srslog::basic_levels::debug) { + sched_metrics_cfg.consumers.push_back( + std::make_unique(srslog::fetch_basic_logger("METRICS"))); + } - // Connect Console Aggregator to DU Scheduler UE metrics. - source->add_subscriber(metrics_stdout); + // Connect JSON metrics reporter to DU Scheduler UE metrics. + if (du_high_unit_cfg.metrics.enable_json_metrics) { + srslog::log_channel& json_channel = srslog::fetch_log_channel("JSON_channel", json_sink, {}); + json_channel.set_enabled(true); + sched_metrics_cfg.consumers.push_back(std::make_unique(json_channel)); + } - if (metrics_logger.is_enabled()) { - source->add_subscriber(metrics_logger); - } + // Connect E2 agent to DU Scheduler UE metrics. + if (du_high_unit_cfg.e2_cfg.enable_du_e2) { + sched_metrics_cfg.consumers.push_back(std::make_unique(e2_notifier)); + } - // Connect JSON metrics reporter to DU Scheduler UE metrics. - if (du_high_unit_cfg.metrics.enable_json_metrics) { - source->add_subscriber(metrics_json); - } + return out; +} - // Connect E2 agent to DU Scheduler UE metrics. - if (du_high_unit_cfg.e2_cfg.enable_du_e2) { - source->add_subscriber(e2_metric_connectors.get_e2_du_metric_notifier(i)); - } +static rlc_metrics_notifier* build_rlc_du_metrics(std::vector& metrics, + app_services::metrics_notifier& metrics_notifier, + const du_high_unit_config& du_high_unit_cfg, + srslog::sink& json_sink, + e2_du_metrics_notifier& e2_notifier) +{ + rlc_metrics_notifier* out = nullptr; - metrics_hub.add_source(std::move(source)); + // RLC metrics. + if (!du_high_unit_cfg.metrics.rlc.json_enabled && !du_high_unit_cfg.e2_cfg.enable_du_e2 && + du_high_unit_cfg.loggers.metrics_level != srslog::basic_levels::debug) { + return out; } - // Set up sources for the DU Scheruler UE metrics and add them to metric hub. - for (unsigned i = 0; i != cells.size(); i++) { - if (du_high_unit_cfg.metrics.rlc.report_period != 0) { - // This source aggregates the RLC metrics from all DRBs in a single DU. - std::string source_name = "DU RLC " + std::to_string(i); - auto rlc_source = std::make_unique(source_name); - - if (du_high_unit_cfg.metrics.rlc.json_enabled) { - // Connect JSON metrics plotter to RLC metric source. - rlc_source->add_subscriber(rlc_json_metrics); - } - if (metrics_logger.is_enabled()) { - rlc_source->add_subscriber(metrics_logger); - } - if (du_high_unit_cfg.e2_cfg.enable_du_e2) { - // Connect E2 agent to RLC metric source. - rlc_source->add_subscriber(e2_metric_connectors.get_e2_du_metric_notifier(i)); - } - // Pass RLC metric source to the DU high. - metrics_hub.add_source(std::move(rlc_source)); - } + app_services::metrics_config& rlc_metrics_cfg = metrics.emplace_back(); + rlc_metrics_cfg.metric_name = rlc_metrics_properties_impl().name(); + rlc_metrics_cfg.callback = rlc_metrics_callback; + + // Fill the generator. + auto rlc_metric_gen = std::make_unique(metrics_notifier); + out = &(*rlc_metric_gen); + rlc_metrics_cfg.producers.push_back(std::move(rlc_metric_gen)); + + // Consumers. + if (du_high_unit_cfg.loggers.metrics_level == srslog::basic_levels::debug) { + rlc_metrics_cfg.consumers.push_back( + std::make_unique(srslog::fetch_basic_logger("METRICS"))); + } + + if (du_high_unit_cfg.metrics.rlc.json_enabled) { + srslog::log_channel& rlc_json_channel = srslog::fetch_log_channel("JSON_RLC_channel", json_sink, {}); + rlc_json_channel.set_enabled(true); + rlc_metrics_cfg.consumers.push_back(std::make_unique(rlc_json_channel)); } + + if (du_high_unit_cfg.e2_cfg.enable_du_e2) { + rlc_metrics_cfg.consumers.push_back(std::make_unique(e2_notifier)); + } + + return out; } -void srsran::fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, - const du_high_unit_config& du_high_unit_cfg, - unsigned du_idx, - du_high_executor_mapper& execution_mapper, - srs_du::f1c_connection_client& f1c_client_handler, - srs_du::f1u_du_gateway& f1u_gw, - timer_manager& timer_mng, - mac_pcap& mac_p, - rlc_pcap& rlc_p, - e2_connection_client& e2_client_handler, - e2_metric_connector_manager& e2_metric_connectors, - metrics_hub& metrics_hub) +std::pair, std::vector>> +srsran::fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, + const du_high_unit_config& du_high_unit_cfg, + unsigned du_idx, + du_high_executor_mapper& execution_mapper, + srs_du::f1c_connection_client& f1c_client_handler, + srs_du::f1u_du_gateway& f1u_gw, + timer_manager& timer_mng, + mac_pcap& mac_p, + rlc_pcap& rlc_p, + e2_connection_client& e2_client_handler, + e2_metric_connector_manager& e2_metric_connectors, + srslog::sink& json_sink, + app_services::metrics_notifier& metrics_notifier) { // DU-high configuration. srs_du::du_high_configuration& du_hi_cfg = out_cfg.du_hi; @@ -119,14 +155,12 @@ void srsran::fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, du_hi_cfg.qos = generate_du_qos_config(du_high_unit_cfg); du_hi_cfg.mac_p = &mac_p; du_hi_cfg.rlc_p = &rlc_p; - du_hi_cfg.gnb_du_id = (gnb_du_id_t)((unsigned)du_high_unit_cfg.gnb_du_id + du_idx); - du_hi_cfg.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.gnb_du_id); - du_hi_cfg.mac_cfg = generate_mac_expert_config(du_high_unit_cfg); + du_hi_cfg.gnb_du_id = static_cast((static_cast(du_high_unit_cfg.gnb_du_id) + du_idx)); + du_hi_cfg.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.gnb_du_id); + du_hi_cfg.mac_cfg = generate_mac_expert_config(du_high_unit_cfg); // Assign different initial C-RNTIs to different DUs. - du_hi_cfg.mac_cfg.initial_crnti = to_rnti(0x4601 + (0x1000 * du_idx)); - du_hi_cfg.sched_ue_metrics_notifier = metrics_hub.get_scheduler_ue_metrics_source("DU " + std::to_string(du_idx)); - du_hi_cfg.rlc_metrics_notif = metrics_hub.get_rlc_metrics_source("DU RLC " + std::to_string(du_idx)); - du_hi_cfg.sched_cfg = generate_scheduler_expert_config(du_high_unit_cfg); + du_hi_cfg.mac_cfg.initial_crnti = to_rnti(0x4601 + (0x1000 * du_idx)); + du_hi_cfg.sched_cfg = generate_scheduler_expert_config(du_high_unit_cfg); if (du_high_unit_cfg.e2_cfg.enable_du_e2) { // Connect E2 agent to RLC metric source. @@ -135,6 +169,22 @@ void srsran::fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, du_hi_cfg.e2_du_metric_iface = &(e2_metric_connectors.get_e2_du_metrics_interface(du_idx)); } + // DU high metrics. + std::pair, std::vector>> + du_services_cfg; + du_hi_cfg.sched_ue_metrics_notifier = + build_scheduler_du_metrics(du_services_cfg, + metrics_notifier, + du_high_unit_cfg, + json_sink, + e2_metric_connectors.get_e2_du_metric_notifier(du_idx)); + + du_hi_cfg.rlc_metrics_notif = build_rlc_du_metrics(du_services_cfg.first, + metrics_notifier, + du_high_unit_cfg, + json_sink, + e2_metric_connectors.get_e2_du_metric_notifier(du_idx)); + // Configure test mode if (du_high_unit_cfg.test_mode_cfg.test_ue.rnti != rnti_t::INVALID_RNTI) { du_hi_cfg.test_cfg.test_ue = @@ -150,4 +200,6 @@ void srsran::fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, du_high_unit_cfg.test_mode_cfg.test_ue.i_1_3, du_high_unit_cfg.test_mode_cfg.test_ue.i_2}; } + + return du_services_cfg; } diff --git a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.h b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.h index fc28685cff..c96f24ca6d 100644 --- a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.h +++ b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.h @@ -10,8 +10,15 @@ #pragma once +#include "apps/services/application_command.h" +#include "apps/services/metrics/metrics_config.h" + namespace srsran { +namespace app_services { +class metrics_notifier; +} + namespace srs_du { class f1u_du_gateway; class f1c_connection_client; @@ -21,11 +28,6 @@ class du_high_executor_mapper; class e2_metric_connector_manager; class e2_connection_client; class mac_pcap; -class metrics_hub; -class metrics_log_helper; -class metrics_plotter_json; -class metrics_plotter_stdout; -class rlc_metrics_notifier; class rlc_pcap; class timer_manager; struct du_high_unit_config; @@ -33,26 +35,22 @@ struct du_high_wrapper_config; struct du_high_wrapper_dependencies; /// Set up sources for the DU high metrics. -void configure_du_high_metrics(const du_high_unit_config& du_high_unit_cfg, - metrics_plotter_stdout& metrics_stdout, - metrics_log_helper& metrics_logger, - metrics_plotter_json& metrics_json, - rlc_metrics_notifier& rlc_metrics_json, - e2_metric_connector_manager& e2_metric_connectors, - metrics_hub& metrics_hub); +void announce_du_high_cells(const du_high_unit_config& du_high_unit_cfg); /// Fills the given DU high wrapper configuration. -void fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, - const du_high_unit_config& du_high_unit_cfg, - unsigned du_id, - du_high_executor_mapper& execution_mapper, - srs_du::f1c_connection_client& f1c_client_handler, - srs_du::f1u_du_gateway& f1u_gw, - timer_manager& timer_mng, - mac_pcap& mac_p, - rlc_pcap& rlc_p, - e2_connection_client& e2_client_handler, - e2_metric_connector_manager& e2_metric_connectors, - metrics_hub& metrics_hub); +std::pair, std::vector>> +fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, + const du_high_unit_config& du_high_unit_cfg, + unsigned du_idx, + du_high_executor_mapper& execution_mapper, + srs_du::f1c_connection_client& f1c_client_handler, + srs_du::f1u_du_gateway& f1u_gw, + timer_manager& timer_mng, + mac_pcap& mac_p, + rlc_pcap& rlc_p, + e2_connection_client& e2_client_handler, + e2_metric_connector_manager& e2_metric_connectors, + srslog::sink& json_sink, + app_services::metrics_notifier& metrics_notifier); } // namespace srsran diff --git a/apps/units/flexible_du/du_high/metrics/CMakeLists.txt b/apps/units/flexible_du/du_high/metrics/CMakeLists.txt new file mode 100644 index 0000000000..43ebdb6282 --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# 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. +# + +set(SOURCES + du_high_rlc_metrics_producer.cpp + du_high_rlc_metrics_consumers.cpp + du_high_scheduler_cell_metrics_producer.cpp + du_high_scheduler_cell_metrics_consumers.cpp) + +add_library(srsran_du_high_unit_metrics_helpers STATIC ${SOURCES}) +target_include_directories(srsran_du_high_unit_metrics_helpers PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics.h b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics.h new file mode 100644 index 0000000000..997eb55525 --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics.h @@ -0,0 +1,58 @@ +/* + * + * 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/metrics/metrics_consumer.h" +#include "apps/services/metrics/metrics_properties.h" +#include "apps/services/metrics/metrics_set.h" +#include "srsran/adt/span.h" +#include "srsran/rlc/rlc_metrics.h" + +namespace srsran { + +/// RLC metrics properties implementation. +class rlc_metrics_properties_impl : public app_services::metrics_properties +{ +public: + std::string_view name() const override { return "RLC metrics"; } +}; + +class rlc_metrics_impl : public app_services::metrics_set +{ + rlc_metrics_properties_impl properties; + rlc_metrics metrics; + +public: + explicit rlc_metrics_impl(const rlc_metrics& metrics_) : metrics(metrics_) {} + + // See interface for documentation. + const app_services::metrics_properties& get_properties() const override { return properties; } + + const rlc_metrics& get_metrics() const { return metrics; } +}; + +/// Callback for the RLC metrics. +inline auto rlc_metrics_callback = [](const app_services::metrics_set& report, + span consumers, + task_executor& executor, + srslog::basic_logger& logger) { + const auto& metric = static_cast(report); + + if (!executor.defer([metric, consumers]() { + for (auto& consumer : consumers) { + consumer->handle_metric(metric); + } + })) { + logger.error("Failed to dispatch the metric '{}'", metric.get_properties().name()); + } +}; + +} // namespace srsran diff --git a/apps/services/rlc_metrics_plotter_json.cpp b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.cpp similarity index 78% rename from apps/services/rlc_metrics_plotter_json.cpp rename to apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.cpp index d1c791a97b..b2d329db17 100644 --- a/apps/services/rlc_metrics_plotter_json.cpp +++ b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.cpp @@ -8,8 +8,9 @@ * */ -#include "rlc_metrics_plotter_json.h" -#include "srsran/support/math_utils.h" +#include "du_high_rlc_metrics_consumers.h" +#include "du_high_rlc_metrics.h" +#include "srsran/support/format_utils.h" using namespace srsran; @@ -77,8 +78,10 @@ static double get_time_stamp() return std::chrono::duration_cast(tp).count() * 1e-3; } -void rlc_metrics_plotter_json::report_metrics(const rlc_metrics& drb) +void rlc_metrics_consumer_json::handle_metric(const app_services::metrics_set& metric) { + const rlc_metrics& drb = static_cast(metric).get_metrics(); + metric_context_t ctx("JSON RLC Metrics"); ctx.get().emplace_back(); @@ -109,3 +112,23 @@ void rlc_metrics_plotter_json::report_metrics(const rlc_metrics& drb) ctx.write(get_time_stamp()); log_chan(ctx); } + +void rlc_metrics_consumer_log::handle_metric(const app_services::metrics_set& metric) +{ + const rlc_metrics& drb = static_cast(metric).get_metrics(); + + fmt::memory_buffer buffer; + fmt::format_to(buffer, "RLC Metrics:"); + fmt::format_to(buffer, " du={}", static_cast(drb.du_index)); + fmt::format_to(buffer, " ue={}", drb.ue_index); + fmt::format_to(buffer, " rb={}", drb.rb_id); + fmt::format_to(buffer, " mode={}", drb.rx.mode); + fmt::format_to(buffer, " TX=[{}]", format_rlc_tx_metrics(drb.metrics_period, drb.tx)); + fmt::format_to(buffer, " RX=[{}] ", format_rlc_rx_metrics(drb.metrics_period, drb.rx)); + logger.debug("{}", to_c_str(buffer)); +} + +void rlc_metrics_consumer_e2::handle_metric(const app_services::metrics_set& metric) +{ + notifier.report_metrics(static_cast(metric).get_metrics()); +} diff --git a/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.h b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.h new file mode 100644 index 0000000000..7e4ad76560 --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_consumers.h @@ -0,0 +1,58 @@ +/* + * + * 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 "du_high_rlc_metrics.h" +#include "srsran/srslog/log_channel.h" +#include "srsran/srslog/logger.h" + +namespace srsran { + +/// Consumer for the json RLC metrics. +class rlc_metrics_consumer_json : public app_services::metrics_consumer +{ +public: + explicit rlc_metrics_consumer_json(srslog::log_channel& log_chan_) : log_chan(log_chan_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + +private: + srslog::log_channel& log_chan; +}; + +/// Consumer for the log RLC metrics. +class rlc_metrics_consumer_log : public app_services::metrics_consumer +{ +public: + explicit rlc_metrics_consumer_log(srslog::basic_logger& logger_) : logger(logger_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + +private: + srslog::basic_logger& logger; +}; + +/// Consumer for the E2 RLC metrics. +class rlc_metrics_consumer_e2 : public app_services::metrics_consumer +{ +public: + explicit rlc_metrics_consumer_e2(rlc_metrics_notifier& notifier_) : notifier(notifier_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + +private: + rlc_metrics_notifier& notifier; +}; + +} // namespace srsran diff --git a/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.cpp b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.cpp new file mode 100644 index 0000000000..cbb93b7883 --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.cpp @@ -0,0 +1,19 @@ +/* + * + * 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 "du_high_rlc_metrics_producer.h" +#include "du_high_rlc_metrics.h" + +using namespace srsran; + +void rlc_metrics_producer_impl::report_metrics(const rlc_metrics& report) +{ + notifier.on_new_metric(rlc_metrics_impl(report)); +} diff --git a/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.h b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.h new file mode 100644 index 0000000000..370050e0de --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_rlc_metrics_producer.h @@ -0,0 +1,32 @@ +/* + * + * 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/metrics/metrics_notifier.h" +#include "apps/services/metrics/metrics_producer.h" +#include "srsran/rlc/rlc_metrics.h" + +namespace srsran { + +/// RLC metrics producer implementation. +class rlc_metrics_producer_impl : public rlc_metrics_notifier, public app_services::metrics_producer +{ +public: + explicit rlc_metrics_producer_impl(app_services::metrics_notifier& notifier_) : notifier(notifier_) {} + + // See interface for documentation. + void report_metrics(const rlc_metrics& metrics) override; + +private: + app_services::metrics_notifier& notifier; +}; + +} // namespace srsran diff --git a/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics.h b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics.h new file mode 100644 index 0000000000..bf10fb91ee --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics.h @@ -0,0 +1,41 @@ +/* + * + * 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/metrics/metrics_properties.h" +#include "apps/services/metrics/metrics_set.h" +#include "srsran/scheduler/scheduler_metrics.h" + +namespace srsran { + +/// Scheduler cell metrics property implementation. +class scheduler_cell_metrics_property_impl : public app_services::metrics_properties +{ +public: + std::string_view name() const override { return "Scheduler UE metrics"; } +}; + +/// Scheduler cell metrics implementation for the application service. +class scheduler_cell_metrics_impl : public app_services::metrics_set +{ + scheduler_cell_metrics_property_impl properties; + const scheduler_cell_metrics& metrics; + +public: + explicit scheduler_cell_metrics_impl(const scheduler_cell_metrics& metrics_) : metrics(metrics_) {} + + // See interface for documentation. + const app_services::metrics_properties& get_properties() const override { return properties; } + + const scheduler_cell_metrics& get_metrics() const { return metrics; } +}; + +} // namespace srsran diff --git a/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp new file mode 100644 index 0000000000..b84cd2237f --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -0,0 +1,343 @@ +/* + * + * 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 "du_high_scheduler_cell_metrics_consumers.h" +#include "du_high_rlc_metrics.h" +#include "srsran/scheduler/scheduler_metrics.h" +#include "srsran/support/engineering_notation.h" +#include "srsran/support/format_utils.h" +#include "srsran/support/math_utils.h" +#include +#include + +using namespace srsran; + +namespace { + +/// UE container metrics. +DECLARE_METRIC("pci", metric_pci, pci_t, ""); +DECLARE_METRIC("rnti", metric_rnti, uint16_t, ""); +DECLARE_METRIC("cqi", metric_cqi, uint8_t, ""); +DECLARE_METRIC("ri", metric_ri, float, ""); +DECLARE_METRIC("dl_mcs", metric_dl_mcs, uint8_t, ""); +DECLARE_METRIC("dl_brate", metric_dl_brate, double, ""); +DECLARE_METRIC("dl_nof_ok", metric_dl_nof_ok, unsigned, ""); +DECLARE_METRIC("dl_nof_nok", metric_dl_nof_nok, unsigned, ""); +DECLARE_METRIC("dl_bs", metric_dl_bs, unsigned, ""); +DECLARE_METRIC("pusch_snr_db", metric_pusch_snr_db, float, ""); +DECLARE_METRIC("ul_mcs", metric_ul_mcs, uint8_t, ""); +DECLARE_METRIC("ul_brate", metric_ul_brate, double, ""); +DECLARE_METRIC("ul_nof_ok", metric_ul_nof_ok, unsigned, ""); +DECLARE_METRIC("ul_nof_nok", metric_ul_nof_nok, unsigned, ""); +DECLARE_METRIC("bsr", metric_bsr, unsigned, ""); +DECLARE_METRIC_SET("ue_container", + mset_ue_container, + metric_pci, + metric_rnti, + metric_cqi, + metric_ri, + metric_dl_mcs, + metric_dl_brate, + metric_dl_nof_ok, + metric_dl_nof_nok, + metric_dl_bs, + metric_pusch_snr_db, + metric_ul_mcs, + metric_ul_brate, + metric_ul_nof_ok, + metric_ul_nof_nok, + metric_bsr); + +/// cell-wide metrics. +DECLARE_METRIC("error_indication_count", metric_error_indication_count, unsigned, ""); +DECLARE_METRIC("average_latency", metric_average_latency, unsigned, ""); +DECLARE_METRIC("latency_bin_start_usec", latency_bin_start_usec, unsigned, ""); +DECLARE_METRIC("latency_bin_count", latency_bin_count, unsigned, ""); +DECLARE_METRIC_SET("latency_bin", latency_bin, latency_bin_start_usec, latency_bin_count); +DECLARE_METRIC_LIST("latency_histogram", latency_histogram, std::vector); +DECLARE_METRIC_SET("cell_metrics", + cell_metrics, + metric_error_indication_count, + metric_average_latency, + latency_histogram); + +/// Metrics root object. +DECLARE_METRIC("timestamp", metric_timestamp_tag, double, ""); +DECLARE_METRIC_LIST("ue_list", mlist_ues, std::vector); + +/// Metrics context. +using metric_context_t = srslog::build_context_type; + +} // namespace + +static void print_header() +{ + fmt::print("\n"); + fmt::print( + " " + "|--------------------DL---------------------|-------------------------UL------------------------------\n"); + fmt::print(" pci rnti | cqi ri mcs brate ok nok (%) dl_bs | pusch rsrp mcs brate ok nok (%) bsr " + " ta phr\n"); +} + +void scheduler_cell_metrics_consumer_stdout::handle_metric(const app_services::metrics_set& metric) +{ + if (!print_metrics) { + return; + } + + const scheduler_cell_metrics& metrics = static_cast(metric).get_metrics(); + + if (metrics.ue_metrics.size() > 10) { + print_header(); + } else if (++nof_lines > 10 && !metrics.ue_metrics.empty()) { + nof_lines = 0; + print_header(); + } + + for (const auto& ue : metrics.ue_metrics) { + fmt::print("{:>4}", ue.pci); + fmt::print("{:>5x}", to_value(ue.rnti)); + + if (ue.cqi_stats.get_nof_observations() > 0) { + fmt::print(" | {:>3}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); + } else { + fmt::print(" | {:>3.3}", "n/a"); + } + + if (ue.ri_stats.get_nof_observations() > 0) { + fmt::print(" {:>3.1f}", ue.ri_stats.get_mean()); + } else { + fmt::print(" {:>3.3}", "n/a"); + } + + fmt::print(" {:>2}", int(ue.dl_mcs.to_uint())); + if (ue.dl_brate_kbps > 0) { + fmt::print(" {:>6.6}", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, true)); + } else { + fmt::print(" {:>6}", 0); + } + fmt::print(" {:>4}", ue.dl_nof_ok); + fmt::print(" {:>4}", ue.dl_nof_nok); + unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; + if (dl_total > 0) { + fmt::print(" {:>3}%", int((float)100 * ue.dl_nof_nok / dl_total)); + } else { + fmt::print(" {:>3}%", 0); + } + fmt::print(" {}", scaled_fmt_integer(ue.dl_bs, true)); + + fmt::print(" |"); + + if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { + fmt::print(" {:>5.1f}", std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); + } else { + fmt::print(" {:>5.5}", "n/a"); + } + + if (!std::isinf(ue.pusch_rsrp_db) && !std::isnan(ue.pusch_rsrp_db)) { + if (ue.pusch_rsrp_db >= 0.0F) { + fmt::print(" {:>5.5}", "ovl"); + } else { + fmt::print(" {:>5.1f}", std::clamp(ue.pusch_rsrp_db, -99.9F, 0.0F)); + } + } else { + fmt::print(" {:>5.5}", "n/a"); + } + + fmt::print(" {:>2}", ue.ul_mcs.to_uint()); + if (ue.ul_brate_kbps > 0) { + fmt::print(" {:>6.6}", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, true)); + } else { + fmt::print(" {:>6}", 0); + } + fmt::print(" {:>4}", ue.ul_nof_ok); + fmt::print(" {:>4}", ue.ul_nof_nok); + + unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; + if (ul_total > 0) { + fmt::print(" {:>3}%", int((float)100 * ue.ul_nof_nok / ul_total)); + } else { + fmt::print(" {:>3}%", 0); + } + fmt::print(" {}", scaled_fmt_integer(ue.bsr, true)); + if (ue.last_ta.has_value()) { + fmt::print(" {}", float_to_eng_string(ue.last_ta->to_seconds(), 0, true)); + } else { + fmt::print(" n/a"); + } + if (ue.last_phr.has_value()) { + fmt::print(" {:>4}", ue.last_phr.value()); + } else { + fmt::print(" n/a"); + } + + fmt::print("\n"); + } +} + +/// Returns the current time in seconds with ms precision since UNIX epoch. +static double get_time_stamp() +{ + auto tp = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast(tp).count() * 1e-3; +} + +void scheduler_cell_metrics_consumer_json::handle_metric(const app_services::metrics_set& metric) +{ + const scheduler_cell_metrics& metrics = static_cast(metric).get_metrics(); + + metric_context_t ctx("JSON Metrics"); + + for (const auto& ue : metrics.ue_metrics) { + ctx.get().emplace_back(); + auto& output = ctx.get().back(); + + output.write(ue.pci); + output.write(to_value(ue.rnti)); + if (ue.cqi_stats.get_nof_observations() > 0) { + output.write(static_cast(std::roundf(ue.cqi_stats.get_mean()))); + } + if (ue.ri_stats.get_nof_observations() > 0) { + output.write(ue.ri_stats.get_mean()); + } + output.write(ue.dl_mcs.to_uint()); + output.write(ue.dl_brate_kbps * 1e3); + output.write(ue.dl_nof_ok); + output.write(ue.dl_nof_nok); + output.write(ue.dl_bs); + if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { + output.write(std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); + } + output.write(ue.ul_mcs.to_uint()); + output.write(ue.ul_brate_kbps * 1e3); + output.write(ue.ul_nof_ok); + output.write(ue.ul_nof_nok); + output.write(ue.bsr); + } + + auto& cell_output = ctx.get(); + cell_output.write(metrics.nof_error_indications); + cell_output.write(metrics.average_decision_latency.count()); + unsigned bin_idx = 0; + for (unsigned bin_count : metrics.latency_histogram) { + cell_output.get().emplace_back(); + auto& elem = cell_output.get().back(); + elem.write(bin_idx * scheduler_cell_metrics::nof_usec_per_bin); + elem.write(bin_count); + bin_idx++; + } + + // Log the context. + ctx.write(get_time_stamp()); + log_chan(ctx); +} + +void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metrics_set& metric) +{ + const scheduler_cell_metrics& metrics = static_cast(metric).get_metrics(); + + fmt::memory_buffer buffer; + + // log cell-wide metrics + fmt::format_to(buffer, "Cell Scheduler Metrics:"); + fmt::format_to(buffer, + " error_indications={} mean_latency={}usec latency_hist=[{}]", + metrics.nof_error_indications, + metrics.average_decision_latency.count(), + fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); + logger.info("{}", to_c_str(buffer)); + buffer.clear(); + + // log ue-specific metrics + for (const auto& ue : metrics.ue_metrics) { + fmt::format_to(buffer, "Scheduler UE Metrics:"); + fmt::format_to(buffer, " pci={}", ue.pci); + fmt::format_to(buffer, " rnti={:x}", to_value(ue.rnti)); + if (ue.cqi_stats.get_nof_observations() > 0) { + fmt::format_to(buffer, " cqi={}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); + } else { + fmt::format_to(buffer, " cqi=n/a"); + } + + if (ue.ri_stats.get_nof_observations() > 0) { + fmt::format_to(buffer, " ri={:.1f}", ue.ri_stats.get_mean()); + } else { + fmt::format_to(buffer, " ri=n/a"); + } + + fmt::format_to(buffer, " dl_mcs={}", int(ue.dl_mcs.to_uint())); + if (ue.dl_brate_kbps > 0) { + fmt::format_to(buffer, " dl_brate_kbps={}", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, false)); + } else { + fmt::format_to(buffer, " dl_brate_kbps={}", 0); + } + fmt::format_to(buffer, " dl_nof_ok={}", ue.dl_nof_ok); + fmt::format_to(buffer, " dl_nof_nok={}", ue.dl_nof_nok); + unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; + if (dl_total > 0) { + fmt::format_to(buffer, " dl_error_rate={}%", int((float)100 * ue.dl_nof_nok / dl_total)); + } else { + fmt::format_to(buffer, " dl_error_rate={}%", 0); + } + fmt::format_to(buffer, " dl_bs={}", scaled_fmt_integer(ue.dl_bs, false)); + + if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { + fmt::format_to(buffer, " pusch_snr_db={:.1f}", std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); + } else { + fmt::format_to(buffer, " pusch_snr_db=n/a"); + } + + if (!std::isinf(ue.pusch_rsrp_db) && !std::isnan(ue.pusch_rsrp_db)) { + if (ue.pusch_rsrp_db >= 0.0F) { + fmt::format_to(buffer, " pusch_rsrp_db=ovl"); + } else { + fmt::format_to(buffer, " pusch_rsrp_db={:.1f}", std::clamp(ue.pusch_rsrp_db, -99.9F, 0.0F)); + } + } else { + fmt::format_to(buffer, " pusch_rsrp_db=n/a"); + } + + fmt::format_to(buffer, " ul_mcs={}", ue.ul_mcs.to_uint()); + if (ue.ul_brate_kbps > 0) { + fmt::format_to(buffer, " ul_brate_kbps={}", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, false)); + } else { + fmt::format_to(buffer, " ul_brate_kbps={}", 0); + } + fmt::format_to(buffer, " ul_nof_ok={}", ue.ul_nof_ok); + fmt::format_to(buffer, " ul_nof_nok={}", ue.ul_nof_nok); + + unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; + if (ul_total > 0) { + fmt::format_to(buffer, " ul_error_rate={}%", int((float)100 * ue.ul_nof_nok / ul_total)); + } else { + fmt::format_to(buffer, " ul_error_rate={}%", 0); + } + fmt::format_to(buffer, " bsr={}", scaled_fmt_integer(ue.bsr, false)); + if (ue.last_ta.has_value()) { + fmt::format_to(buffer, " last_ta={}s", float_to_eng_string(ue.last_ta->to_seconds(), 0, false)); + } else { + fmt::format_to(buffer, " last_ta=n/a"); + } + if (ue.last_phr.has_value()) { + fmt::format_to(buffer, " last_phr={}", ue.last_phr.value()); + } else { + fmt::format_to(buffer, " last_phr=n/a"); + } + + logger.info("{}", to_c_str(buffer)); + buffer.clear(); + } +} + +void scheduler_cell_metrics_consumer_e2::handle_metric(const app_services::metrics_set& metric) +{ + notifier.report_metrics(static_cast(metric).get_metrics()); +} diff --git a/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.h b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.h new file mode 100644 index 0000000000..ab3eafd5a0 --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.h @@ -0,0 +1,76 @@ +/* + * + * 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/metrics/metrics_consumer.h" +#include "du_high_scheduler_cell_metrics.h" +#include "srsran/srslog/log_channel.h" +#include "srsran/srslog/logger.h" + +namespace srsran { + +/// Consumer for the STDOUT scheduler cell metrics. +class scheduler_cell_metrics_consumer_stdout : public app_services::metrics_consumer +{ +public: + explicit scheduler_cell_metrics_consumer_stdout(bool print_metrics_) : print_metrics(print_metrics_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + + /// This can be called from another execution context to turn on/off the actual plotting. + void toggle_print() { print_metrics = !print_metrics; } + +private: + unsigned nof_lines = 10; + std::atomic print_metrics = {false}; +}; + +/// Consumer for the json scheduler cell metrics. +class scheduler_cell_metrics_consumer_json : public app_services::metrics_consumer +{ +public: + explicit scheduler_cell_metrics_consumer_json(srslog::log_channel& log_chan_) : log_chan(log_chan_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + +private: + srslog::log_channel& log_chan; +}; + +/// Consumer for the log file scheduler cell metrics. +class scheduler_cell_metrics_consumer_log : public app_services::metrics_consumer +{ +public: + explicit scheduler_cell_metrics_consumer_log(srslog::basic_logger& logger_) : logger(logger_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + +private: + srslog::basic_logger& logger; +}; + +/// Consumer for the E2 file scheduler cell metrics. +class scheduler_cell_metrics_consumer_e2 : public app_services::metrics_consumer +{ +public: + explicit scheduler_cell_metrics_consumer_e2(scheduler_metrics_notifier& notifier_) : notifier(notifier_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override; + +private: + scheduler_metrics_notifier& notifier; +}; + +} // namespace srsran diff --git a/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp new file mode 100644 index 0000000000..acaa71cb4d --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp @@ -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. + * + */ + +#include "du_high_scheduler_cell_metrics_producer.h" +#include "du_high_scheduler_cell_metrics.h" +#include "srsran/support/executors/task_executor.h" + +using namespace srsran; + +void scheduler_metrics_producer_impl::report_metrics(const scheduler_cell_metrics& report) +{ + notifier.on_new_metric(scheduler_cell_metrics_impl(report)); +} + +app_services::metrics_callback scheduler_metrics_producer_impl::get_callback() +{ + return [&](const app_services::metrics_set& report, + span consumers, + task_executor& executor, + srslog::basic_logger& logger) { + const auto& metric = static_cast(report); + + // Fetch a metrics report object from the pool. + // Note: We are trying to reuse the pre-existing allocated memory in the cached_metrics object. + auto cached_metrics = metrics_pool.get(); + *cached_metrics = metric.get_metrics(); + if (!executor.defer([sched_metric = std::move(cached_metrics), consumers]() { + for (auto& consumer : consumers) { + consumer->handle_metric(scheduler_cell_metrics_impl(*sched_metric)); + } + })) { + logger.error("Failed to dispatch the metric '{}'", report.get_properties().name()); + } + }; +} \ No newline at end of file diff --git a/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.h b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.h new file mode 100644 index 0000000000..409cbbd06d --- /dev/null +++ b/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_producer.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/services/metrics/metrics_config.h" +#include "apps/services/metrics/metrics_notifier.h" +#include "apps/services/metrics/metrics_producer.h" +#include "srsran/scheduler/scheduler_metrics.h" +#include "srsran/support/memory_pool/unbounded_object_pool.h" + +namespace srsran { + +/// Scheduler metrics producer. +class scheduler_metrics_producer_impl : public scheduler_metrics_notifier, public app_services::metrics_producer +{ + static constexpr size_t METRIC_POOL_INITIAL_CAPACITY = 3; + +public: + explicit scheduler_metrics_producer_impl(app_services::metrics_notifier& notifier_) : + notifier(notifier_), metrics_pool(METRIC_POOL_INITIAL_CAPACITY) + { + } + + // See interface for documentation. + void report_metrics(const scheduler_cell_metrics& report) override; + + /// Callback for the scheduler cell metrics. + app_services::metrics_callback get_callback(); + +private: + app_services::metrics_notifier& notifier; + // We use the metrics pool to cache and avoid allocating memory for each report in a RT thread. + unbounded_object_pool metrics_pool; +}; + +} // namespace srsran 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 992d8a544e..3754e3f513 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp @@ -10,7 +10,6 @@ #include "dynamic_du_factory.h" #include "apps/services/e2_metric_connector_manager.h" -#include "apps/services/metrics_log_helper.h" #include "apps/units/flexible_du/du_high/du_high_commands.h" #include "apps/units/flexible_du/du_high/du_high_config_translators.h" #include "apps/units/flexible_du/du_high/du_high_wrapper_config_helper.h" @@ -104,20 +103,45 @@ create_radio_unit(const std::variant& flexible_du_cfg, + std::vector local_du_cfg, + bool is_e2_enabled) +{ + // Empty config, copy the local. + if (flexible_du_cfg.empty()) { + flexible_du_cfg = std::move(local_du_cfg); + } + + if (!is_e2_enabled) { + return; + } + + // When E2 is enabled grab the E2 consumers from the local DU and add them to the flexible DU. + srsran_assert(flexible_du_cfg.size() == local_du_cfg.size(), + "Flexible DU metrics size '{}' does not match DU metrics size '{}'", + flexible_du_cfg.size(), + local_du_cfg.size()); + for (unsigned i = 0, e = local_du_cfg.size(); i != e; ++i) { + flexible_du_cfg.push_back(std::move(local_du_cfg.back())); + } +} + +du_unit srsran::create_du(const dynamic_du_unit_config& dyn_du_cfg, + worker_manager& workers, + srs_du::f1c_connection_client& f1c_client_handler, + srs_du::f1u_du_gateway& f1u_gw, + timer_manager& timer_mng, + mac_pcap& mac_p, + rlc_pcap& rlc_p, + e2_connection_client& e2_client_handler, + e2_metric_connector_manager& e2_metric_connectors, + srslog::sink& json_sink, + app_services::metrics_notifier& metrics_notifier) { du_unit du_cmd_wrapper; @@ -125,10 +149,6 @@ du_unit srsran::create_du(const dynamic_du_unit_config& dyn_du_cfg, const du_low_unit_config& du_lo = dyn_du_cfg.du_low_cfg; const fapi_unit_config& fapi_cfg = dyn_du_cfg.fapi_cfg; - // Configure the application unit metrics for the DU high. - configure_du_high_metrics( - du_hi, metrics_stdout, metrics_logger, metrics_json, rlc_json_metrics, e2_metric_connectors, metrics_hub); - auto du_cells = generate_du_cell_config(du_hi); std::vector> du_insts; @@ -234,18 +254,27 @@ du_unit srsran::create_du(const dynamic_du_unit_config& dyn_du_cfg, workers, i); - fill_du_high_wrapper_config(du_cfg.du_high_cfg, - tmp_cfg, - i, - workers.get_du_high_executor_mapper(i), - f1c_client_handler, - f1u_gw, - timer_mng, - mac_p, - rlc_p, - e2_client_handler, - e2_metric_connectors, - metrics_hub); + auto cell_services_cfg = fill_du_high_wrapper_config(du_cfg.du_high_cfg, + tmp_cfg, + i, + workers.get_du_high_executor_mapper(i), + f1c_client_handler, + f1u_gw, + timer_mng, + mac_p, + rlc_p, + e2_client_handler, + e2_metric_connectors, + json_sink, + metrics_notifier); + + update_du_metrics(du_cmd_wrapper.metrics, std::move(cell_services_cfg.first), tmp_cfg.e2_cfg.enable_du_e2); + + // Use the commands of the first cell. + if (i == 0) { + for (auto& command : cell_services_cfg.second) + du_cmd_wrapper.commands.push_back(std::move(command)); + } // FAPI configuration. du_cfg.du_high_cfg.fapi.log_level = fapi_cfg.fapi_level; @@ -279,13 +308,13 @@ du_unit srsran::create_du(const dynamic_du_unit_config& dyn_du_cfg, du_cmd_wrapper.commands.push_back(std::make_unique(ru->get_controller())); du_cmd_wrapper.commands.push_back(std::make_unique(ru->get_controller())); - // Add DU command. - du_cmd_wrapper.commands.push_back(std::make_unique(metrics_stdout)); - du_impl->add_ru(std::move(ru)); du_impl->add_dus(std::move(du_insts)); du_cmd_wrapper.unit = std::move(du_impl); + // Configure the application unit metrics for the DU high. + announce_du_high_cells(du_hi); + return du_cmd_wrapper; } diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.h b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.h index 3b7628efa9..2460ba701b 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.h +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.h @@ -12,13 +12,17 @@ #include "apps/gnb/gnb_appconfig.h" #include "apps/services/application_command.h" -#include "apps/services/metrics_hub.h" +#include "apps/services/metrics/metrics_config.h" #include "apps/services/worker_manager.h" #include "srsran/du/du.h" #include "srsran/pcap/rlc_pcap.h" namespace srsran { +namespace app_services { +class metrics_notifier; +} + class e2_connection_client; class e2_metric_connector_manager; class f1ap_message_notifier; @@ -40,21 +44,19 @@ class f1u_du_gateway; struct du_unit { std::unique_ptr unit; std::vector> commands; + std::vector metrics; }; -du_unit create_du(const dynamic_du_unit_config& dyn_du_cfg, - worker_manager& workers, - srs_du::f1c_connection_client& f1c_client_handler, - srs_du::f1u_du_gateway& f1u_gw, - timer_manager& timer_mng, - mac_pcap& mac_p, - rlc_pcap& rlc_p, - metrics_plotter_stdout& metrics_stdout, - metrics_plotter_json& metrics_json, - metrics_log_helper& metrics_logger, - e2_connection_client& e2_client_handler, - e2_metric_connector_manager& e2_metric_connectors, - rlc_metrics_notifier& rlc_json_metrics, - metrics_hub& metrics_hub); +du_unit create_du(const dynamic_du_unit_config& dyn_du_cfg, + worker_manager& workers, + srs_du::f1c_connection_client& f1c_client_handler, + srs_du::f1u_du_gateway& f1u_gw, + timer_manager& timer_mng, + mac_pcap& mac_p, + rlc_pcap& rlc_p, + e2_connection_client& e2_client_handler, + e2_metric_connector_manager& e2_metric_connectors, + srslog::sink& json_sink, + app_services::metrics_notifier& metrics_notifier); } // namespace srsran diff --git a/tests/unittests/apps/CMakeLists.txt b/tests/unittests/apps/CMakeLists.txt index 6f0eba9e18..5d55538428 100644 --- a/tests/unittests/apps/CMakeLists.txt +++ b/tests/unittests/apps/CMakeLists.txt @@ -6,4 +6,4 @@ # the distribution. # -add_subdirectory(services) +add_subdirectory(units) diff --git a/tests/unittests/apps/services/CMakeLists.txt b/tests/unittests/apps/services/CMakeLists.txt deleted file mode 100644 index 69a8c36839..0000000000 --- a/tests/unittests/apps/services/CMakeLists.txt +++ /dev/null @@ -1,12 +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. -# - -add_executable(metrics_plotter_stdout_test metrics_plotter_stdout_test.cpp) -target_link_libraries(metrics_plotter_stdout_test srsran_support srsran_app_services) -add_test(metrics_plotter_stdout_test metrics_plotter_stdout_test) -include_directories(${CMAKE_SOURCE_DIR}/apps/gnb/helpers) diff --git a/tests/unittests/apps/units/CMakeLists.txt b/tests/unittests/apps/units/CMakeLists.txt new file mode 100644 index 0000000000..a591a7c697 --- /dev/null +++ b/tests/unittests/apps/units/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# 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_subdirectory(flexible_du) diff --git a/tests/unittests/apps/units/flexible_du/CMakeLists.txt b/tests/unittests/apps/units/flexible_du/CMakeLists.txt new file mode 100644 index 0000000000..03391139e2 --- /dev/null +++ b/tests/unittests/apps/units/flexible_du/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# 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_subdirectory(du_high) diff --git a/tests/unittests/apps/units/flexible_du/du_high/CMakeLists.txt b/tests/unittests/apps/units/flexible_du/du_high/CMakeLists.txt new file mode 100644 index 0000000000..acca12633b --- /dev/null +++ b/tests/unittests/apps/units/flexible_du/du_high/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# 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_subdirectory(metrics) diff --git a/tests/unittests/apps/units/flexible_du/du_high/metrics/CMakeLists.txt b/tests/unittests/apps/units/flexible_du/du_high/metrics/CMakeLists.txt new file mode 100644 index 0000000000..58646bb034 --- /dev/null +++ b/tests/unittests/apps/units/flexible_du/du_high/metrics/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# 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(du_high_scheduler_cell_metrics_consumer_stdout_test du_high_scheduler_cell_metrics_consumer_stdout_test.cpp) +target_link_libraries(du_high_scheduler_cell_metrics_consumer_stdout_test srsran_support srsran_du_high_unit_metrics_helpers srsran_app_services) +add_test(du_high_scheduler_cell_metrics_consumer_stdout_test du_high_scheduler_cell_metrics_consumer_stdout_test) +target_include_directories(du_high_scheduler_cell_metrics_consumer_stdout_test PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/tests/unittests/apps/services/metrics_plotter_stdout_test.cpp b/tests/unittests/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumer_stdout_test.cpp similarity index 83% rename from tests/unittests/apps/services/metrics_plotter_stdout_test.cpp rename to tests/unittests/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumer_stdout_test.cpp index 5c78470f6a..43c419f372 100644 --- a/tests/unittests/apps/services/metrics_plotter_stdout_test.cpp +++ b/tests/unittests/apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumer_stdout_test.cpp @@ -8,7 +8,7 @@ * */ -#include "../../../apps/services/metrics_plotter_stdout.h" +#include "apps/units/flexible_du/du_high/metrics/du_high_scheduler_cell_metrics_consumers.h" using namespace srsran; @@ -45,11 +45,11 @@ void fill_metrics_single_ue() int main() { - metrics_plotter_stdout plotter(true); + scheduler_cell_metrics_consumer_stdout plotter(true); fill_metrics_single_ue(); - plotter.report_metrics(reports); + plotter.handle_metric(scheduler_cell_metrics_impl(reports)); return 0; } From 75e38fe06d10ab87554e51cdf91f66d220c4f018 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 8 Aug 2024 19:14:26 +0200 Subject: [PATCH 146/407] flexible_du: fix the function that joins the metrics configuration of every DU --- .../split_dynamic/dynamic_du_factory.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) 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 3754e3f513..8d19295c9a 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp @@ -112,22 +112,27 @@ static void update_du_metrics(std::vector& flexibl std::vector local_du_cfg, bool is_e2_enabled) { - // Empty config, copy the local. + // First call, copy everything. if (flexible_du_cfg.empty()) { flexible_du_cfg = std::move(local_du_cfg); - } - - if (!is_e2_enabled) { return; } - // When E2 is enabled grab the E2 consumers from the local DU and add them to the flexible DU. + // Safe check that all the DUs provides the same amount of metrics. srsran_assert(flexible_du_cfg.size() == local_du_cfg.size(), "Flexible DU metrics size '{}' does not match DU metrics size '{}'", flexible_du_cfg.size(), local_du_cfg.size()); + + // Iterate the metrics configs of each DU. Each DU should ha for (unsigned i = 0, e = local_du_cfg.size(); i != e; ++i) { - flexible_du_cfg.push_back(std::move(local_du_cfg.back())); + // Store the metrics producers for each DU. + flexible_du_cfg[i].producers.push_back(std::move(local_du_cfg[i].producers.back())); + + // Move E2 consumers for each DU to the common output config. E2 Consumers occupy the last position. + if (is_e2_enabled) { + flexible_du_cfg[i].consumers.push_back(std::move(local_du_cfg[i].consumers.back())); + } } } From 70082268eea02b20390d89a825f2f14211b7454e Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 8 Aug 2024 10:21:17 +0200 Subject: [PATCH 147/407] ci: remove n300 tests, and build tag --- .gitlab/ci/build.yml | 1 - .gitlab/ci/e2e.yml | 14 -------------- .gitlab/ci/e2e/.env | 2 +- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index d129edf1c6..c6f30c3454 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -26,7 +26,6 @@ variables: - amd64-avx2-avx512 - arm64 - on-prem-amd64 - - on-prem-amd64-avx2-avx512 - on-prem-arm64 - aws-spot-amd64 - aws-spot-arm64 diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 6b6acd3782..1a90be93b4 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -23,7 +23,6 @@ variables: - "rf_b200" - "rf_hp" - "android_b200" - - "android_n300" - "android_x300" - "viavi" - "none" @@ -574,13 +573,6 @@ validate b200 config: variables: MARKERS: "rf_b200" -validate n300 config: - extends: .rf - variables: - MARKERS: "rf_n300" - TESTBED: "android_n300" - allow_failure: true - ################################################################################ # Android ############################################################################### @@ -613,12 +605,6 @@ android x300: artifacts: true - *retina-needs -android n300: - extends: android x300 - variables: - TESTBED: "android_n300" - allow_failure: true - ################################################################################ # VIAVI ############################################################################### diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 07f8b90df0..a2d6eaa82c 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -9,6 +9,6 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.3 DPDK_VERSION=23.11 ZMQ_HOSTLABEL_0=kubernetes.io/hostname=k8s-worker-vm2 -ZMQ_HOSTLABEL_1=kubernetes.io/hostname=srskit +ZMQ_HOSTLABEL_1=kubernetes.io/hostname=skinny-beast AMARISOFT_TXRX_BINARY_PATH=../../build_trx_srsran/libtrx_srsran.so GNB_BINARY_PATH=../../build/apps/gnb/gnb From dff9a29308bb6060c8211195a0ae9f2f9c4255b0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 2 Aug 2024 18:53:42 +0200 Subject: [PATCH 148/407] phy: experimental bg_hr_parity_nodes phy: optimize systematic_bits_inner phy: LDPC encoder, zero output node phy: more efficient rotation and XOR in LDPC encoder AVX2 phy: extent LDPC encoder optimization to NEON phy: optimize LDPC decoder generic --- .../channel_coding/ldpc/ldpc_encoder_avx2.cpp | 91 ++++++++++-------- .../channel_coding/ldpc/ldpc_encoder_avx2.h | 2 +- .../ldpc/ldpc_encoder_generic.cpp | 92 +++++++++++++------ .../channel_coding/ldpc/ldpc_encoder_neon.cpp | 90 ++++++++++-------- .../channel_coding/ldpc/ldpc_graph_impl.cpp | 8 -- .../channel_coding/ldpc/ldpc_graph_impl.h | 7 -- 6 files changed, 175 insertions(+), 115 deletions(-) diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp index 5ff5815e49..ec4289d233 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp @@ -119,7 +119,7 @@ void ldpc_encoder_avx2::load_input(const bit_buffer& in) codeblock_used_size = codeblock_length / lifting_size * node_size_avx2; length_extended = (codeblock_length / lifting_size - bg_K) * node_size_avx2; - span codeblock(codeblock_buffer.data(), codeblock_used_size * AVX2_SIZE_BYTE); + span codeblock = span(codeblock_buffer).first((bg_K + bg_hr_parity_nodes) * node_size_byte); // Unpack the input bits into the CB buffer. for (unsigned i_node = 0; i_node != bg_K; ++i_node) { srsvec::bit_unpack(codeblock.first(lifting_size), in, i_node * lifting_size); @@ -181,47 +181,35 @@ void ldpc_encoder_avx2::systematic_bits_inner() mm256::avx2_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_AVX2_PH); - const auto& parity_check_sparse = current_graph->get_parity_check_sparse(); - std::array tmp_blk; - span blk = span(tmp_blk).first(2 * lifting_size); - unsigned current_i_blk = std::numeric_limits::max(); + span blk = span(tmp_blk).first(2 * lifting_size); - std::array m_mask; - m_mask.fill(false); + for (unsigned m = 0; m != bg_hr_parity_nodes; ++m) { + const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); - for (const auto& element : parity_check_sparse) { - unsigned m = std::get<0>(element); - unsigned k = std::get<1>(element); - unsigned node_shift = std::get<2>(element); + for (uint16_t k : row) { + if ((k >= bg_K) || (k == NO_EDGE)) { + break; + } - unsigned i_aux = m * NODE_SIZE_AVX2_PH; - unsigned i_blk = k * NODE_SIZE_AVX2_PH; + unsigned node_shift = current_graph->get_lifted_node(m, k); + if (node_shift == NO_EDGE) { + break; + } - if (i_aux >= length_extended) { - continue; - } + unsigned i_aux = m * NODE_SIZE_AVX2_PH; + unsigned i_blk = k * NODE_SIZE_AVX2_PH; - if (i_blk != current_i_blk) { - current_i_blk = i_blk; - srsvec::copy(blk.first(lifting_size), codeblock.plain_span(current_i_blk, lifting_size)); - srsvec::copy(blk.last(lifting_size), codeblock.plain_span(current_i_blk, lifting_size)); - } + srsvec::copy(blk.first(lifting_size), codeblock.plain_span(i_blk, lifting_size)); + srsvec::copy(blk.last(lifting_size), codeblock.plain_span(i_blk, lifting_size)); - auto set_plain_auxiliary = [this, auxiliary, m, i_aux]() { - if (m < bg_hr_parity_nodes) { - return auxiliary.plain_span(i_aux, lifting_size); - } - unsigned offset = (bg_K + m) * NODE_SIZE_AVX2_PH * AVX2_SIZE_BYTE; - return span(reinterpret_cast(codeblock_buffer.data()) + offset, lifting_size); - }; - span plain_auxiliary = set_plain_auxiliary(); + span plain_auxiliary = auxiliary.plain_span(i_aux, lifting_size); - if (m_mask[m]) { - fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); - } else { - srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); - m_mask[m] = true; + if (k == row[0]) { + srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); + } else { + fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); + } } } } @@ -384,9 +372,40 @@ void ldpc_encoder_avx2::ext_region_inner(span out_node, unsigned m) con unsigned node_size_byte = node_size_avx2 * AVX2_SIZE_BYTE; span codeblock(codeblock_buffer); - // Copy the current data in the node. - srsvec::copy(out_node, codeblock.subspan((bg_K + m) * node_size_byte, lifting_size)); + // Get the adjacency row for the node m. + const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); + + // Zero node. + srsvec::zero(out_node); + + // Process each of the nodes. + for (uint16_t k : row) { + // Check if the node is in codeblock range. + if ((k >= bg_K) || (k == NO_EDGE)) { + break; + } + + // Obtain the node cyclic shift. + unsigned node_shift = current_graph->get_lifted_node(m, k); + if (node_shift == NO_EDGE) { + break; + } + + // Get the view of the codeblock node. + span codeblock_node = codeblock.subspan(k * node_size_byte, lifting_size); + + // The first time is copied and after-wards combined. + if (k == row[0]) { + srsvec::circ_shift_backward(out_node, codeblock_node, node_shift); + } else { + fast_xor(out_node.first(lifting_size - node_shift), + out_node.first(lifting_size - node_shift), + codeblock_node.last(lifting_size - node_shift)); + fast_xor(out_node.last(node_shift), out_node.last(node_shift), codeblock_node.first(node_shift)); + } + } + // Process extended region. for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h index 354c133cba..03713aa044 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.h @@ -69,7 +69,7 @@ class ldpc_encoder_avx2 : public ldpc_encoder_impl /// \tparam NODE_SIZE_AVX2_PH Placeholder for the number of AVX2 registers used to represent a code node. template void high_rate_bg2_other_inner(); - /// Carries out the extended region encoding when the lifting size is long. + /// Carries out the extended region encoding when the lifting size is large. void ext_region_inner(span output_node, unsigned i_layer) const; /// Buffer containing the codeblock. diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp index f7cb981c35..d48b1c11d8 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp @@ -10,6 +10,7 @@ #include "ldpc_encoder_generic.h" #include "srsran/srsvec/binary.h" +#include "srsran/srsvec/circ_shift.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/zero.h" @@ -53,34 +54,41 @@ void ldpc_encoder_generic::preprocess_systematic_bits() // Initialize the rest to zero. srsvec::zero(span(codeblock.data() + message.size(), codeblock_length - message.size())); - const auto& parity_check_sparse = current_graph->get_parity_check_sparse(); + for (unsigned m = 0; m != bg_hr_parity_nodes; ++m) { + const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); - for (const auto& element : parity_check_sparse) { - unsigned m = std::get<0>(element); - unsigned k = std::get<1>(element); - unsigned node_shift = std::get<2>(element); - - span message_chunk = message.subspan(static_cast(k * lifting_size), lifting_size); + for (uint16_t k : row) { + if ((k >= bg_K) || (k == NO_EDGE)) { + break; + } - // Rotate node. Equivalent to: - // for (uint16_t l = 0; l != lifting_size; ++l) { - // uint16_t shifted_index = (node_shift + l) % lifting_size; - // auxiliary[m][l] ^= message_chunk[shifted_index]; - // } - auto set_auxiliary_chunk = [this, m]() { - if (m < bg_hr_parity_nodes) { - return span(auxiliary[m].data(), lifting_size); + unsigned node_shift = current_graph->get_lifted_node(m, k); + if (node_shift == NO_EDGE) { + break; } - unsigned offset = (bg_K + m) * lifting_size; - return span(codeblock.data() + offset, lifting_size); - }; - span auxiliary_chunk = set_auxiliary_chunk(); - - srsvec::binary_xor(auxiliary_chunk.first(lifting_size - node_shift), - message_chunk.last(lifting_size - node_shift), - auxiliary_chunk.first(lifting_size - node_shift)); - srsvec::binary_xor( - auxiliary_chunk.last(node_shift), message_chunk.first(node_shift), auxiliary_chunk.last(node_shift)); + + span message_chunk = message.subspan(static_cast(k * lifting_size), lifting_size); + + // Rotate node. Equivalent to: + // for (uint16_t l = 0; l != lifting_size; ++l) { + // uint16_t shifted_index = (node_shift + l) % lifting_size; + // auxiliary[m][l] ^= message_chunk[shifted_index]; + // } + auto set_auxiliary_chunk = [this, m]() { + if (m < bg_hr_parity_nodes) { + return span(auxiliary[m].data(), lifting_size); + } + unsigned offset = (bg_K + m) * lifting_size; + return span(codeblock.data() + offset, lifting_size); + }; + span auxiliary_chunk = set_auxiliary_chunk(); + + srsvec::binary_xor(auxiliary_chunk.first(lifting_size - node_shift), + message_chunk.last(lifting_size - node_shift), + auxiliary_chunk.first(lifting_size - node_shift)); + srsvec::binary_xor( + auxiliary_chunk.last(node_shift), message_chunk.first(node_shift), auxiliary_chunk.last(node_shift)); + } } } @@ -88,8 +96,38 @@ void ldpc_encoder_generic::ext_region_inner(span out_node, unsigned m) { span codeblock_view(codeblock); - // Copy the current data in the node. - srsvec::copy(out_node, codeblock_view.subspan((bg_K + m) * lifting_size, lifting_size)); + // Get the adjacency row for the node m. + const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); + + // Zero node. + srsvec::zero(out_node); + + // Process each of the nodes. + for (uint16_t k : row) { + // Check if the node is in codeblock range. + if ((k >= bg_K) || (k == NO_EDGE)) { + break; + } + + // Obtain the node cyclic shift. + unsigned node_shift = current_graph->get_lifted_node(m, k); + if (node_shift == NO_EDGE) { + break; + } + + // Get the view of the codeblock node. + span codeblock_node = codeblock_view.subspan(k * lifting_size, lifting_size); + + // The first time is copied and after-wards combined. + if (k == row[0]) { + srsvec::circ_shift_backward(out_node, codeblock_node, node_shift); + } else { + srsvec::binary_xor(out_node.first(lifting_size - node_shift), + codeblock_node.last(lifting_size - node_shift), + out_node.first(lifting_size - node_shift)); + srsvec::binary_xor(out_node.last(node_shift), codeblock_node.first(node_shift), out_node.last(node_shift)); + } + } for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp index b7c0812ac1..17c195dad6 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp @@ -119,7 +119,7 @@ void ldpc_encoder_neon::load_input(const bit_buffer& in) codeblock_used_size = codeblock_length / lifting_size * node_size_neon; length_extended = (codeblock_length / lifting_size - bg_K) * node_size_neon; - span codeblock(codeblock_buffer.data(), codeblock_used_size * NEON_SIZE_BYTE); + span codeblock = span(codeblock_buffer).first((bg_K + bg_hr_parity_nodes) * node_size_byte); for (unsigned i_node = 0; i_node != bg_K; ++i_node) { srsvec::bit_unpack(codeblock.first(lifting_size), in, i_node * lifting_size); codeblock = codeblock.last(codeblock.size() - lifting_size); @@ -158,47 +158,35 @@ void ldpc_encoder_neon::systematic_bits_inner() neon::neon_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_NEON_PH); - const auto& parity_check_sparse = current_graph->get_parity_check_sparse(); - std::array tmp_blk; - span blk = span(tmp_blk).first(2 * lifting_size); - unsigned current_i_blk = std::numeric_limits::max(); + span blk = span(tmp_blk).first(2 * lifting_size); - std::array m_mask; - m_mask.fill(false); + for (unsigned m = 0; m != bg_hr_parity_nodes; ++m) { + const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); - for (const auto& element : parity_check_sparse) { - unsigned m = std::get<0>(element); - unsigned k = std::get<1>(element); - unsigned node_shift = std::get<2>(element); + for (uint16_t k : row) { + if ((k >= bg_K) || (k == NO_EDGE)) { + break; + } - unsigned i_aux = m * NODE_SIZE_NEON_PH; - unsigned i_blk = k * NODE_SIZE_NEON_PH; + unsigned node_shift = current_graph->get_lifted_node(m, k); + if (node_shift == NO_EDGE) { + break; + } - if (i_aux >= length_extended) { - continue; - } + unsigned i_aux = m * NODE_SIZE_NEON_PH; + unsigned i_blk = k * NODE_SIZE_NEON_PH; - if (i_blk != current_i_blk) { - current_i_blk = i_blk; - srsvec::copy(blk.first(lifting_size), codeblock.plain_span(current_i_blk, lifting_size)); - srsvec::copy(blk.last(lifting_size), codeblock.plain_span(current_i_blk, lifting_size)); - } + srsvec::copy(blk.first(lifting_size), codeblock.plain_span(i_blk, lifting_size)); + srsvec::copy(blk.last(lifting_size), codeblock.plain_span(i_blk, lifting_size)); - auto set_plain_auxiliary = [this, auxiliary, m, i_aux]() { - if (m < bg_hr_parity_nodes) { - return auxiliary.plain_span(i_aux, lifting_size); - } - unsigned offset = (bg_K + m) * NODE_SIZE_NEON_PH * NEON_SIZE_BYTE; - return span(reinterpret_cast(codeblock_buffer.data()) + offset, lifting_size); - }; - span plain_auxiliary = set_plain_auxiliary(); + span plain_auxiliary = auxiliary.plain_span(i_aux, lifting_size); - if (m_mask[m]) { - fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); - } else { - srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); - m_mask[m] = true; + if (k == row[0]) { + srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); + } else { + fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); + } } } } @@ -361,8 +349,38 @@ void ldpc_encoder_neon::ext_region_inner(span out_node, unsigned m) con unsigned node_size_byte = node_size_neon * NEON_SIZE_BYTE; span codeblock(codeblock_buffer); - // Copy the current data in the node. - srsvec::copy(out_node, codeblock.subspan((bg_K + m) * node_size_byte, lifting_size)); + // Get the adjacency row for the node m. + const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); + + // Zero node. + srsvec::zero(out_node); + + // Process each of the nodes. + for (uint16_t k : row) { + // Check if the node is in codeblock range. + if ((k >= bg_K) || (k == NO_EDGE)) { + break; + } + + // Obtain the node cyclic shift. + unsigned node_shift = current_graph->get_lifted_node(m, k); + if (node_shift == NO_EDGE) { + break; + } + + // Get the view of the codeblock node. + span codeblock_node = codeblock.subspan(k * node_size_byte, lifting_size); + + // The first time is copied and after-wards combined. + if (k == row[0]) { + srsvec::circ_shift_backward(out_node, codeblock_node, node_shift); + } else { + fast_xor(out_node.first(lifting_size - node_shift), + out_node.first(lifting_size - node_shift), + codeblock_node.last(lifting_size - node_shift)); + fast_xor(out_node.last(node_shift), out_node.last(node_shift), codeblock_node.first(node_shift)); + } + } for (unsigned k = 0; k != bg_hr_parity_nodes; ++k) { unsigned node_shift = current_graph->get_lifted_node(m, bg_K + k); diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.cpp index d6e94b19f8..e0b1312e4c 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.cpp @@ -30,14 +30,6 @@ ldpc_graph_impl::ldpc_graph_impl(ldpc_base_graph_type _bg, ldpc::lifting_size_t nof_BG_var_nodes_full = BG2_N_FULL; nof_BG_var_nodes_short = BG2_N_SHORT; } - - for (unsigned k = 0, k_end = nof_BG_var_nodes_full - nof_BG_check_nodes; k != k_end; ++k) { - for (unsigned m = 0; m != nof_BG_check_nodes; ++m) { - if (parity_check_matrix[m][k] != NO_EDGE) { - parity_check_sparse.push_back({m, k, parity_check_matrix[m][k]}); - } - } - } } std::array srsran::ldpc::create_graph_array() diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.h index b7d41dfed9..2bb73ff35a 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_graph_impl.h @@ -125,11 +125,6 @@ class ldpc_graph_impl /// Returns a reference to the selected row of ldpc_graph_impl::adjacency_matrix. const ldpc::BG_adjacency_row_t& get_adjacency_row(unsigned m) const { return (*adjacency_matrix)[m]; } - const std::vector>& get_parity_check_sparse() const - { - return parity_check_sparse; - } - private: /// Base graph. ldpc_base_graph_type base_graph; @@ -147,8 +142,6 @@ class ldpc_graph_impl /// Parity check matrix of the graph (BG representation). ldpc::BG_matrix_t parity_check_matrix; - std::vector> parity_check_sparse; - /// Adjacency matrix of the base graph (sparse representation). const ldpc::BG_adjacency_matrix_t* adjacency_matrix; }; From e9d06715578843bedd050e34104b565136e693ff Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 6 Aug 2024 10:55:14 +0200 Subject: [PATCH 149/407] phy: review LDPC encoder doc --- lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp | 2 +- lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp | 2 +- lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h | 2 +- lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp | 2 +- lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp index ec4289d233..42fb7e351d 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp @@ -394,7 +394,7 @@ void ldpc_encoder_avx2::ext_region_inner(span out_node, unsigned m) con // Get the view of the codeblock node. span codeblock_node = codeblock.subspan(k * node_size_byte, lifting_size); - // The first time is copied and after-wards combined. + // The first time, the node is copied; afterwards combined. if (k == row[0]) { srsvec::circ_shift_backward(out_node, codeblock_node, node_shift); } else { diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp index d48b1c11d8..30f13dc9e1 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.cpp @@ -118,7 +118,7 @@ void ldpc_encoder_generic::ext_region_inner(span out_node, unsigned m) // Get the view of the codeblock node. span codeblock_node = codeblock_view.subspan(k * lifting_size, lifting_size); - // The first time is copied and after-wards combined. + // The first time, the node is copied; afterwards combined. if (k == row[0]) { srsvec::circ_shift_backward(out_node, codeblock_node, node_shift); } else { diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h index e9e62e8c86..957c60bd44 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_generic.h @@ -46,7 +46,7 @@ class ldpc_encoder_generic : public ldpc_encoder_impl void high_rate_bg2_i3_7(); /// Carries out the high-rate region encoding for BG2 and lifting size index in {0, 1, 2, 4, 5, 6}. void high_rate_bg2_other(); - /// Carries out the extended region encoding when the lifting size is long. + /// Carries out the extended region encoding when the lifting size is large. void ext_region_inner(span output_node, unsigned i_layer) const; /// Unpacked local copy of the message to encode. diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp index 17c195dad6..a6a92ec0df 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp @@ -371,7 +371,7 @@ void ldpc_encoder_neon::ext_region_inner(span out_node, unsigned m) con // Get the view of the codeblock node. span codeblock_node = codeblock.subspan(k * node_size_byte, lifting_size); - // The first time is copied and after-wards combined. + // The first time, the node is copied; afterwards combined. if (k == row[0]) { srsvec::circ_shift_backward(out_node, codeblock_node, node_shift); } else { diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h index 6abe2e3e2c..76f3d04c72 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.h @@ -69,7 +69,7 @@ class ldpc_encoder_neon : public ldpc_encoder_impl /// \tparam NODE_SIZE_NEON_PH Placeholder for the number of NEON registers used to represent a code node. template void high_rate_bg2_other_inner(); - /// Carries out the extended region encoding when the lifting size is long. + /// Carries out the extended region encoding when the lifting size is large. void ext_region_inner(span output_node, unsigned i_layer) const; /// Buffer containing the codeblock. From e7eb4424ba0b0bfbc0fb37f59f65ae78d6aa0e85 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 1 Aug 2024 15:52:57 +0200 Subject: [PATCH 150/407] sched: create a default SRB slice with high priority and default DRB slice --- lib/scheduler/slicing/slice_scheduler.cpp | 34 +++-- lib/scheduler/slicing/slice_scheduler.h | 7 +- .../slicing/slice_scheduler_test.cpp | 144 +++++++++++------- 3 files changed, 119 insertions(+), 66 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 1563487654..11bf383349 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -17,15 +17,21 @@ using namespace srsran; slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, const ue_repository& ues_) : cell_cfg(cell_cfg_), logger(srslog::fetch_basic_logger("SCHED")), ues(ues_) { - // Create a number of slices equal to the number of configured RRM Policy members + 1 (default slice). - slices.reserve(cell_cfg.rrm_policy_members.size() + 1); + // Create a number of slices equal to the number of configured RRM Policy members + 1 (default SRB slice) + 1 (default + // DRB slice). + slices.reserve(cell_cfg.rrm_policy_members.size() + 2); // Create RAN slice instances. - ran_slice_id_t id_count{0}; - // Default slice. - slices.emplace_back(id_count, cell_cfg, slice_rrm_policy_config{}); + // Default SRB slice. + // NOTE: We set \c min_prb for default SRB slice to maximum nof. PRBs of a UE carrier to give maximum priority to this + // slice. + slices.emplace_back(default_srb_ran_slice_id, cell_cfg, slice_rrm_policy_config{.min_prb = MAX_NOF_PRBS}); slices.back().policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); - ++id_count; + // Default DRB slice. + slices.emplace_back(default_drb_ran_slice_id, cell_cfg, slice_rrm_policy_config{}); + slices.back().policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); + // NOTE: RAN slice IDs 0 and 1 are reserved for default SRB and default DRB slice respectively. + ran_slice_id_t id_count{2}; // Configured RRM policy members. for (const slice_rrm_policy_config& rrm : cell_cfg.rrm_policy_members) { slices.emplace_back(id_count, cell_cfg, rrm); @@ -56,7 +62,7 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); + ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); if (ues.contains(ue_cfg.ue_index)) { sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid); } @@ -67,13 +73,13 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co { // Remove old bearers. for (const logical_channel_config& lc_cfg : prev_ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); + ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); sl_inst.rem_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid); } // Add new bearers. for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); + ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); if (ues.contains(next_ue_cfg.ue_index)) { sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid); } @@ -87,14 +93,18 @@ void slice_scheduler::rem_ue(du_ue_index_t ue_idx) } } -ran_slice_instance& slice_scheduler::get_slice(const rrm_policy_member& rrm) +ran_slice_instance& slice_scheduler::get_slice(const rrm_policy_member& rrm, const logical_channel_config& lc_cfg) { auto it = std::find_if(slices.begin(), slices.end(), [&rrm](const ran_slice_sched_context& slice) { return slice.inst.cfg.rrc_member == rrm; }); if (it == slices.end()) { - // Slice with the provided RRM policy member was not found. Return default slice. - return slices.front().inst; + // Slice with the provided RRM policy member was not found. If logicall channel is a SRB then return default SRB + // slice. Else, return default DRB slice. + if (lc_cfg.lcid < LCID_MIN_DRB) { + return slices[default_srb_ran_slice_id.value()].inst; + } + return slices[default_drb_ran_slice_id.value()].inst; } return it->inst; } diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index 235e439ad0..9cd28d991b 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -46,6 +46,11 @@ class slice_scheduler scheduler_policy& get_policy(ran_slice_id_t id) { return *slices[id.value()].policy; } private: + /// RAN slice ID for default slice used to schedule SRB(s) traffic. + const ran_slice_id_t default_srb_ran_slice_id = ran_slice_id_t{0}; + /// RAN slice ID for default slice used to schedule DRB(s) traffic. + const ran_slice_id_t default_drb_ran_slice_id = ran_slice_id_t{1}; + /// Class responsible for tracking the scheduling context of each RAN slice instance. struct ran_slice_sched_context { ran_slice_instance inst; @@ -101,7 +106,7 @@ class slice_scheduler } }; - ran_slice_instance& get_slice(const rrm_policy_member& rrm); + ran_slice_instance& get_slice(const rrm_policy_member& rrm, const logical_channel_config& lc_cfg); template std::optional> get_next_candidate(); diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 5e1568dc0c..6a332c5399 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -74,11 +74,13 @@ class default_slice_scheduler_test : public slice_scheduler_test, public ::testi } }; -TEST_F(default_slice_scheduler_test, if_no_rrm_policy_cfg_exists_then_only_default_slice_is_created) +TEST_F(default_slice_scheduler_test, if_no_rrm_policy_cfg_exists_then_only_default_slices_are_created) { - ASSERT_EQ(slice_sched.nof_slices(), 1); - ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{0}).min_prb, 0); + ASSERT_EQ(slice_sched.nof_slices(), 2); + ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{0}).min_prb, MAX_NOF_PRBS); ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{0}).max_prb, MAX_NOF_PRBS); + ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{1}).min_prb, 0); + ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{1}).max_prb, MAX_NOF_PRBS); } TEST_F(default_slice_scheduler_test, when_no_lcid_exists_then_default_slice_is_not_a_candidate) @@ -159,17 +161,30 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test constexpr static unsigned MIN_SLICE_RB = 10; constexpr static unsigned MAX_SLICE_RB = 20; - rb_ratio_slice_scheduler_test() : slice_scheduler_test({{{"00101", s_nssai_t{1}}, MIN_SLICE_RB, MAX_SLICE_RB}}) {} + constexpr static ran_slice_id_t default_srb_slice_id{0}; + constexpr static ran_slice_id_t default_drb_slice_id{1}; + constexpr static ran_slice_id_t drb1_slice_id{2}; - const ue_configuration* add_ue(du_ue_index_t ue_idx) + rb_ratio_slice_scheduler_test() : + slice_scheduler_test( + {{{"00101", s_nssai_t{1}}, MIN_SLICE_RB, MAX_SLICE_RB}, {{"00101", s_nssai_t{2}}, MIN_SLICE_RB, MAX_SLICE_RB}}) { - const unsigned drb1_idx = 2; - auto req = test_cfg.get_default_ue_config_request(); - req.ue_index = ue_idx; - req.crnti = to_rnti(0x4601 + ue_idx); - req.starts_in_fallback = false; - (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.plmn_id = "00101"; - (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.s_nssai = s_nssai_t{1}; + } + + const ue_configuration* add_ue(du_ue_index_t ue_idx, + const std::initializer_list& lc_cfgs = {}) + { + const unsigned drb1_idx = 2; + auto req = test_cfg.get_default_ue_config_request(); + req.ue_index = ue_idx; + req.crnti = to_rnti(0x4601 + ue_idx); + req.starts_in_fallback = false; + if (lc_cfgs.size() == 0) { + (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.plmn_id = "00101"; + (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.s_nssai = s_nssai_t{1}; + } else { + *req.cfg.lc_config_list = lc_cfgs; + } return slice_scheduler_test::add_ue(req); } }; @@ -179,8 +194,12 @@ TEST_F(rb_ratio_slice_scheduler_test, when_slice_with_min_rb_has_ues_then_it_is_ ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); slice_sched.slot_indication(); + // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); + 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_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_MIN_DRB)); } @@ -189,8 +208,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); slice_sched.slot_indication(); + // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); + 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); } @@ -201,14 +224,14 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); slice_sched.slot_indication(); + // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); - 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); + ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); - // Another slice should be selected as second candidate. next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); + 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(); @@ -221,27 +244,19 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); slice_sched.slot_indication(); + // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); + 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); ASSERT_EQ(next_dl_slice->remaining_rbs(), 0); - // Another slice should be selected as second candidate (assuming RR between the slices 0 and 1). - ran_slice_id_t last_slice_id{}; - for (unsigned i = 0; i != 2; ++i) { - next_dl_slice = slice_sched.get_next_dl_candidate(); - if (i == 1) { - ASSERT_NE(next_dl_slice->id(), last_slice_id) << "The same slice was selected twice."; - } - if (next_dl_slice->id() == ran_slice_id_t{0}) { - ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_NOF_PRBS); - } else { - // Original slice is selected again, now using maxRB ratio as the remaining RBs. - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); - ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_SLICE_RB - MIN_SLICE_RB); - } - last_slice_id = next_dl_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); // No more slices to schedule. next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -254,7 +269,11 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); slice_sched.slot_indication(); + // 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(); next_dl_slice->store_grant(MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -263,14 +282,16 @@ TEST_F(rb_ratio_slice_scheduler_test, // New slot and priorities are reestablished. slice_sched.slot_indication(); + // Default SRB slice has very high priority. + 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(), ran_slice_id_t{1}); + 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(); - ran_slice_id_t last_slice_id = next_dl_slice->id(); - next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_NE(next_dl_slice->id(), last_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(); ASSERT_FALSE(next_dl_slice.has_value()); } @@ -278,28 +299,45 @@ TEST_F(rb_ratio_slice_scheduler_test, TEST_F(rb_ratio_slice_scheduler_test, when_slices_are_saturated_then_slices_should_have_equal_opportunity_to_reach_max_rbs) { - ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); + constexpr static ran_slice_id_t drb2_slice_id{3}; + + std::initializer_list lc_cfgs = { + config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB0), + config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB1), + config_helpers::create_default_logical_channel_config(lcid_t::LCID_MIN_DRB), + config_helpers::create_default_logical_channel_config(uint_to_lcid(lcid_t::LCID_MIN_DRB + 1))}; + ASSERT_NE(this->add_ue(to_du_ue_index(0), lc_cfgs), nullptr); unsigned max_nof_slots = 100; - unsigned slice_0_count = 0; + unsigned slice_3_count = 0; + unsigned slice_2_count = 0; for (unsigned count = 0; count != max_nof_slots; ++count) { slice_sched.slot_indication(); - // Slice 1 with minRBs to fill is first selected. + // Either default SRB slice (Slice 0) or DRB1 slice (Slice 2) or DRB2 slice (Slice 3) is selected first since both + // have minRBs > 0. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); - next_dl_slice->store_grant(MIN_SLICE_RB); + if (not next_dl_slice.has_value()) { + continue; + } + if (next_dl_slice->id() == drb1_slice_id or next_dl_slice->id() == drb2_slice_id) { + next_dl_slice->store_grant(MIN_SLICE_RB); + } else { + ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); + } - // Either Slice 0 or 1 are then selected. + // Either Slice 0 or 2 or 3 are then selected. next_dl_slice = slice_sched.get_next_dl_candidate(); - if (next_dl_slice->id() == ran_slice_id_t{0}) { - ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_NOF_PRBS); - slice_0_count++; - } else { - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); + if (next_dl_slice->id() == drb1_slice_id) { + slice_2_count++; + ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); + ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_SLICE_RB - MIN_SLICE_RB); + } else if (next_dl_slice->id() == drb2_slice_id) { + slice_3_count++; + ASSERT_EQ(next_dl_slice->id(), drb2_slice_id); ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_SLICE_RB - MIN_SLICE_RB); } } - ASSERT_EQ(slice_0_count, max_nof_slots / 2) << "Round-robin of slices of same priority failed"; + ASSERT_EQ(slice_3_count, slice_2_count) << "Round-robin of slices of same priority failed"; } From 951d47b40fd8e38ff1322f2e93f58b09bbf9ebe3 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 2 Aug 2024 09:47:20 +0200 Subject: [PATCH 151/407] sched: keep lookup of LCIDs to LCG IDs belonging to a slice --- lib/scheduler/slicing/ran_slice_instance.cpp | 4 ++-- lib/scheduler/slicing/ran_slice_instance.h | 2 +- lib/scheduler/slicing/slice_scheduler.cpp | 4 ++-- lib/scheduler/slicing/slice_ue_repository.cpp | 4 +++- lib/scheduler/slicing/slice_ue_repository.h | 7 ++++--- tests/unittests/scheduler/policy/scheduler_policy_test.cpp | 2 +- .../scheduler/ue_scheduling/ue_grid_allocator_test.cpp | 2 +- 7 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index c002ac59f7..4c9be1bca7 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -54,10 +54,10 @@ const slice_ue_repository& ran_slice_instance::get_ues() return slice_ues; } -void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid) +void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id) { if (not slice_ues.contains(u.ue_index)) { slice_ues.emplace(u.ue_index, u); } - slice_ues[u.ue_index].add_logical_channel(lcid); + slice_ues[u.ue_index].add_logical_channel(lcid, lcg_id); } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 076424b478..c12b3e4ff0 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -47,7 +47,7 @@ class ran_slice_instance } /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. - void add_logical_channel(const ue& u, lcid_t lcid); + void add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id); /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. /// \remark UE is removed if all LCIDs of a UE are removed. diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 11bf383349..31c76dd24c 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -64,7 +64,7 @@ void slice_scheduler::add_ue(const ue_configuration& ue_cfg) for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); if (ues.contains(ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); } } } @@ -81,7 +81,7 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); if (ues.contains(next_ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); } } } diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index a334861166..28373d79e1 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -14,14 +14,16 @@ using namespace srsran; slice_ue::slice_ue(const ue& u_) : u(u_), bearers(MAX_NOF_RB_LCIDS) {} -void slice_ue::add_logical_channel(lcid_t lcid) +void slice_ue::add_logical_channel(lcid_t lcid, lcg_id_t lcg_id) { bearers.set(lcid); + lcid_to_lcg_id_lookup[lcid] = lcg_id; } void slice_ue::rem_logical_channel(lcid_t lcid) { bearers.reset(lcid); + lcid_to_lcg_id_lookup.erase(lcid); } bool slice_ue::has_pending_dl_newtx_bytes() const diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h index 6d77525648..180bee9c9d 100644 --- a/lib/scheduler/slicing/slice_ue_repository.h +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -44,7 +44,7 @@ class slice_ue const ue_cell& get_pcell() const { return u.get_pcell(); } /// Add LCID to the bearers of the UE belonging to this slice. - void add_logical_channel(lcid_t lcid); + void add_logical_channel(lcid_t lcid, lcg_id_t lcg_id); /// Remove LCID from the bearers of the UE belonging to this slice. void rem_logical_channel(lcid_t lcid); @@ -83,8 +83,9 @@ class slice_ue unsigned pending_ul_srb_newtx_bytes() const; private: - const ue& u; - bounded_bitset bearers; + const ue& u; + bounded_bitset bearers; + std::unordered_map lcid_to_lcg_id_lookup; }; /// Container that store all UEs belonging to a slice. diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index ccdcd5f033..c9a5ecd2ce 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -115,7 +115,7 @@ class base_scheduler_policy_test ues.add_ue(std::make_unique( ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, harq_timeout_handler})); for (const auto& lc_cfg : *ue_req.cfg.lc_config_list) { - slice_instance.add_logical_channel(ues[ue_req.ue_index], lc_cfg.lcid); + slice_instance.add_logical_channel(ues[ue_req.ue_index], lc_cfg.lcid, lc_cfg.lc_group); } return ues[ue_req.ue_index]; } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 3f2aa6bb28..f4ff0ce655 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -102,7 +102,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam ue_creation_command{ev.next_config(), ue_creation_req.starts_in_fallback, harq_timeout_handler})); slice_ues.emplace(ue_creation_req.ue_index, ues[ue_creation_req.ue_index]); for (const auto& lc_cfg : *ue_creation_req.cfg.lc_config_list) { - slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid); + slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid, lc_cfg.lc_group); } return ues[ue_creation_req.ue_index]; } From bd132d80d7764009a126ce20793b5c40ba456270 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 5 Aug 2024 11:07:30 +0200 Subject: [PATCH 152/407] sched: schedule bytes only from bearers belonging to a particular slice --- lib/scheduler/policy/scheduler_time_pf.cpp | 4 +- lib/scheduler/policy/scheduler_time_rr.cpp | 17 ++--- lib/scheduler/slicing/ran_slice_instance.cpp | 17 +++-- lib/scheduler/slicing/slice_ue_repository.cpp | 66 +++++++++++++------ lib/scheduler/slicing/slice_ue_repository.h | 25 ++----- lib/scheduler/ue_scheduling/ue.cpp | 5 ++ lib/scheduler/ue_scheduling/ue.h | 3 + 7 files changed, 82 insertions(+), 55 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index 31b4f115a9..a683c97b3f 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -202,7 +202,7 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u) // Calculate DL priority. dl_retx_h = srb_retx_h != nullptr ? srb_retx_h : ue_cc->harqs.find_pending_dl_retx(); dl_newtx_h = ue_cc->harqs.find_empty_dl_harq(); - dl_newtx_srb_pending_bytes = u.pending_dl_srb_newtx_bytes(); + dl_newtx_srb_pending_bytes = u.has_srb_bearers_in_slice() ? u.pending_dl_newtx_bytes() : 0; if (dl_retx_h != nullptr or (dl_newtx_h != nullptr and u.has_pending_dl_newtx_bytes())) { // NOTE: It does not matter whether it's a reTx or newTx since DL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. @@ -269,7 +269,7 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, const ue_res ul_retx_h = ue_cc->harqs.find_pending_ul_retx(); ul_newtx_h = ue_cc->harqs.find_empty_ul_harq(); sr_ind_received = u.has_pending_sr(); - ul_newtx_srb_pending_bytes = u.pending_ul_srb_newtx_bytes(); + ul_newtx_srb_pending_bytes = u.has_srb_bearers_in_slice() ? u.pending_ul_newtx_bytes() : 0; if (ul_retx_h != nullptr or (ul_newtx_h != nullptr and u.pending_ul_newtx_bytes() > 0)) { // NOTE: It does not matter whether it's a reTx or newTx since UL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index dddb44a105..7fe473e554 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -276,7 +276,7 @@ static alloc_result alloc_dl_ue(const slice_ue& u, std::optional dl_new_tx_max_nof_rbs_per_ue_per_slot = {}) { if (not is_retx) { - if (ue_with_srb_data_only and not u.has_pending_dl_srb_newtx_bytes()) { + if (ue_with_srb_data_only and not u.has_srb_bearers_in_slice()) { return {alloc_status::skip_ue}; } if (not u.has_pending_dl_newtx_bytes()) { @@ -311,9 +311,8 @@ static alloc_result alloc_dl_ue(const slice_ue& u, for (const dl_harq_process* h_dl : harq_candidates) { ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl->id}; if (not is_retx) { - grant.recommended_nof_bytes = - ue_with_srb_data_only ? u.pending_dl_srb_newtx_bytes() : u.pending_dl_newtx_bytes(); - grant.max_nof_rbs = dl_new_tx_max_nof_rbs_per_ue_per_slot; + grant.recommended_nof_bytes = u.pending_dl_newtx_bytes(); + grant.max_nof_rbs = dl_new_tx_max_nof_rbs_per_ue_per_slot; } const alloc_result result = pdsch_alloc.allocate_dl_grant(grant); // If the allocation failed due to invalid parameters, we continue iteration. @@ -335,15 +334,13 @@ static alloc_result alloc_ul_ue(const slice_ue& u, srslog::basic_logger& logger, std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) { - unsigned pending_newtx_bytes = 0; - unsigned pending_srb_newtx_bytes = 0; + unsigned pending_newtx_bytes = 0; if (not is_retx) { if (schedule_sr_only and not u.has_pending_sr()) { return {alloc_status::skip_ue}; } - // Fetch pending bytes of SRBs. - pending_srb_newtx_bytes = u.pending_ul_srb_newtx_bytes(); - if (ue_with_srb_data_only and pending_srb_newtx_bytes == 0) { + pending_newtx_bytes = u.pending_ul_newtx_bytes(); + if (ue_with_srb_data_only and not u.has_srb_bearers_in_slice()) { return {alloc_status::skip_ue}; } pending_newtx_bytes = u.pending_ul_newtx_bytes(); @@ -371,7 +368,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, for (const ul_harq_process* h_ul : harq_candidates) { ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id}; if (not is_retx) { - grant.recommended_nof_bytes = ue_with_srb_data_only ? pending_srb_newtx_bytes : pending_newtx_bytes; + grant.recommended_nof_bytes = pending_newtx_bytes; grant.max_nof_rbs = ul_new_tx_max_nof_rbs_per_ue_per_slot; } const alloc_result result = pusch_alloc.allocate_ul_grant(grant); diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 4c9be1bca7..4b4804513e 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -37,15 +37,22 @@ void ran_slice_instance::slot_indication(const ue_repository& cell_ues) void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) { + if (not slice_ues.contains(ue_idx)) { + return; + } if (lcid < MAX_NOF_RB_LCIDS) { - if (slice_ues.contains(ue_idx)) { - slice_ues[ue_idx].rem_logical_channel(lcid); - if (not slice_ues[ue_idx].has_bearers_in_slice()) { - slice_ues_to_rem.push_back(ue_idx); - } + slice_ues[ue_idx].rem_logical_channel(lcid); + if (not slice_ues[ue_idx].has_bearers_in_slice()) { + slice_ues_to_rem.push_back(ue_idx); } return; } + // Disable all DRBs. + for (unsigned lcid_to_rem = LCID_MIN_DRB; lcid_to_rem < MAX_NOF_RB_LCIDS; ++lcid_to_rem) { + if (slice_ues[ue_idx].contains(uint_to_lcid(lcid_to_rem))) { + slice_ues[ue_idx].rem_logical_channel(uint_to_lcid(lcid_to_rem)); + } + } slice_ues_to_rem.push_back(ue_idx); } diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index 28373d79e1..bb48342fff 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -28,37 +28,63 @@ void slice_ue::rem_logical_channel(lcid_t lcid) bool slice_ue::has_pending_dl_newtx_bytes() const { - // TODO: Check for pending bytes only in bearers belonging to this slice. - return u.has_pending_dl_newtx_bytes(); + for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { + if (bearers.test(lcid) and u.has_pending_dl_newtx_bytes(uint_to_lcid(lcid))) { + return true; + } + } + return false; } -unsigned slice_ue::pending_dl_srb_newtx_bytes() const +unsigned slice_ue::pending_dl_newtx_bytes() const { - return u.pending_dl_srb_newtx_bytes(); + unsigned pending_bytes = 0; + for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { + if (bearers.test(lcid)) { + pending_bytes += u.pending_dl_newtx_bytes(uint_to_lcid(lcid)); + } + } + return pending_bytes; } -unsigned slice_ue::pending_dl_newtx_bytes(lcid_t lcid) const +unsigned slice_ue::pending_ul_newtx_bytes() const { - return u.pending_dl_newtx_bytes(lcid); -} + constexpr static unsigned SR_GRANT_BYTES = 512; -bool slice_ue::has_pending_dl_srb_newtx_bytes() const -{ - return u.has_pending_dl_srb_newtx_bytes(); -} + bounded_bitset lcg_ids(MAX_NOF_LCGS); + unsigned pending_bytes = 0; + for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { + if (bearers.test(lcid)) { + lcg_ids.set(lcid_to_lcg_id_lookup.at(uint_to_lcid(lcid))); + } + } + for (unsigned lcg_id = 0; lcg_id < lcg_ids.size(); ++lcg_id) { + if (lcg_ids.test(lcg_id)) { + pending_bytes += u.pending_ul_newtx_bytes(uint_to_lcg_id(lcg_id)); + } + } + // Subtract the bytes already allocated in UL HARQs. + for (unsigned cell_idx = 0; cell_idx < nof_cells(); ++cell_idx) { + const ue_cell& ue_cc = get_cell(to_ue_cell_index(cell_idx)); + if (pending_bytes == 0) { + break; + } + unsigned harq_bytes = 0; + for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { + const ul_harq_process& h_ul = ue_cc.harqs.ul_harq(i); + if (not h_ul.empty()) { + harq_bytes += h_ul.last_tx_params().tbs_bytes; + } + } + harq_bytes += ue_cc.harqs.ntn_get_tbs_pending_crcs(); + pending_bytes -= std::min(pending_bytes, harq_bytes); + } -unsigned slice_ue::pending_ul_newtx_bytes() const -{ - // TODO: Check for pending bytes only in bearers belonging to this slice. - return u.pending_ul_newtx_bytes(); + // If there are no pending bytes, check if a SR is pending. + return pending_bytes > 0 ? pending_bytes : (has_pending_sr() ? SR_GRANT_BYTES : 0); } bool slice_ue::has_pending_sr() const { return u.has_pending_sr(); } - -unsigned slice_ue::pending_ul_srb_newtx_bytes() const -{ - return u.pending_ul_srb_newtx_bytes(); -} diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h index 180bee9c9d..d65e9aa430 100644 --- a/lib/scheduler/slicing/slice_ue_repository.h +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -37,6 +37,12 @@ class slice_ue /// Determines if at least one bearer of the UE is part of this slice. bool has_bearers_in_slice() const { return bearers.any(); } + /// Determines if at least one SRB bearer of the UE is part of this slice. + bool has_srb_bearers_in_slice() const + { + return contains(LCID_SRB0) or contains(LCID_SRB1) or contains(LCID_SRB2) or contains(LCID_SRB3); + } + /// Determines if bearer with LCID is part of this slice. bool contains(lcid_t lcid) const { return bearers.test(lcid); } @@ -54,20 +60,9 @@ class slice_ue /// \remark Excludes SRB0 and UE Contention Resolution Identity CE. bool has_pending_dl_newtx_bytes() const; - /// \brief Computes the number of DL pending bytes in SRBs that are not already allocated in a DL HARQ. - /// \return The number of DL pending bytes in SRBs that are not already allocated in a DL HARQ. - /// \remark Excludes SRB0 pending bytes. - unsigned pending_dl_srb_newtx_bytes() const; - /// \brief Computes the number of DL pending bytes that are not already allocated in a DL HARQ. - /// param[in] lcid If the LCID is provided, the method will return the number of pending bytes for that LCID. - /// Otherwise it will return the sum of all LCIDs pending bytes, excluding SRB0. /// \return The number of DL pending bytes that are not already allocated in a DL HARQ. - unsigned pending_dl_newtx_bytes(lcid_t lcid = lcid_t::INVALID_LCID) const; - - /// \brief Checks if there are DL pending bytes in SRBs that are not already allocated in a DL HARQ. - /// \remark Excludes SRB0 pending bytes. - bool has_pending_dl_srb_newtx_bytes() const; + unsigned pending_dl_newtx_bytes() const; /// \brief Computes the number of UL pending bytes in bearers belonging to this slice that are not already allocated /// in a UL HARQ. @@ -76,12 +71,6 @@ class slice_ue /// \brief Returns whether a SR indication handling is pending. bool has_pending_sr() const; - /// \brief Computes the number of UL pending bytes in SRBs. The value is used to derive the required transport block - /// size for an UL grant. - /// \return The number of UL pending bytes in SRBs. - /// \remark The returned UL pending bytes does not exclude already allocated bytes in UL HARQ(s). - unsigned pending_ul_srb_newtx_bytes() const; - private: const ue& u; bounded_bitset bearers; diff --git a/lib/scheduler/ue_scheduling/ue.cpp b/lib/scheduler/ue_scheduling/ue.cpp index 805e04d802..d8b5c8990a 100644 --- a/lib/scheduler/ue_scheduling/ue.cpp +++ b/lib/scheduler/ue_scheduling/ue.cpp @@ -167,6 +167,11 @@ unsigned ue::pending_ul_newtx_bytes() const return pending_bytes > 0 ? pending_bytes : (ul_lc_ch_mgr.has_pending_sr() ? SR_GRANT_BYTES : 0); } +unsigned ue::pending_ul_newtx_bytes(lcg_id_t lcg_id) const +{ + return ul_lc_ch_mgr.pending_bytes(lcg_id); +} + bool ue::has_pending_sr() const { return ul_lc_ch_mgr.has_pending_sr(); diff --git a/lib/scheduler/ue_scheduling/ue.h b/lib/scheduler/ue_scheduling/ue.h index 861fbef8ca..42974f9159 100644 --- a/lib/scheduler/ue_scheduling/ue.h +++ b/lib/scheduler/ue_scheduling/ue.h @@ -156,6 +156,9 @@ class ue /// to derive the required transport block size for an UL grant. unsigned pending_ul_newtx_bytes() const; + /// \brief Computes the number of UL pending bytes for a LCG ID. + unsigned pending_ul_newtx_bytes(lcg_id_t lcg_id) const; + /// \brief Computes the number of UL pending bytes in SRBs. The value is used to derive the required transport block /// size for an UL grant. /// \return The number of UL pending bytes in SRBs. From b6a9ecb9c533ecb7586b7b1784a036fb5b0d40e1 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 5 Aug 2024 11:32:13 +0200 Subject: [PATCH 153/407] sched: add helper to fetch the bearers belonging to a slice --- lib/scheduler/slicing/slice_ue_repository.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h index d65e9aa430..884b1ff837 100644 --- a/lib/scheduler/slicing/slice_ue_repository.h +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -43,6 +43,9 @@ class slice_ue return contains(LCID_SRB0) or contains(LCID_SRB1) or contains(LCID_SRB2) or contains(LCID_SRB3); } + /// Fetches the bitmap of bearers belonging to this slice. + const bounded_bitset& get_bearers() const { return bearers; } + /// Determines if bearer with LCID is part of this slice. bool contains(lcid_t lcid) const { return bearers.test(lcid); } From 7d8cfae6f2e0fb7609713770f00b2d329df411ea Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 5 Aug 2024 11:32:43 +0200 Subject: [PATCH 154/407] sched: build TB information only for bearers belonging to a slice --- lib/scheduler/ue_scheduling/ue.cpp | 11 +++++++++-- lib/scheduler/ue_scheduling/ue.h | 4 +++- .../ue_scheduling/ue_cell_grid_allocator.cpp | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue.cpp b/lib/scheduler/ue_scheduling/ue.cpp index d8b5c8990a..af2bbd5705 100644 --- a/lib/scheduler/ue_scheduling/ue.cpp +++ b/lib/scheduler/ue_scheduling/ue.cpp @@ -177,11 +177,18 @@ bool ue::has_pending_sr() const return ul_lc_ch_mgr.has_pending_sr(); } -unsigned ue::build_dl_transport_block_info(dl_msg_tb_info& tb_info, unsigned tb_size_bytes, lcid_t lcid) +unsigned ue::build_dl_transport_block_info(dl_msg_tb_info& tb_info, + unsigned tb_size_bytes, + const bounded_bitset& lcids) { unsigned total_subpdu_bytes = 0; total_subpdu_bytes += allocate_mac_ces(tb_info, dl_lc_ch_mgr, tb_size_bytes); - total_subpdu_bytes += allocate_mac_sdus(tb_info, dl_lc_ch_mgr, tb_size_bytes - total_subpdu_bytes, lcid); + for (unsigned lcid = 0; lcid < lcids.size(); ++lcid) { + if (lcids.test(lcid)) { + total_subpdu_bytes += + allocate_mac_sdus(tb_info, dl_lc_ch_mgr, tb_size_bytes - total_subpdu_bytes, uint_to_lcid(lcid)); + } + } return total_subpdu_bytes; } diff --git a/lib/scheduler/ue_scheduling/ue.h b/lib/scheduler/ue_scheduling/ue.h index 42974f9159..5874b1388b 100644 --- a/lib/scheduler/ue_scheduling/ue.h +++ b/lib/scheduler/ue_scheduling/ue.h @@ -171,7 +171,9 @@ class ue /// \brief Defines the list of subPDUs, including LCID and payload size, that will compose the transport block. /// \return Returns the number of bytes reserved in the TB for subPDUs (other than padding). /// \remark Excludes SRB0. - unsigned build_dl_transport_block_info(dl_msg_tb_info& tb_info, unsigned tb_size_bytes, lcid_t lcid = INVALID_LCID); + unsigned build_dl_transport_block_info(dl_msg_tb_info& tb_info, + unsigned tb_size_bytes, + const bounded_bitset& lcids); /// \brief Defines the list of subPDUs, including LCID and payload size, that will compose the transport block for /// SRB0 or for SRB1 in fallback mode. diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 4fc4afca70..ec264cfac4 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -466,7 +466,8 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra if (is_new_data) { // Set MAC logical channels to schedule in this PDU if it is a newtx. - u.build_dl_transport_block_info(msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes); + u.build_dl_transport_block_info( + msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes, grant.user->get_bearers()); // Update context with buffer occupancy after the TB is built. msg.context.buffer_occupancy = u.pending_dl_newtx_bytes(); From e2e39c18c79acce83bbdc83ab4524710df0e2b7d Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 5 Aug 2024 17:04:57 +0200 Subject: [PATCH 155/407] sched,unittest: remove LCID to LCG ID lookup and use the LC configuration in UE dedicated configuration --- lib/scheduler/policy/scheduler_time_pf.cpp | 19 +++++---- lib/scheduler/policy/scheduler_time_rr.cpp | 1 - lib/scheduler/slicing/ran_slice_instance.cpp | 4 +- lib/scheduler/slicing/ran_slice_instance.h | 2 +- lib/scheduler/slicing/slice_scheduler.cpp | 20 ++++----- lib/scheduler/slicing/slice_scheduler.h | 2 +- lib/scheduler/slicing/slice_ue_repository.cpp | 18 ++++++-- lib/scheduler/slicing/slice_ue_repository.h | 10 +++-- .../policy/scheduler_policy_test.cpp | 41 +++++++++---------- .../slicing/slice_scheduler_test.cpp | 32 +++++++++++++++ .../ue_scheduling/ue_grid_allocator_test.cpp | 2 +- 11 files changed, 98 insertions(+), 53 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index a683c97b3f..83b6bbdb1a 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -200,9 +200,10 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u) } // Calculate DL priority. - dl_retx_h = srb_retx_h != nullptr ? srb_retx_h : ue_cc->harqs.find_pending_dl_retx(); - dl_newtx_h = ue_cc->harqs.find_empty_dl_harq(); - dl_newtx_srb_pending_bytes = u.has_srb_bearers_in_slice() ? u.pending_dl_newtx_bytes() : 0; + dl_retx_h = srb_retx_h != nullptr ? srb_retx_h : ue_cc->harqs.find_pending_dl_retx(); + dl_newtx_h = ue_cc->harqs.find_empty_dl_harq(); + // NOTE: Only if the slice is an SRB slice then \c dl_newtx_srb_pending_bytes will be > 0. + dl_newtx_srb_pending_bytes = u.pending_dl_newtx_bytes(); if (dl_retx_h != nullptr or (dl_newtx_h != nullptr and u.has_pending_dl_newtx_bytes())) { // NOTE: It does not matter whether it's a reTx or newTx since DL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. @@ -266,11 +267,13 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, const ue_res } // Calculate UL priority. - ul_retx_h = ue_cc->harqs.find_pending_ul_retx(); - ul_newtx_h = ue_cc->harqs.find_empty_ul_harq(); - sr_ind_received = u.has_pending_sr(); - ul_newtx_srb_pending_bytes = u.has_srb_bearers_in_slice() ? u.pending_ul_newtx_bytes() : 0; - if (ul_retx_h != nullptr or (ul_newtx_h != nullptr and u.pending_ul_newtx_bytes() > 0)) { + ul_retx_h = ue_cc->harqs.find_pending_ul_retx(); + ul_newtx_h = ue_cc->harqs.find_empty_ul_harq(); + sr_ind_received = u.has_pending_sr(); + unsigned pending_bytes = u.pending_ul_newtx_bytes(); + // NOTE: Only if the slice is an SRB slice or has SR pending then \c dl_newtx_srb_pending_bytes will be > 0. + ul_newtx_srb_pending_bytes = pending_bytes; + if (ul_retx_h != nullptr or (ul_newtx_h != nullptr and pending_bytes > 0)) { // NOTE: It does not matter whether it's a reTx or newTx since UL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. // [Implementation-defined] We consider only the SearchSpace defined in UE dedicated configuration. diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 7fe473e554..f4fde02038 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -343,7 +343,6 @@ static alloc_result alloc_ul_ue(const slice_ue& u, if (ue_with_srb_data_only and not u.has_srb_bearers_in_slice()) { return {alloc_status::skip_ue}; } - pending_newtx_bytes = u.pending_ul_newtx_bytes(); if (pending_newtx_bytes == 0) { return {alloc_status::skip_ue}; } diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 4b4804513e..ede1ea08fe 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -61,10 +61,10 @@ const slice_ue_repository& ran_slice_instance::get_ues() return slice_ues; } -void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id) +void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid) { if (not slice_ues.contains(u.ue_index)) { slice_ues.emplace(u.ue_index, u); } - slice_ues[u.ue_index].add_logical_channel(lcid, lcg_id); + slice_ues[u.ue_index].add_logical_channel(lcid); } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index c12b3e4ff0..076424b478 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -47,7 +47,7 @@ class ran_slice_instance } /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. - void add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id); + void add_logical_channel(const ue& u, lcid_t lcid); /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. /// \remark UE is removed if all LCIDs of a UE are removed. diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 31c76dd24c..0df6c9fa76 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -62,9 +62,9 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); + ran_slice_instance& sl_inst = get_slice(lc_cfg); if (ues.contains(ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); + sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid); } } } @@ -73,15 +73,15 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co { // Remove old bearers. for (const logical_channel_config& lc_cfg : prev_ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); + ran_slice_instance& sl_inst = get_slice(lc_cfg); sl_inst.rem_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid); } // Add new bearers. for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy, lc_cfg); + ran_slice_instance& sl_inst = get_slice(lc_cfg); if (ues.contains(next_ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); + sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid); } } } @@ -93,13 +93,13 @@ void slice_scheduler::rem_ue(du_ue_index_t ue_idx) } } -ran_slice_instance& slice_scheduler::get_slice(const rrm_policy_member& rrm, const logical_channel_config& lc_cfg) +ran_slice_instance& slice_scheduler::get_slice(const logical_channel_config& lc_cfg) { - auto it = std::find_if(slices.begin(), slices.end(), [&rrm](const ran_slice_sched_context& slice) { - return slice.inst.cfg.rrc_member == rrm; + auto it = std::find_if(slices.begin(), slices.end(), [&lc_cfg](const ran_slice_sched_context& slice) { + return slice.inst.cfg.rrc_member == lc_cfg.rrm_policy; }); - if (it == slices.end()) { - // Slice with the provided RRM policy member was not found. If logicall channel is a SRB then return default SRB + if (it == slices.end() or lc_cfg.rrm_policy == rrm_policy_member{}) { + // Slice with the provided RRM policy member was not found. If logical channel is an SRB then return default SRB // slice. Else, return default DRB slice. if (lc_cfg.lcid < LCID_MIN_DRB) { return slices[default_srb_ran_slice_id.value()].inst; diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index 9cd28d991b..91b566a2f3 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -106,7 +106,7 @@ class slice_scheduler } }; - ran_slice_instance& get_slice(const rrm_policy_member& rrm, const logical_channel_config& lc_cfg); + ran_slice_instance& get_slice(const logical_channel_config& lc_cfg); template std::optional> get_next_candidate(); diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index bb48342fff..0989b7a502 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -14,16 +14,14 @@ using namespace srsran; slice_ue::slice_ue(const ue& u_) : u(u_), bearers(MAX_NOF_RB_LCIDS) {} -void slice_ue::add_logical_channel(lcid_t lcid, lcg_id_t lcg_id) +void slice_ue::add_logical_channel(lcid_t lcid) { bearers.set(lcid); - lcid_to_lcg_id_lookup[lcid] = lcg_id; } void slice_ue::rem_logical_channel(lcid_t lcid) { bearers.reset(lcid); - lcid_to_lcg_id_lookup.erase(lcid); } bool slice_ue::has_pending_dl_newtx_bytes() const @@ -55,7 +53,7 @@ unsigned slice_ue::pending_ul_newtx_bytes() const unsigned pending_bytes = 0; for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { if (bearers.test(lcid)) { - lcg_ids.set(lcid_to_lcg_id_lookup.at(uint_to_lcid(lcid))); + lcg_ids.set(get_lcg_id_for_bearer(uint_to_lcid(lcid))); } } for (unsigned lcg_id = 0; lcg_id < lcg_ids.size(); ++lcg_id) { @@ -88,3 +86,15 @@ bool slice_ue::has_pending_sr() const { return u.has_pending_sr(); } + +lcg_id_t slice_ue::get_lcg_id_for_bearer(lcid_t lcid) const +{ + const ue_configuration* ue_ded_cfg = u.ue_cfg_dedicated(); + span lc_cfgs = ue_ded_cfg->logical_channels(); + for (const auto& cfg : lc_cfgs) { + if (cfg.lcid == lcid) { + return cfg.lc_group; + } + } + return LCG_ID_INVALID; +} diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h index 884b1ff837..dc420e0b04 100644 --- a/lib/scheduler/slicing/slice_ue_repository.h +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -53,7 +53,7 @@ class slice_ue const ue_cell& get_pcell() const { return u.get_pcell(); } /// Add LCID to the bearers of the UE belonging to this slice. - void add_logical_channel(lcid_t lcid, lcg_id_t lcg_id); + void add_logical_channel(lcid_t lcid); /// Remove LCID from the bearers of the UE belonging to this slice. void rem_logical_channel(lcid_t lcid); @@ -75,9 +75,11 @@ class slice_ue bool has_pending_sr() const; private: - const ue& u; - bounded_bitset bearers; - std::unordered_map lcid_to_lcg_id_lookup; + /// Helper function to get LCG ID of a bearer. + lcg_id_t get_lcg_id_for_bearer(lcid_t lcid) const; + + const ue& u; + bounded_bitset bearers; }; /// Container that store all UEs belonging to a slice. diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index c9a5ecd2ce..4e649dccd4 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -12,8 +12,8 @@ #include "lib/scheduler/logging/scheduler_result_logger.h" #include "lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.h" #include "lib/scheduler/policy/scheduler_policy_factory.h" -#include "lib/scheduler/policy/scheduler_time_rr.h" #include "lib/scheduler/pucch_scheduling/pucch_allocator_impl.h" +#include "lib/scheduler/slicing/slice_scheduler.h" #include "lib/scheduler/uci_scheduling/uci_allocator_impl.h" #include "lib/scheduler/ue_scheduling/ue.h" #include "lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h" @@ -51,18 +51,13 @@ class base_scheduler_policy_test cell_cfg(*[this, &msg]() { return cell_cfg_list.emplace(to_du_cell_index(0), std::make_unique(sched_cfg, msg)).get(); }()), - slice_instance(ran_slice_id_t{0}, cell_cfg, slice_rrm_policy_config{}) + slice_sched(cell_cfg, ues) { logger.set_level(srslog::basic_levels::debug); srslog::init(); grid_alloc.add_cell(to_du_cell_index(0), pdcch_alloc, uci_alloc, res_grid); ue_res_grid.add_cell(res_grid); - - sched = create_scheduler_strategy(sched_cfg.ue); - if (sched == nullptr) { - report_fatal_error("Failed to initialize slice scheduler"); - } } ~base_scheduler_policy_test() { srslog::flush(); } @@ -72,7 +67,7 @@ class base_scheduler_policy_test logger.set_context(next_slot.sfn(), next_slot.slot_index()); grid_alloc.slot_indication(next_slot); - slice_instance.slot_indication(ues); + slice_sched.slot_indication(); res_grid.slot_indication(next_slot); pdcch_alloc.slot_indication(next_slot); @@ -80,8 +75,20 @@ class base_scheduler_policy_test uci_alloc.slot_indication(next_slot); if (cell_cfg.is_dl_enabled(next_slot)) { - sched->dl_sched(slice_pdsch_alloc, ue_res_grid, dl_slice_candidate); - sched->ul_sched(slice_pusch_alloc, ue_res_grid, ul_slice_candidate); + auto dl_slice_candidate = slice_sched.get_next_dl_candidate(); + while (dl_slice_candidate.has_value()) { + auto& policy = slice_sched.get_policy(dl_slice_candidate->id()); + dl_slice_ue_cell_grid_allocator slice_pdsch_alloc{grid_alloc, *dl_slice_candidate}; + policy.dl_sched(slice_pdsch_alloc, ue_res_grid, *dl_slice_candidate); + dl_slice_candidate = slice_sched.get_next_dl_candidate(); + } + auto ul_slice_candidate = slice_sched.get_next_ul_candidate(); + while (ul_slice_candidate.has_value()) { + auto& policy = slice_sched.get_policy(ul_slice_candidate->id()); + ul_slice_ue_cell_grid_allocator slice_pusch_alloc{grid_alloc, *ul_slice_candidate}; + policy.ul_sched(slice_pusch_alloc, ue_res_grid, *ul_slice_candidate); + ul_slice_candidate = slice_sched.get_next_ul_candidate(); + } } // Log scheduler results. @@ -114,9 +121,7 @@ class base_scheduler_policy_test std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); ues.add_ue(std::make_unique( ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, harq_timeout_handler})); - for (const auto& lc_cfg : *ue_req.cfg.lc_config_list) { - slice_instance.add_logical_channel(ues[ue_req.ue_index], lc_cfg.lcid, lc_cfg.lc_group); - } + slice_sched.add_ue(*ues[ue_req.ue_index].ue_cfg_dedicated()); return ues[ue_req.ue_index]; } @@ -177,14 +182,8 @@ class base_scheduler_policy_test ue_resource_grid_view ue_res_grid; ue_repository ues; ue_cell_grid_allocator grid_alloc{sched_cfg.ue, ues, logger}; - std::unique_ptr sched; - - // Default RAN slice instance. - ran_slice_instance slice_instance; - dl_ran_slice_candidate dl_slice_candidate{slice_instance}; - ul_ran_slice_candidate ul_slice_candidate{slice_instance}; - dl_slice_ue_cell_grid_allocator slice_pdsch_alloc{grid_alloc, dl_slice_candidate}; - ul_slice_ue_cell_grid_allocator slice_pusch_alloc{grid_alloc, ul_slice_candidate}; + // NOTE: Policy scheduler is part of RAN slice instances created in slice scheduler. + slice_scheduler slice_sched; slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; }; diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 6a332c5399..a4f8a3798a 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -122,6 +122,10 @@ TEST_F(default_slice_scheduler_test, ASSERT_TRUE(next_dl_slice.has_value()); ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); + next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_TRUE(next_dl_slice.has_value()); + ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{1}); + next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); } @@ -341,3 +345,31 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_EQ(slice_3_count, slice_2_count) << "Round-robin of slices of same priority failed"; } + +class srb_prioritization_slice_scheduler_test : public slice_scheduler_test, public ::testing::Test +{ +protected: + const ue_configuration* add_ue(du_ue_index_t ue_idx) + { + auto req = test_cfg.get_default_ue_config_request(); + req.ue_index = ue_idx; + req.crnti = to_rnti(0x4601 + ue_idx); + req.starts_in_fallback = false; + return slice_scheduler_test::add_ue(req); + } +}; + +TEST_F(srb_prioritization_slice_scheduler_test, schedules_default_srb_slice_first_before_any_other_slices) +{ + ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); + ASSERT_NE(this->add_ue(to_du_ue_index(1)), nullptr); + slice_sched.slot_indication(); + + auto next_ul_slice = slice_sched.get_next_ul_candidate(); + ASSERT_TRUE(next_ul_slice.has_value()); + ASSERT_EQ(next_ul_slice->id(), ran_slice_id_t{0}); + + auto next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_TRUE(next_dl_slice.has_value()); + ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); +} diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index f4ff0ce655..3f2aa6bb28 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -102,7 +102,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam ue_creation_command{ev.next_config(), ue_creation_req.starts_in_fallback, harq_timeout_handler})); slice_ues.emplace(ue_creation_req.ue_index, ues[ue_creation_req.ue_index]); for (const auto& lc_cfg : *ue_creation_req.cfg.lc_config_list) { - slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid, lc_cfg.lc_group); + slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid); } return ues[ue_creation_req.ue_index]; } From 0a8861f3ec0b0fd5287f6ce3758fb3e0f71651d1 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 6 Aug 2024 08:57:32 +0200 Subject: [PATCH 156/407] sched: store LCG IDs of bearers belonging to a slice --- lib/scheduler/slicing/ran_slice_instance.cpp | 4 +-- lib/scheduler/slicing/ran_slice_instance.h | 2 +- lib/scheduler/slicing/slice_scheduler.cpp | 5 ++-- lib/scheduler/slicing/slice_ue_repository.cpp | 28 +++++++++++++------ lib/scheduler/slicing/slice_ue_repository.h | 4 ++- .../ue_scheduling/ue_grid_allocator_test.cpp | 2 +- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index ede1ea08fe..4b4804513e 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -61,10 +61,10 @@ const slice_ue_repository& ran_slice_instance::get_ues() return slice_ues; } -void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid) +void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id) { if (not slice_ues.contains(u.ue_index)) { slice_ues.emplace(u.ue_index, u); } - slice_ues[u.ue_index].add_logical_channel(lcid); + slice_ues[u.ue_index].add_logical_channel(lcid, lcg_id); } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 076424b478..c12b3e4ff0 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -47,7 +47,7 @@ class ran_slice_instance } /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. - void add_logical_channel(const ue& u, lcid_t lcid); + void add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id); /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. /// \remark UE is removed if all LCIDs of a UE are removed. diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 0df6c9fa76..91c8dffdc5 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -64,7 +64,7 @@ void slice_scheduler::add_ue(const ue_configuration& ue_cfg) for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); if (ues.contains(ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); } } } @@ -81,7 +81,7 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); if (ues.contains(next_ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); } } } @@ -89,6 +89,7 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co void slice_scheduler::rem_ue(du_ue_index_t ue_idx) { for (auto& slice : slices) { + // Remove all logical channels of UE. slice.inst.rem_logical_channel(ue_idx); } } diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index 0989b7a502..a6934ef840 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -12,16 +12,32 @@ using namespace srsran; -slice_ue::slice_ue(const ue& u_) : u(u_), bearers(MAX_NOF_RB_LCIDS) {} +slice_ue::slice_ue(const ue& u_) : u(u_), bearers(MAX_NOF_RB_LCIDS), lcg_ids(MAX_NOF_LCGS) {} -void slice_ue::add_logical_channel(lcid_t lcid) +void slice_ue::add_logical_channel(lcid_t lcid, lcg_id_t lcg_id) { + srsran_assert(lcid < MAX_NOF_RB_LCIDS, "Invalid LCID={} to add for a slice UE", lcid); bearers.set(lcid); + srsran_assert(lcg_id < MAX_NOF_LCGS, "Invalid LCG ID={} for bearer with LCID={}", lcg_id, lcid); + lcg_ids.set(lcg_id); } void slice_ue::rem_logical_channel(lcid_t lcid) { + srsran_assert(lcid < MAX_NOF_RB_LCIDS, "Invalid LCID={} to remove from a slice UE", lcid); bearers.reset(lcid); + lcg_id_t lcg_id_to_rem = get_lcg_id_for_bearer(lcid); + srsran_assert(lcg_id_to_rem < MAX_NOF_LCGS, "Unable to fetch LCG ID for bearer with LCID={}", lcid); + // Check whether there are bearers with same LCG ID. If not, remove LCG ID from slice. + for (unsigned lcid_idx = 0; lcid_idx < bearers.size(); ++lcid_idx) { + if (bearers.test(uint_to_lcid(lcid_idx))) { + lcg_id_t other_lcg_id = get_lcg_id_for_bearer(uint_to_lcid(lcid_idx)); + if (lcg_id_to_rem == other_lcg_id) { + return; + } + } + } + lcg_ids.reset(lcg_id_to_rem); } bool slice_ue::has_pending_dl_newtx_bytes() const @@ -49,13 +65,7 @@ unsigned slice_ue::pending_ul_newtx_bytes() const { constexpr static unsigned SR_GRANT_BYTES = 512; - bounded_bitset lcg_ids(MAX_NOF_LCGS); - unsigned pending_bytes = 0; - for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { - if (bearers.test(lcid)) { - lcg_ids.set(get_lcg_id_for_bearer(uint_to_lcid(lcid))); - } - } + unsigned pending_bytes = 0; for (unsigned lcg_id = 0; lcg_id < lcg_ids.size(); ++lcg_id) { if (lcg_ids.test(lcg_id)) { pending_bytes += u.pending_ul_newtx_bytes(uint_to_lcg_id(lcg_id)); diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h index dc420e0b04..228f308498 100644 --- a/lib/scheduler/slicing/slice_ue_repository.h +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -53,7 +53,7 @@ class slice_ue const ue_cell& get_pcell() const { return u.get_pcell(); } /// Add LCID to the bearers of the UE belonging to this slice. - void add_logical_channel(lcid_t lcid); + void add_logical_channel(lcid_t lcid, lcg_id_t lcg_id); /// Remove LCID from the bearers of the UE belonging to this slice. void rem_logical_channel(lcid_t lcid); @@ -80,6 +80,8 @@ class slice_ue const ue& u; bounded_bitset bearers; + /// LCG IDs of bearers belonging to this slice. + bounded_bitset lcg_ids; }; /// Container that store all UEs belonging to a slice. diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 3f2aa6bb28..f4ff0ce655 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -102,7 +102,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam ue_creation_command{ev.next_config(), ue_creation_req.starts_in_fallback, harq_timeout_handler})); slice_ues.emplace(ue_creation_req.ue_index, ues[ue_creation_req.ue_index]); for (const auto& lc_cfg : *ue_creation_req.cfg.lc_config_list) { - slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid); + slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid, lc_cfg.lc_group); } return ues[ue_creation_req.ue_index]; } From 4e25be0623538d1771770d7588bba45c0881c5e8 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 6 Aug 2024 09:51:07 +0200 Subject: [PATCH 157/407] sched: minor refactor in getting slice based on RRM policy --- lib/scheduler/slicing/slice_scheduler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 91c8dffdc5..09320d42f8 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -96,15 +96,15 @@ void slice_scheduler::rem_ue(du_ue_index_t ue_idx) ran_slice_instance& slice_scheduler::get_slice(const logical_channel_config& lc_cfg) { + // Return default SRB slice if LCID belongs to a SRB. + if (lc_cfg.lcid < LCID_MIN_DRB) { + return slices[default_srb_ran_slice_id.value()].inst; + } auto it = std::find_if(slices.begin(), slices.end(), [&lc_cfg](const ran_slice_sched_context& slice) { return slice.inst.cfg.rrc_member == lc_cfg.rrm_policy; }); if (it == slices.end() or lc_cfg.rrm_policy == rrm_policy_member{}) { - // Slice with the provided RRM policy member was not found. If logical channel is an SRB then return default SRB - // slice. Else, return default DRB slice. - if (lc_cfg.lcid < LCID_MIN_DRB) { - return slices[default_srb_ran_slice_id.value()].inst; - } + // Slice with the provided RRM policy member was not found. Return default DRB slice. return slices[default_drb_ran_slice_id.value()].inst; } return it->inst; From d1e1c050a9e370ba9fa917e9384049554a7d5742 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 6 Aug 2024 09:52:02 +0200 Subject: [PATCH 158/407] unittest: add unittest to verify only pending DL bytes of bearers belonging to a slice is returned --- .../slicing/slice_scheduler_test.cpp | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index a4f8a3798a..dbe298754a 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -157,6 +157,43 @@ TEST_F(default_slice_scheduler_test, when_grant_gets_allocated_then_number_of_av ASSERT_EQ(next_dl_slice->remaining_rbs(), rem_rbs - alloc_rbs); } +TEST_F(default_slice_scheduler_test, returns_only_dl_pending_bytes_of_bearers_belonging_to_a_slice) +{ + constexpr static ran_slice_id_t default_srb_slice_id{0}; + constexpr static ran_slice_id_t default_drb_slice_id{1}; + + constexpr static unsigned srb_pending_bytes{200}; + constexpr static unsigned drb_pending_bytes{5000}; + + constexpr static du_ue_index_t ue_idx{to_du_ue_index(0)}; + + ASSERT_NE(this->add_ue(ue_idx), nullptr); + // Push buffer state indication for DRB. + dl_buffer_state_indication_message ind{}; + ind.ue_index = ue_idx; + ind.lcid = LCID_MIN_DRB; + ind.bs = drb_pending_bytes; + this->ues[ue_idx].handle_dl_buffer_state_indication(ind); + // Push buffer state indication for SRB. + ind.lcid = LCID_SRB1; + ind.bs = srb_pending_bytes; + this->ues[ue_idx].handle_dl_buffer_state_indication(ind); + + slice_sched.slot_indication(); + + // 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); + const slice_ue_repository& srb_slice_ues = next_dl_slice->get_slice_ues(); + ASSERT_EQ(srb_slice_ues[ue_idx].pending_dl_newtx_bytes(), get_mac_sdu_required_bytes(srb_pending_bytes)); + + // Default DRB slice is next candidate. + next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_EQ(next_dl_slice->id(), default_drb_slice_id); + const slice_ue_repository& drb_slice_ues = next_dl_slice->get_slice_ues(); + ASSERT_EQ(drb_slice_ues[ue_idx].pending_dl_newtx_bytes(), get_mac_sdu_required_bytes(drb_pending_bytes)); +} + // rb_ratio_slice_scheduler_test class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::testing::Test From c19da1e3554f2e0e429035e6f214083eb3d137cd Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 6 Aug 2024 10:22:58 +0200 Subject: [PATCH 159/407] unittest: add unittest to verify only pending UL bytes of bearers belonging to a slice is returned --- .../slicing/slice_scheduler_test.cpp | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index dbe298754a..0fc1d5f5a1 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -194,6 +194,49 @@ TEST_F(default_slice_scheduler_test, returns_only_dl_pending_bytes_of_bearers_be ASSERT_EQ(drb_slice_ues[ue_idx].pending_dl_newtx_bytes(), get_mac_sdu_required_bytes(drb_pending_bytes)); } +TEST_F(default_slice_scheduler_test, returns_only_ul_pending_bytes_of_bearers_belonging_to_a_slice) +{ + // Estimate of the number of bytes required for the upper layer header. + constexpr static unsigned RLC_HEADER_SIZE_ESTIMATE = 3U; + + constexpr static ran_slice_id_t default_srb_slice_id{0}; + constexpr static ran_slice_id_t default_drb_slice_id{1}; + + constexpr static unsigned srb_pending_bytes{200}; + constexpr static unsigned drb_pending_bytes{5000}; + + const lcg_id_t srb_lcg_id = config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB1).lc_group; + const lcg_id_t drb_lcg_id = config_helpers::create_default_logical_channel_config(lcid_t::LCID_MIN_DRB).lc_group; + + constexpr static du_ue_index_t ue_idx{to_du_ue_index(0)}; + + ASSERT_NE(this->add_ue(ue_idx), nullptr); + // Push UL BSR for DRB. + ul_bsr_indication_message msg{ + to_du_cell_index(0), ue_idx, to_rnti(0x4601 + (unsigned)ue_idx), bsr_format::SHORT_BSR, {}}; + msg.reported_lcgs.push_back(ul_bsr_lcg_report{drb_lcg_id, drb_pending_bytes}); + this->ues[ue_idx].handle_bsr_indication(msg); + // Push UL BSR for SRB. + msg.reported_lcgs.clear(); + msg.reported_lcgs.push_back(ul_bsr_lcg_report{srb_lcg_id, srb_pending_bytes}); + this->ues[ue_idx].handle_bsr_indication(msg); + + slice_sched.slot_indication(); + + // 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); + const slice_ue_repository& srb_slice_ues = next_dl_slice->get_slice_ues(); + ASSERT_EQ(srb_slice_ues[ue_idx].pending_ul_newtx_bytes(), get_mac_sdu_required_bytes(srb_pending_bytes)); + + // Default DRB slice is next candidate. + next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_EQ(next_dl_slice->id(), default_drb_slice_id); + const slice_ue_repository& drb_slice_ues = next_dl_slice->get_slice_ues(); + ASSERT_EQ(drb_slice_ues[ue_idx].pending_ul_newtx_bytes(), + RLC_HEADER_SIZE_ESTIMATE + get_mac_sdu_required_bytes(drb_pending_bytes)); +} + // rb_ratio_slice_scheduler_test class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::testing::Test From 51e7c46af6428944b47ae467469e110faf5fa021 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 6 Aug 2024 15:26:06 +0200 Subject: [PATCH 160/407] sched: store RAN slice Id as part of the HARQ alloc params --- lib/scheduler/policy/scheduler_time_pf.cpp | 12 ++- lib/scheduler/policy/scheduler_time_pf.h | 14 +++- lib/scheduler/policy/scheduler_time_rr.cpp | 78 ++++++++++--------- lib/scheduler/policy/ue_allocator.h | 2 + lib/scheduler/ue_scheduling/harq_process.cpp | 2 + lib/scheduler/ue_scheduling/harq_process.h | 22 ++++-- .../ue_scheduling/ue_cell_grid_allocator.cpp | 2 + 7 files changed, 79 insertions(+), 53 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index 83b6bbdb1a..cf27997c65 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -49,7 +49,7 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, while (not dl_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *dl_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_dl_alloc(ue, ues, pdsch_alloc, rem_rbs); + alloc_result = try_dl_alloc(ue, ues, pdsch_alloc, rem_rbs, slice_candidate.id()); } ue.save_dl_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -94,7 +94,7 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, while (not ul_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *ul_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs); + alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs, slice_candidate.id()); } ue.save_ul_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -110,10 +110,12 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, - unsigned max_rbs) + unsigned max_rbs, + ran_slice_id_t slice_id) { alloc_result alloc_result = {alloc_status::invalid_params}; ue_pdsch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; + grant.slice_id = slice_id; // Prioritize reTx over newTx. if (ctxt.dl_retx_h != nullptr) { grant.h_id = ctxt.dl_retx_h->id; @@ -144,10 +146,12 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, - unsigned max_rbs) + unsigned max_rbs, + ran_slice_id_t slice_id) { alloc_result alloc_result = {alloc_status::invalid_params}; ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; + grant.slice_id = slice_id; // Prioritize reTx over newTx. if (ctxt.ul_retx_h != nullptr) { grant.h_id = ctxt.ul_retx_h->id; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index dbc1e5a02e..29a532b165 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -83,12 +83,18 @@ class scheduler_time_pf : public scheduler_policy /// \brief Attempts to allocate PDSCH for a UE. /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. - alloc_result - try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, unsigned max_rbs); + alloc_result try_dl_alloc(ue_ctxt& ctxt, + const slice_ue_repository& ues, + ue_pdsch_allocator& pdsch_alloc, + unsigned max_rbs, + ran_slice_id_t slice_id); /// \brief Attempts to allocate PUSCH for a UE. /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. - alloc_result - try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, unsigned max_rbs); + alloc_result try_ul_alloc(ue_ctxt& ctxt, + const slice_ue_repository& ues, + ue_pusch_allocator& pusch_alloc, + unsigned max_rbs, + ran_slice_id_t slice_id); slotted_id_table ue_history_db; diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index f4fde02038..aa24a9b516 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -266,14 +266,14 @@ round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, } /// Allocate UE PDSCH grant. -static alloc_result alloc_dl_ue(const slice_ue& u, - const ue_resource_grid_view& res_grid, - ue_pdsch_allocator& pdsch_alloc, - bool is_retx, - bool ue_with_srb_data_only, - srslog::basic_logger& logger, - const scheduler_ue_expert_config& ue_expert_cfg, - std::optional dl_new_tx_max_nof_rbs_per_ue_per_slot = {}) +static alloc_result alloc_dl_ue(const slice_ue& u, + const ue_resource_grid_view& res_grid, + ue_pdsch_allocator& pdsch_alloc, + bool is_retx, + bool ue_with_srb_data_only, + srslog::basic_logger& logger, + ran_slice_id_t slice_id, + std::optional dl_new_tx_max_nof_rbs_per_ue_per_slot = {}) { if (not is_retx) { if (ue_with_srb_data_only and not u.has_srb_bearers_in_slice()) { @@ -309,7 +309,7 @@ static alloc_result alloc_dl_ue(const slice_ue& u, // Iterate through allocation parameter candidates. for (const dl_harq_process* h_dl : harq_candidates) { - ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl->id}; + ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl->id, slice_id}; if (not is_retx) { grant.recommended_nof_bytes = u.pending_dl_newtx_bytes(); grant.max_nof_rbs = dl_new_tx_max_nof_rbs_per_ue_per_slot; @@ -325,14 +325,14 @@ static alloc_result alloc_dl_ue(const slice_ue& u, } /// Allocate UE PUSCH grant. -static alloc_result alloc_ul_ue(const slice_ue& u, - const ue_resource_grid_view& res_grid, - ue_pusch_allocator& pusch_alloc, - bool is_retx, - bool schedule_sr_only, - bool ue_with_srb_data_only, - srslog::basic_logger& logger, - std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) +static alloc_result alloc_ul_ue(const slice_ue& u, + ue_pusch_allocator& pusch_alloc, + bool is_retx, + bool schedule_sr_only, + bool ue_with_srb_data_only, + srslog::basic_logger& logger, + ran_slice_id_t slice_id, + std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) { unsigned pending_newtx_bytes = 0; if (not is_retx) { @@ -365,7 +365,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, // Iterate through allocation parameter candidates. for (const ul_harq_process* h_ul : harq_candidates) { - ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id}; + ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id, slice_id}; if (not is_retx) { grant.recommended_nof_bytes = pending_newtx_bytes; grant.max_nof_rbs = ul_new_tx_max_nof_rbs_per_ue_per_slot; @@ -394,8 +394,9 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, const ue_resource_grid_view& res_grid, dl_ran_slice_candidate& slice_candidate) { - const slice_ue_repository& ues = slice_candidate.get_slice_ues(); - const unsigned max_rbs = slice_candidate.remaining_rbs(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); + const unsigned max_rbs = slice_candidate.remaining_rbs(); + const ran_slice_id_t slice_id = slice_candidate.id(); if (ues.empty() or max_rbs == 0) { // No UEs to be scheduled or if there are no RBs to be scheduled in slice. @@ -403,8 +404,8 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, } // First, schedule UEs with SRB data re-transmissions. - auto srb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const slice_ue& u) { - return alloc_dl_ue(u, res_grid, pdsch_alloc, true, true, logger, expert_cfg); + auto srb_retx_ue_function = [this, &res_grid, &pdsch_alloc, slice_id](const slice_ue& u) { + return alloc_dl_ue(u, res_grid, pdsch_alloc, true, true, logger, slice_id); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_retx_ue_function); @@ -413,25 +414,25 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Second, schedule UEs with SRB data new transmission. auto srb_newtx_ue_function = - [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { + [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { return alloc_dl_ue( - u, res_grid, pdsch_alloc, false, true, logger, expert_cfg, dl_new_tx_max_nof_rbs_per_ue_per_slot); + u, res_grid, pdsch_alloc, false, true, logger, slice_id, dl_new_tx_max_nof_rbs_per_ue_per_slot); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_newtx_ue_function); } // Third, schedule UEs with DRB re-transmissions. - auto drb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const slice_ue& u) { - return alloc_dl_ue(u, res_grid, pdsch_alloc, true, false, logger, expert_cfg); + auto drb_retx_ue_function = [this, &res_grid, &pdsch_alloc, slice_id](const slice_ue& u) { + return alloc_dl_ue(u, res_grid, pdsch_alloc, true, false, logger, slice_id); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_retx_ue_function); if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Then, schedule UEs with DRB new transmissions. auto drb_newtx_ue_function = - [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { + [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { return alloc_dl_ue( - u, res_grid, pdsch_alloc, false, false, logger, expert_cfg, dl_new_tx_max_nof_rbs_per_ue_per_slot); + u, res_grid, pdsch_alloc, false, false, logger, slice_id, dl_new_tx_max_nof_rbs_per_ue_per_slot); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); } @@ -441,8 +442,9 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, ul_ran_slice_candidate& slice_candidate) { - const slice_ue_repository& ues = slice_candidate.get_slice_ues(); - const unsigned max_rbs = slice_candidate.remaining_rbs(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); + const unsigned max_rbs = slice_candidate.remaining_rbs(); + const ran_slice_id_t slice_id = slice_candidate.id(); if (ues.empty() or max_rbs == 0) { // No UEs to be scheduled or if there are no RBs to be scheduled in slice. @@ -452,31 +454,31 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. - auto sr_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { - return alloc_ul_ue(u, res_grid, pusch_alloc, false, true, false, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); + auto sr_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, false, true, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Second, schedule UEs with SRB data new transmissions. - auto srb_newtx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot]( + auto srb_newtx_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id]( const slice_ue& u) { - return alloc_ul_ue(u, res_grid, pusch_alloc, false, false, true, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); + return alloc_ul_ue(u, pusch_alloc, false, false, true, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, srb_newtx_ue_function); } // Third, schedule UEs with re-transmissions. - auto data_retx_ue_function = [this, &res_grid, &pusch_alloc](const slice_ue& u) { - return alloc_ul_ue(u, res_grid, pusch_alloc, true, false, false, logger); + auto data_retx_ue_function = [this, &pusch_alloc, slice_id](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, true, false, false, logger, slice_id); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); // Then, schedule UEs with new transmissions. if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - auto data_tx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot]( + auto data_tx_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id]( const slice_ue& u) { - return alloc_ul_ue(u, res_grid, pusch_alloc, false, false, false, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); + return alloc_ul_ue(u, pusch_alloc, false, false, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); } diff --git a/lib/scheduler/policy/ue_allocator.h b/lib/scheduler/policy/ue_allocator.h index 77de875655..f30e9fbb71 100644 --- a/lib/scheduler/policy/ue_allocator.h +++ b/lib/scheduler/policy/ue_allocator.h @@ -24,6 +24,7 @@ struct ue_pdsch_grant { const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; + ran_slice_id_t slice_id; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. std::optional recommended_nof_bytes; /// Maximum nof. RBs to allocate to the UE. This field is not present/ignored in case of HARQ retransmission. @@ -35,6 +36,7 @@ struct ue_pusch_grant { const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; + ran_slice_id_t slice_id; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. std::optional recommended_nof_bytes; /// Maximum nof. RBs to allocate to the UE. This field is not present/ignored in case of HARQ retransmission. diff --git a/lib/scheduler/ue_scheduling/harq_process.cpp b/lib/scheduler/ue_scheduling/harq_process.cpp index 41f56e0e30..bf2142d215 100644 --- a/lib/scheduler/ue_scheduling/harq_process.cpp +++ b/lib/scheduler/ue_scheduling/harq_process.cpp @@ -289,6 +289,7 @@ void dl_harq_process::save_alloc_params(const dl_harq_sched_context& ctx, prev_tx_params.tb[tb_idx]->tbs_bytes = cw.tb_size_bytes; prev_tx_params.tb[tb_idx]->olla_mcs = ctx.olla_mcs; prev_tx_params.tb[tb_idx]->contains_srb_data = contains_srb_data; + prev_tx_params.tb[tb_idx]->slice_id = ctx.slice_id; } else { srsran_assert(ctx.dci_cfg_type == prev_tx_params.dci_cfg_type, "DCI format and RNTI type cannot change during DL HARQ retxs"); @@ -363,6 +364,7 @@ void ul_harq_process::save_alloc_params(const ul_harq_sched_context& ctx, const prev_tx_params.dci_cfg_type = ctx.dci_cfg_type; prev_tx_params.olla_mcs = ctx.olla_mcs; prev_tx_params.tbs_bytes = pusch.tb_size_bytes; + prev_tx_params.slice_id = ctx.slice_id; } else { srsran_assert(ctx.dci_cfg_type == prev_tx_params.dci_cfg_type, "DCI format and RNTI type cannot change during HARQ retxs"); diff --git a/lib/scheduler/ue_scheduling/harq_process.h b/lib/scheduler/ue_scheduling/harq_process.h index 8c6148290f..16540c6e69 100644 --- a/lib/scheduler/ue_scheduling/harq_process.h +++ b/lib/scheduler/ue_scheduling/harq_process.h @@ -10,6 +10,7 @@ #pragma once +#include "../slicing/ran_slice_id.h" #include "srsran/adt/static_vector.h" #include "srsran/ran/csi_report/csi_report_data.h" #include "srsran/ran/pdsch/pdsch_mcs.h" @@ -255,6 +256,8 @@ struct dl_harq_sched_context { dci_dl_rnti_config_type dci_cfg_type; /// MCS suggested by the OLLA. std::optional olla_mcs; + /// RAN slice identifier of the slice to which PDSCH belongs to. + std::optional slice_id; }; class dl_harq_process : public detail::harq_process @@ -273,6 +276,8 @@ class dl_harq_process : public detail::harq_process unsigned tbs_bytes; /// Flag indicating whether the TB contains data from SRB or not. bool contains_srb_data; + /// RAN slice identifier. + std::optional slice_id; /// \brief MCS originally suggested by the OLLA. It might differ from the actual MCS used. std::optional olla_mcs; }; @@ -364,6 +369,8 @@ struct ul_harq_sched_context { dci_ul_rnti_config_type dci_cfg_type; /// MCS suggested by the OLLA. std::optional olla_mcs; + /// RAN slice identifier of the slice to which PUSCH belongs to. + std::optional slice_id; }; class ul_harq_process : private detail::harq_process @@ -373,13 +380,14 @@ class ul_harq_process : private detail::harq_process public: /// \brief Parameters relative to the last allocated PUSCH PDU for this HARQ process. struct alloc_params { - dci_ul_rnti_config_type dci_cfg_type; - vrb_alloc rbs; - pusch_mcs_table mcs_table; - sch_mcs_index mcs; - unsigned tbs_bytes; - unsigned nof_symbols; - std::optional olla_mcs; + dci_ul_rnti_config_type dci_cfg_type; + vrb_alloc rbs; + pusch_mcs_table mcs_table; + sch_mcs_index mcs; + unsigned tbs_bytes; + unsigned nof_symbols; + std::optional slice_id; + std::optional olla_mcs; }; using base_type::transport_block; diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index ec264cfac4..9cf8e53552 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -461,6 +461,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra if (is_new_data) { pdsch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_dl_mcs(msg.pdsch_cfg.codewords[0].mcs_table); + pdsch_sched_ctx.slice_id = grant.slice_id; } ue_cc->last_pdsch_allocated_slot = pdsch_alloc.slot; @@ -980,6 +981,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra pusch_sched_ctx.dci_cfg_type = pdcch->dci.type; if (is_new_data) { pusch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_ul_mcs(msg.pusch_cfg.mcs_table); + pusch_sched_ctx.slice_id = grant.slice_id; } ue_cc->last_pusch_allocated_slot = pusch_alloc.slot; From 6324a6224eea754d177ae39cf56bbad0baa6b21d Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 6 Aug 2024 16:30:06 +0200 Subject: [PATCH 161/407] sched: schedule HARQ retx based on stored RAN slice ID --- lib/scheduler/policy/scheduler_time_pf.cpp | 120 ++++++++------------- lib/scheduler/policy/scheduler_time_pf.h | 8 +- lib/scheduler/policy/scheduler_time_rr.cpp | 78 ++++---------- 3 files changed, 68 insertions(+), 138 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index cf27997c65..c3f65a1253 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -40,7 +40,7 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, ue_history_db.emplace(u.ue_index(), ue_ctxt{u.ue_index(), u.get_pcell().cell_index, this}); } ue_ctxt& ctxt = ue_history_db[u.ue_index()]; - ctxt.compute_dl_prio(u); + ctxt.compute_dl_prio(u, slice_candidate.id()); dl_queue.push(&ctxt); } @@ -85,7 +85,7 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, ue_history_db.emplace(u.ue_index(), ue_ctxt{u.ue_index(), u.get_pcell().cell_index, this}); } ue_ctxt& ctxt = ue_history_db[u.ue_index()]; - ctxt.compute_ul_prio(u, res_grid); + ctxt.compute_ul_prio(u, res_grid, slice_candidate.id()); ul_queue.push(&ctxt); } @@ -130,8 +130,7 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, if (ctxt.dl_newtx_h != nullptr) { grant.h_id = ctxt.dl_newtx_h->id; - grant.recommended_nof_bytes = ctxt.dl_newtx_srb_pending_bytes > 0 ? ctxt.dl_newtx_srb_pending_bytes - : ues[ctxt.ue_index].pending_dl_newtx_bytes(); + grant.recommended_nof_bytes = ues[ctxt.ue_index].pending_dl_newtx_bytes(); grant.max_nof_rbs = max_rbs; alloc_result = pdsch_alloc.allocate_dl_grant(grant); if (alloc_result.status == alloc_status::success) { @@ -166,8 +165,7 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, if (ctxt.ul_newtx_h != nullptr) { grant.h_id = ctxt.ul_newtx_h->id; - grant.recommended_nof_bytes = ctxt.ul_newtx_srb_pending_bytes > 0 ? ctxt.ul_newtx_srb_pending_bytes - : ues[ctxt.ue_index].pending_ul_newtx_bytes(); + grant.recommended_nof_bytes = ues[ctxt.ue_index].pending_ul_newtx_bytes(); grant.max_nof_rbs = max_rbs; alloc_result = pusch_alloc.allocate_ul_grant(grant); if (alloc_result.status == alloc_status::success) { @@ -181,33 +179,32 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u) +void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id_t slice_id) { - dl_retx_h = nullptr; - dl_newtx_h = nullptr; - dl_prio = 0; - dl_newtx_srb_pending_bytes = 0; - const ue_cell* ue_cc = u.find_cell(cell_index); + dl_retx_h = nullptr; + dl_newtx_h = nullptr; + dl_prio = 0; + const ue_cell* ue_cc = u.find_cell(cell_index); if (ue_cc == nullptr or not ue_cc->is_active() or ue_cc->is_in_fallback_mode()) { return; } - // Find DL HARQ with transport block containing SRB data to retransmit. - const dl_harq_process* srb_retx_h = nullptr; + static_vector dl_harq_candidates; + // Create list of DL HARQ processes with pending retx, sorted from oldest to newest. for (unsigned i = 0; i != ue_cc->harqs.nof_dl_harqs(); ++i) { const dl_harq_process& h = ue_cc->harqs.dl_harq(i); if (h.has_pending_retx() and not h.last_alloc_params().is_fallback and - h.last_alloc_params().tb[0]->contains_srb_data) { - srb_retx_h = &h; - break; + h.last_alloc_params().tb[0]->slice_id == slice_id) { + dl_harq_candidates.push_back(&h); } } + std::sort(dl_harq_candidates.begin(), + dl_harq_candidates.end(), + [](const dl_harq_process* lhs, const dl_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); // Calculate DL priority. - dl_retx_h = srb_retx_h != nullptr ? srb_retx_h : ue_cc->harqs.find_pending_dl_retx(); + dl_retx_h = dl_harq_candidates.empty() ? nullptr : dl_harq_candidates.front(); dl_newtx_h = ue_cc->harqs.find_empty_dl_harq(); - // NOTE: Only if the slice is an SRB slice then \c dl_newtx_srb_pending_bytes will be > 0. - dl_newtx_srb_pending_bytes = u.pending_dl_newtx_bytes(); if (dl_retx_h != nullptr or (dl_newtx_h != nullptr and u.has_pending_dl_newtx_bytes())) { // NOTE: It does not matter whether it's a reTx or newTx since DL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. @@ -258,26 +255,36 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u) dl_newtx_h = nullptr; } -void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid) +void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, + const ue_resource_grid_view& res_grid, + ran_slice_id_t slice_id) { - ul_retx_h = nullptr; - ul_newtx_h = nullptr; - ul_prio = 0; - sr_ind_received = false; - ul_newtx_srb_pending_bytes = 0; - const ue_cell* ue_cc = u.find_cell(cell_index); + ul_retx_h = nullptr; + ul_newtx_h = nullptr; + ul_prio = 0; + sr_ind_received = false; + const ue_cell* ue_cc = u.find_cell(cell_index); if (ue_cc == nullptr or not ue_cc->is_active() or ue_cc->is_in_fallback_mode()) { return; } + static_vector ul_harq_candidates; + // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. + for (unsigned i = 0; i != ue_cc->harqs.nof_ul_harqs(); ++i) { + const ul_harq_process& h = ue_cc->harqs.ul_harq(i); + if (h.has_pending_retx() and h.last_tx_params().slice_id == slice_id) { + ul_harq_candidates.push_back(&h); + } + } + std::sort(ul_harq_candidates.begin(), + ul_harq_candidates.end(), + [](const ul_harq_process* lhs, const ul_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); + // Calculate UL priority. - ul_retx_h = ue_cc->harqs.find_pending_ul_retx(); - ul_newtx_h = ue_cc->harqs.find_empty_ul_harq(); - sr_ind_received = u.has_pending_sr(); - unsigned pending_bytes = u.pending_ul_newtx_bytes(); - // NOTE: Only if the slice is an SRB slice or has SR pending then \c dl_newtx_srb_pending_bytes will be > 0. - ul_newtx_srb_pending_bytes = pending_bytes; - if (ul_retx_h != nullptr or (ul_newtx_h != nullptr and pending_bytes > 0)) { + ul_retx_h = ul_harq_candidates.empty() ? nullptr : ul_harq_candidates.front(); + ul_newtx_h = ue_cc->harqs.find_empty_ul_harq(); + sr_ind_received = u.has_pending_sr(); + if (ul_retx_h != nullptr or (ul_newtx_h != nullptr and u.pending_ul_newtx_bytes() > 0)) { // NOTE: It does not matter whether it's a reTx or newTx since UL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. // [Implementation-defined] We consider only the SearchSpace defined in UE dedicated configuration. @@ -361,36 +368,8 @@ bool scheduler_time_pf::ue_dl_prio_compare::operator()(const scheduler_time_pf:: { const bool is_lhs_retx = lhs->dl_retx_h != nullptr; const bool is_rhs_retx = rhs->dl_retx_h != nullptr; - const bool is_lhs_srb_retx = - lhs->dl_retx_h != nullptr and (lhs->dl_retx_h->last_alloc_params().tb[0]->contains_srb_data or - (lhs->dl_retx_h->last_alloc_params().tb[1].has_value() and - lhs->dl_retx_h->last_alloc_params().tb[1]->contains_srb_data)); - const bool is_rhs_srb_retx = - rhs->dl_retx_h != nullptr and (rhs->dl_retx_h->last_alloc_params().tb[0]->contains_srb_data or - (rhs->dl_retx_h->last_alloc_params().tb[1].has_value() and - rhs->dl_retx_h->last_alloc_params().tb[1]->contains_srb_data)); - - // First, prioritize UEs with SRB data re-transmissions. - // SRB HARQ retransmission in one UE and not in other UE. - if (is_lhs_srb_retx != is_rhs_srb_retx) { - return is_rhs_srb_retx; - } - // SRB HARQ retransmission in both UEs. - if (is_lhs_srb_retx) { - return lhs->dl_prio < rhs->dl_prio; - } - // Second, prioritize UEs with SRB data new transmission. - // SRB HARQ newTx in one UE and not in other UE. - const bool lhs_has_dl_newtx_srb_pending_bytes = lhs->dl_newtx_srb_pending_bytes > 0; - const bool rhs_has_dl_newtx_srb_pending_bytes = rhs->dl_newtx_srb_pending_bytes > 0; - if (lhs_has_dl_newtx_srb_pending_bytes != rhs_has_dl_newtx_srb_pending_bytes) { - return rhs_has_dl_newtx_srb_pending_bytes; - } - // SRB HARQ newTx in both UEs. - if (lhs_has_dl_newtx_srb_pending_bytes) { - return lhs->dl_prio < rhs->dl_prio; - } - // Third, prioritize UEs with DRB re-transmissions. + + // First, prioritize UEs with re-transmissions. // ReTx in one UE and not in other UE. if (is_lhs_retx != is_rhs_retx) { return is_rhs_retx; @@ -413,18 +392,7 @@ bool scheduler_time_pf::ue_ul_prio_compare::operator()(const scheduler_time_pf:: if (lhs->sr_ind_received) { return lhs->ul_prio < rhs->ul_prio; } - // Second, prioritize UEs with SRB data new transmissions. - // SRB data newTx in one UE and not in other UE. - const bool lhs_has_ul_newtx_srb_pending_bytes = lhs->ul_newtx_srb_pending_bytes > 0; - const bool rhs_has_ul_newtx_srb_pending_bytes = rhs->ul_newtx_srb_pending_bytes > 0; - if (lhs_has_ul_newtx_srb_pending_bytes != rhs_has_ul_newtx_srb_pending_bytes) { - return rhs_has_ul_newtx_srb_pending_bytes; - } - // SRB data newTx in both UEs. - if (lhs_has_ul_newtx_srb_pending_bytes) { - return lhs->ul_prio < rhs->ul_prio; - } - // Third, prioritize UEs with re-transmissions. + // Second, prioritize UEs with re-transmissions. // ReTx in one UE and not in other UE. if (is_lhs_retx != is_rhs_retx) { return is_rhs_retx; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index 29a532b165..09e09bc637 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -44,8 +44,8 @@ class scheduler_time_pf : public scheduler_policy /// Returns average UL rate expressed in bytes per slot. [[nodiscard]] double ul_avg_rate() const { return ul_nof_samples == 0 ? 0 : ul_avg_rate_; } - void compute_dl_prio(const slice_ue& u); - void compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid); + void compute_dl_prio(const slice_ue& u, ran_slice_id_t slice_id); + void compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid, ran_slice_id_t slice_id); void save_dl_alloc(uint32_t alloc_bytes); void save_ul_alloc(uint32_t alloc_bytes); @@ -63,10 +63,6 @@ class scheduler_time_pf : public scheduler_policy const dl_harq_process* dl_newtx_h = nullptr; const ul_harq_process* ul_retx_h = nullptr; const ul_harq_process* ul_newtx_h = nullptr; - /// Number of pending newTx bytes in SRBs in DL to be scheduled. - unsigned dl_newtx_srb_pending_bytes = 0; - /// Number of pending newTx bytes in SRBs in UL to be scheduled. - unsigned ul_newtx_srb_pending_bytes = 0; /// Flag indicating whether SR indication from the UE is received or not. bool sr_ind_received = false; diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index aa24a9b516..785f8b50ad 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -118,10 +118,10 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& } /// \brief Fetches list of DL HARQ candidates to schedule. -static static_vector get_ue_dl_harq_candidates(const slice_ue& ue_ref, - ue_cell_index_t cell_index, - bool is_retx, - bool ue_with_srb_data_only, +static static_vector get_ue_dl_harq_candidates(const slice_ue& ue_ref, + ue_cell_index_t cell_index, + bool is_retx, + ran_slice_id_t slice_id, srslog::basic_logger& logger) { static_vector dl_harq_candidates; @@ -135,7 +135,7 @@ static static_vector get_ue_dl_harq_candi for (unsigned i = 0; i != ue_cc.harqs.nof_dl_harqs(); ++i) { const dl_harq_process& h = ue_cc.harqs.dl_harq(i); if (h.has_pending_retx() and not h.last_alloc_params().is_fallback and - (not ue_with_srb_data_only or (h.last_alloc_params().tb[0]->contains_srb_data))) { + h.last_alloc_params().tb[0]->slice_id == slice_id) { dl_harq_candidates.push_back(&h); } } @@ -178,6 +178,7 @@ static static_vector get_ue_dl_harq_candi static static_vector get_ue_ul_harq_candidates(const slice_ue& ue_ref, ue_cell_index_t cell_index, bool is_retx, + ran_slice_id_t slice_id, srslog::basic_logger& logger) { static_vector ul_harq_candidates; @@ -190,7 +191,7 @@ static static_vector get_ue_ul_harq_candi // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { const ul_harq_process& h = ue_cc.harqs.ul_harq(i); - if (h.has_pending_retx()) { + if (h.has_pending_retx() and h.last_tx_params().slice_id == slice_id) { ul_harq_candidates.push_back(&h); } } @@ -270,15 +271,11 @@ static alloc_result alloc_dl_ue(const slice_ue& u, const ue_resource_grid_view& res_grid, ue_pdsch_allocator& pdsch_alloc, bool is_retx, - bool ue_with_srb_data_only, srslog::basic_logger& logger, ran_slice_id_t slice_id, std::optional dl_new_tx_max_nof_rbs_per_ue_per_slot = {}) { if (not is_retx) { - if (ue_with_srb_data_only and not u.has_srb_bearers_in_slice()) { - return {alloc_status::skip_ue}; - } if (not u.has_pending_dl_newtx_bytes()) { return {alloc_status::skip_ue}; } @@ -300,8 +297,7 @@ static alloc_result alloc_dl_ue(const slice_ue& u, } // Get DL HARQ candidates. - const auto harq_candidates = - get_ue_dl_harq_candidates(u, to_ue_cell_index(i), is_retx, ue_with_srb_data_only, logger); + const auto harq_candidates = get_ue_dl_harq_candidates(u, to_ue_cell_index(i), is_retx, slice_id, logger); if (harq_candidates.empty()) { // The conditions for a new PDSCH allocation for this UE were not met (e.g. lack of available HARQs). continue; @@ -329,7 +325,6 @@ static alloc_result alloc_ul_ue(const slice_ue& u, ue_pusch_allocator& pusch_alloc, bool is_retx, bool schedule_sr_only, - bool ue_with_srb_data_only, srslog::basic_logger& logger, ran_slice_id_t slice_id, std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) @@ -340,9 +335,6 @@ static alloc_result alloc_ul_ue(const slice_ue& u, return {alloc_status::skip_ue}; } pending_newtx_bytes = u.pending_ul_newtx_bytes(); - if (ue_with_srb_data_only and not u.has_srb_bearers_in_slice()) { - return {alloc_status::skip_ue}; - } if (pending_newtx_bytes == 0) { return {alloc_status::skip_ue}; } @@ -357,7 +349,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, } // Get UL HARQ candidates. - const auto harq_candidates = get_ue_ul_harq_candidates(u, to_ue_cell_index(i), is_retx, logger); + const auto harq_candidates = get_ue_ul_harq_candidates(u, to_ue_cell_index(i), is_retx, slice_id, logger); if (harq_candidates.empty()) { // The conditions for a new PUSCH allocation for this UE were not met (e.g. lack of available HARQs). continue; @@ -403,36 +395,19 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, return; } - // First, schedule UEs with SRB data re-transmissions. - auto srb_retx_ue_function = [this, &res_grid, &pdsch_alloc, slice_id](const slice_ue& u) { - return alloc_dl_ue(u, res_grid, pdsch_alloc, true, true, logger, slice_id); + // First, schedule UEs with re-transmissions. + auto retx_ue_function = [this, &res_grid, &pdsch_alloc, slice_id](const slice_ue& u) { + return alloc_dl_ue(u, res_grid, pdsch_alloc, true, logger, slice_id); }; - next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_retx_ue_function); + next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, retx_ue_function); const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg, max_rbs); if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - // Second, schedule UEs with SRB data new transmission. - auto srb_newtx_ue_function = - [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { - return alloc_dl_ue( - u, res_grid, pdsch_alloc, false, true, logger, slice_id, dl_new_tx_max_nof_rbs_per_ue_per_slot); - }; - next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_newtx_ue_function); - } - - // Third, schedule UEs with DRB re-transmissions. - auto drb_retx_ue_function = [this, &res_grid, &pdsch_alloc, slice_id](const slice_ue& u) { - return alloc_dl_ue(u, res_grid, pdsch_alloc, true, false, logger, slice_id); - }; - next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_retx_ue_function); - - if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - // Then, schedule UEs with DRB new transmissions. + // Then, schedule UEs with new transmissions. auto drb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { - return alloc_dl_ue( - u, res_grid, pdsch_alloc, false, false, logger, slice_id, dl_new_tx_max_nof_rbs_per_ue_per_slot); + return alloc_dl_ue(u, res_grid, pdsch_alloc, false, logger, slice_id, dl_new_tx_max_nof_rbs_per_ue_per_slot); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); } @@ -455,31 +430,22 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. auto sr_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, false, true, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); + return alloc_ul_ue(u, pusch_alloc, false, true, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); - if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - // Second, schedule UEs with SRB data new transmissions. - auto srb_newtx_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id]( - const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, false, false, true, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); - }; - next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, srb_newtx_ue_function); - } - - // Third, schedule UEs with re-transmissions. + // Second, schedule UEs with re-transmissions. auto data_retx_ue_function = [this, &pusch_alloc, slice_id](const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, true, false, false, logger, slice_id); + return alloc_ul_ue(u, pusch_alloc, true, false, logger, slice_id); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); // Then, schedule UEs with new transmissions. if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - auto data_tx_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id]( - const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, false, false, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); - }; + auto data_tx_ue_function = + [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, false, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); + }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); } } From 33b3ddd5c149e6682b9d98d288f54b52f5272290 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 7 Aug 2024 10:30:14 +0200 Subject: [PATCH 162/407] sched: remove flag indicating whether HARQ TB consists of SRB data or not --- lib/scheduler/ue_scheduling/harq_process.cpp | 15 ++++----------- lib/scheduler/ue_scheduling/harq_process.h | 5 +---- .../ue_scheduling/ue_cell_grid_allocator.cpp | 14 +------------- .../ue_scheduling/ue_fallback_scheduler.cpp | 2 +- 4 files changed, 7 insertions(+), 29 deletions(-) diff --git a/lib/scheduler/ue_scheduling/harq_process.cpp b/lib/scheduler/ue_scheduling/harq_process.cpp index bf2142d215..45f9757726 100644 --- a/lib/scheduler/ue_scheduling/harq_process.cpp +++ b/lib/scheduler/ue_scheduling/harq_process.cpp @@ -195,8 +195,6 @@ void dl_harq_process::new_tx(slot_point pdsch_slot, prev_tx_params.nof_layers = nof_layers; prev_tx_params.is_fallback = is_fallback_; prev_tx_params.tb[0].emplace(); - // NOTE: Correct value will be set when \c save_alloc_params is called. - prev_tx_params.tb[0]->contains_srb_data = false; prev_tx_params.tb[1].reset(); pucch_ack_to_receive = 0; chosen_ack = mac_harq_ack_report_status::dtx; @@ -227,8 +225,6 @@ void dl_harq_process::tx_2_tb(slot_point pdsch_slot, if (tb_tx_req[i] == tb_tx_request::newtx) { base_type::new_tx_tb_common(i, max_harq_nof_retxs, harq_bit_idx); prev_tx_params.tb[i].emplace(); - // NOTE: Correct value will be set when \c save_alloc_params is called. - prev_tx_params.tb[i]->contains_srb_data = false; } else if (tb_tx_req[i] == tb_tx_request::retx) { base_type::new_retx_tb_common(i, harq_bit_idx); } else { @@ -276,9 +272,7 @@ dl_harq_process::ack_info(uint32_t tb_idx, mac_harq_ack_report_status ack, std:: return status_update::no_update; } -void dl_harq_process::save_alloc_params(const dl_harq_sched_context& ctx, - const pdsch_information& pdsch, - bool contains_srb_data) +void dl_harq_process::save_alloc_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) { unsigned tb_idx = empty(0) ? 1 : 0; for (const pdsch_codeword& cw : pdsch.codewords) { @@ -286,10 +280,9 @@ void dl_harq_process::save_alloc_params(const dl_harq_sched_context& ctx, prev_tx_params.tb[tb_idx]->mcs_table = cw.mcs_table; prev_tx_params.tb[tb_idx]->mcs = cw.mcs_index; if (tb(tb_idx).nof_retxs == 0) { - prev_tx_params.tb[tb_idx]->tbs_bytes = cw.tb_size_bytes; - prev_tx_params.tb[tb_idx]->olla_mcs = ctx.olla_mcs; - prev_tx_params.tb[tb_idx]->contains_srb_data = contains_srb_data; - prev_tx_params.tb[tb_idx]->slice_id = ctx.slice_id; + prev_tx_params.tb[tb_idx]->tbs_bytes = cw.tb_size_bytes; + prev_tx_params.tb[tb_idx]->olla_mcs = ctx.olla_mcs; + prev_tx_params.tb[tb_idx]->slice_id = ctx.slice_id; } else { srsran_assert(ctx.dci_cfg_type == prev_tx_params.dci_cfg_type, "DCI format and RNTI type cannot change during DL HARQ retxs"); diff --git a/lib/scheduler/ue_scheduling/harq_process.h b/lib/scheduler/ue_scheduling/harq_process.h index 16540c6e69..024f491036 100644 --- a/lib/scheduler/ue_scheduling/harq_process.h +++ b/lib/scheduler/ue_scheduling/harq_process.h @@ -274,8 +274,6 @@ class dl_harq_process : public detail::harq_process pdsch_mcs_table mcs_table; sch_mcs_index mcs; unsigned tbs_bytes; - /// Flag indicating whether the TB contains data from SRB or not. - bool contains_srb_data; /// RAN slice identifier. std::optional slice_id; /// \brief MCS originally suggested by the OLLA. It might differ from the actual MCS used. @@ -347,8 +345,7 @@ class dl_harq_process : public detail::harq_process /// \brief Stores grant parameters that are associated with the HARQ allocation (e.g. DCI format, PRBs, MCS) so that /// they can be later fetched and optionally reused. - void - save_alloc_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch, bool contains_srb_data = false); + void save_alloc_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch); void increment_pucch_counter(); diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 9cf8e53552..702b2fa720 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -474,19 +474,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra msg.context.buffer_occupancy = u.pending_dl_newtx_bytes(); } - bool contains_srb_data = false; - if (is_new_data) { - const auto* it = std::find_if(msg.tb_list.back().lc_chs_to_sched.begin(), - msg.tb_list.back().lc_chs_to_sched.end(), - [](const dl_msg_lc_info& lc_info) { - return lc_info.lcid.is_sdu() and lc_info.lcid.to_lcid() < LCID_MIN_DRB; - }); - contains_srb_data = it != msg.tb_list.back().lc_chs_to_sched.end(); - } else { - contains_srb_data = h_dl.last_alloc_params().tb[0]->contains_srb_data; - } - - h_dl.save_alloc_params(pdsch_sched_ctx, msg.pdsch_cfg, contains_srb_data); + h_dl.save_alloc_params(pdsch_sched_ctx, msg.pdsch_cfg); return {alloc_status::success, h_dl.last_alloc_params().tb[0]->tbs_bytes, crbs.length()}; } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 9872a31e64..8617791197 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1242,7 +1242,7 @@ unsigned ue_fallback_scheduler::fill_dl_srb_grant(ue& u, } // Save in HARQ the parameters set for this PDCCH and PDSCH PDUs. - h_dl.save_alloc_params(dl_harq_sched_context{pdcch.dci.type}, msg.pdsch_cfg, true); + h_dl.save_alloc_params(dl_harq_sched_context{pdcch.dci.type}, msg.pdsch_cfg); return srb1_bytes_allocated; } From db08aa55da5d696fa3c86fd114a540a2b56a21f4 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 8 Aug 2024 11:52:11 +0200 Subject: [PATCH 163/407] sched: refactor RAN slice Id being passed to cell grid allocator --- lib/scheduler/policy/scheduler_time_pf.cpp | 12 +-- lib/scheduler/policy/scheduler_time_pf.h | 14 +--- lib/scheduler/policy/scheduler_time_rr.cpp | 4 +- lib/scheduler/policy/ue_allocator.h | 2 - .../ue_scheduling/ue_cell_grid_allocator.cpp | 8 +- .../ue_scheduling/ue_cell_grid_allocator.h | 22 ++--- .../ue_scheduling/ue_grid_allocator_test.cpp | 84 ++++++++++++------- 7 files changed, 78 insertions(+), 68 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index c3f65a1253..5b33c706bf 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -49,7 +49,7 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, while (not dl_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *dl_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_dl_alloc(ue, ues, pdsch_alloc, rem_rbs, slice_candidate.id()); + alloc_result = try_dl_alloc(ue, ues, pdsch_alloc, rem_rbs); } ue.save_dl_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -94,7 +94,7 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, while (not ul_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *ul_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs, slice_candidate.id()); + alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs); } ue.save_ul_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -110,12 +110,10 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, - unsigned max_rbs, - ran_slice_id_t slice_id) + unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; ue_pdsch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; - grant.slice_id = slice_id; // Prioritize reTx over newTx. if (ctxt.dl_retx_h != nullptr) { grant.h_id = ctxt.dl_retx_h->id; @@ -145,12 +143,10 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, - unsigned max_rbs, - ran_slice_id_t slice_id) + unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; - grant.slice_id = slice_id; // Prioritize reTx over newTx. if (ctxt.ul_retx_h != nullptr) { grant.h_id = ctxt.ul_retx_h->id; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index 09e09bc637..c2ddd50fdb 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -79,18 +79,12 @@ class scheduler_time_pf : public scheduler_policy /// \brief Attempts to allocate PDSCH for a UE. /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. - alloc_result try_dl_alloc(ue_ctxt& ctxt, - const slice_ue_repository& ues, - ue_pdsch_allocator& pdsch_alloc, - unsigned max_rbs, - ran_slice_id_t slice_id); + alloc_result + try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, unsigned max_rbs); /// \brief Attempts to allocate PUSCH for a UE. /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. - alloc_result try_ul_alloc(ue_ctxt& ctxt, - const slice_ue_repository& ues, - ue_pusch_allocator& pusch_alloc, - unsigned max_rbs, - ran_slice_id_t slice_id); + alloc_result + try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, unsigned max_rbs); slotted_id_table ue_history_db; diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 785f8b50ad..90cbd62727 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -305,7 +305,7 @@ static alloc_result alloc_dl_ue(const slice_ue& u, // Iterate through allocation parameter candidates. for (const dl_harq_process* h_dl : harq_candidates) { - ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl->id, slice_id}; + ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl->id}; if (not is_retx) { grant.recommended_nof_bytes = u.pending_dl_newtx_bytes(); grant.max_nof_rbs = dl_new_tx_max_nof_rbs_per_ue_per_slot; @@ -357,7 +357,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, // Iterate through allocation parameter candidates. for (const ul_harq_process* h_ul : harq_candidates) { - ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id, slice_id}; + ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id}; if (not is_retx) { grant.recommended_nof_bytes = pending_newtx_bytes; grant.max_nof_rbs = ul_new_tx_max_nof_rbs_per_ue_per_slot; diff --git a/lib/scheduler/policy/ue_allocator.h b/lib/scheduler/policy/ue_allocator.h index f30e9fbb71..77de875655 100644 --- a/lib/scheduler/policy/ue_allocator.h +++ b/lib/scheduler/policy/ue_allocator.h @@ -24,7 +24,6 @@ struct ue_pdsch_grant { const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; - ran_slice_id_t slice_id; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. std::optional recommended_nof_bytes; /// Maximum nof. RBs to allocate to the UE. This field is not present/ignored in case of HARQ retransmission. @@ -36,7 +35,6 @@ struct ue_pusch_grant { const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; - ran_slice_id_t slice_id; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. std::optional recommended_nof_bytes; /// Maximum nof. RBs to allocate to the UE. This field is not present/ignored in case of HARQ retransmission. diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 702b2fa720..2ef9e2dfda 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -58,7 +58,7 @@ void ue_cell_grid_allocator::slot_indication(slot_point sl) } } -alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& grant) +alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& grant, ran_slice_id_t slice_id) { srsran_assert(ues.contains(grant.user->ue_index()), "Invalid UE candidate index={}", grant.user->ue_index()); srsran_assert(has_cell(grant.cell_index), "Invalid UE candidate cell_index={}", grant.cell_index); @@ -461,7 +461,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra if (is_new_data) { pdsch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_dl_mcs(msg.pdsch_cfg.codewords[0].mcs_table); - pdsch_sched_ctx.slice_id = grant.slice_id; + pdsch_sched_ctx.slice_id = slice_id; } ue_cc->last_pdsch_allocated_slot = pdsch_alloc.slot; @@ -483,7 +483,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra return {alloc_status::invalid_params}; } -alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant) +alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice_id_t slice_id) { srsran_assert(ues.contains(grant.user->ue_index()), "Invalid UE candidate index={}", grant.user->ue_index()); srsran_assert(has_cell(grant.cell_index), "Invalid UE candidate cell_index={}", grant.cell_index); @@ -969,7 +969,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra pusch_sched_ctx.dci_cfg_type = pdcch->dci.type; if (is_new_data) { pusch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_ul_mcs(msg.pusch_cfg.mcs_table); - pusch_sched_ctx.slice_id = grant.slice_id; + pusch_sched_ctx.slice_id = slice_id; } ue_cc->last_pusch_allocated_slot = pusch_alloc.slot; diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h index 39bf24b3f3..8c53424e62 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h @@ -19,9 +19,9 @@ namespace srsran { -/// This class implements the ue_pdsch_allocator and ue_pusch_allocator interfaces, namely the methods to allocate -/// PDSCH and PUSCH grants in different cells, and the methods to fetch the current gNB resource grid DL and UL states. -class ue_cell_grid_allocator : public ue_pdsch_allocator, public ue_pusch_allocator +/// This class implements the methods to allocate PDSCH and PUSCH grants in different cells for a slice, and the +/// methods to fetch the current gNB resource grid DL and UL states. +class ue_cell_grid_allocator { public: ue_cell_grid_allocator(const scheduler_ue_expert_config& expert_cfg_, @@ -38,9 +38,9 @@ class ue_cell_grid_allocator : public ue_pdsch_allocator, public ue_pusch_alloca void slot_indication(slot_point sl); - alloc_result allocate_dl_grant(const ue_pdsch_grant& grant) override; + alloc_result allocate_dl_grant(const ue_pdsch_grant& grant, ran_slice_id_t slice_id); - alloc_result allocate_ul_grant(const ue_pusch_grant& grant) override; + alloc_result allocate_ul_grant(const ue_pusch_grant& grant, ran_slice_id_t slice_id); private: struct cell_t { @@ -83,14 +83,14 @@ class ue_cell_grid_allocator : public ue_pdsch_allocator, public ue_pusch_alloca class dl_slice_ue_cell_grid_allocator : public ue_pdsch_allocator { public: - dl_slice_ue_cell_grid_allocator(ue_pdsch_allocator& pdsch_alloc_, dl_ran_slice_candidate& slice_candidate_) : + dl_slice_ue_cell_grid_allocator(ue_cell_grid_allocator& pdsch_alloc_, dl_ran_slice_candidate& slice_candidate_) : pdsch_alloc(pdsch_alloc_), slice_candidate(slice_candidate_) { } alloc_result allocate_dl_grant(const ue_pdsch_grant& grant) override { - const alloc_result result = pdsch_alloc.allocate_dl_grant(grant); + const alloc_result result = pdsch_alloc.allocate_dl_grant(grant, slice_candidate.id()); if (result.status == alloc_status::success) { slice_candidate.store_grant(result.alloc_nof_rbs); } @@ -98,7 +98,7 @@ class dl_slice_ue_cell_grid_allocator : public ue_pdsch_allocator } private: - ue_pdsch_allocator& pdsch_alloc; + ue_cell_grid_allocator& pdsch_alloc; dl_ran_slice_candidate& slice_candidate; }; @@ -107,14 +107,14 @@ class dl_slice_ue_cell_grid_allocator : public ue_pdsch_allocator class ul_slice_ue_cell_grid_allocator : public ue_pusch_allocator { public: - ul_slice_ue_cell_grid_allocator(ue_pusch_allocator& pusch_alloc_, ul_ran_slice_candidate& slice_candidate_) : + ul_slice_ue_cell_grid_allocator(ue_cell_grid_allocator& pusch_alloc_, ul_ran_slice_candidate& slice_candidate_) : pusch_alloc(pusch_alloc_), slice_candidate(slice_candidate_) { } alloc_result allocate_ul_grant(const ue_pusch_grant& grant) override { - const alloc_result result = pusch_alloc.allocate_ul_grant(grant); + const alloc_result result = pusch_alloc.allocate_ul_grant(grant, slice_candidate.id()); if (result.status == alloc_status::success) { slice_candidate.store_grant(result.alloc_nof_rbs); } @@ -122,7 +122,7 @@ class ul_slice_ue_cell_grid_allocator : public ue_pusch_allocator } private: - ue_pusch_allocator& pusch_alloc; + ue_cell_grid_allocator& pusch_alloc; ul_ran_slice_candidate& slice_candidate; }; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index f4ff0ce655..ad6dc3cb65 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -129,6 +129,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam ue_repository ues; slice_ue_repository slice_ues; + ran_slice_id_t dummy_slice_id{0}; ue_cell_grid_allocator alloc{expert_cfg, ues, logger}; slot_point current_slot; @@ -160,7 +161,8 @@ TEST_P(ue_grid_allocator_tester, .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); ASSERT_TRUE(crb_lims.contains(res_grid[0].result.dl.ue_grants.back().pdsch_cfg.rbs.type1())); } @@ -184,7 +186,8 @@ TEST_P(ue_grid_allocator_tester, when_using_non_fallback_dci_format_use_mcs_tabl .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); ASSERT_EQ(res_grid[0].result.dl.ue_grants.back().pdsch_cfg.codewords.back().mcs_table, srsran::pdsch_mcs_table::qam256); @@ -207,7 +210,8 @@ TEST_P(ue_grid_allocator_tester, allocates_pdsch_restricted_to_recommended_max_n .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); // Successfully allocates PDSCH corresponding to the grant. ASSERT_GE(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), @@ -231,7 +235,8 @@ TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_n .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH corresponding to the grant. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), grant1.max_nof_rbs); @@ -255,7 +260,8 @@ TEST_P(ue_grid_allocator_tester, does_not_allocate_pusch_with_all_remaining_rbs_ const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH corresponding to the grant. ASSERT_LT(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), cell_crbs.length()); @@ -283,8 +289,8 @@ TEST_P(ue_grid_allocator_tester, no_two_pdschs_are_allocated_in_same_slot_for_a_ .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { - return alloc.allocate_dl_grant(grant1).status == alloc_status::success or - alloc.allocate_dl_grant(grant2).status == alloc_status::success; + return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success or + alloc.allocate_dl_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); @@ -314,8 +320,8 @@ TEST_P(ue_grid_allocator_tester, no_two_puschs_are_allocated_in_same_slot_for_a_ .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { - return alloc.allocate_ul_grant(grant1).status == alloc_status::success or - alloc.allocate_ul_grant(grant2).status == alloc_status::success; + return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success or + alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); @@ -338,7 +344,8 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); slot_point last_pusch_alloc_slot = current_slot; @@ -350,7 +357,8 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant2).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); ASSERT_GT(current_slot, last_pusch_alloc_slot); } @@ -370,7 +378,8 @@ TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_in .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); slot_point last_pdsch_slot = current_slot; @@ -382,7 +391,8 @@ TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_in .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant2).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); ASSERT_GE(current_slot, last_pdsch_slot); } @@ -403,7 +413,8 @@ TEST_P(ue_grid_allocator_tester, .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); slot_point last_pdsch_ack_slot = current_slot + find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants)->context.k1; @@ -415,7 +426,8 @@ TEST_P(ue_grid_allocator_tester, .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant2).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); ASSERT_GE(current_slot + find_ue_pdsch(u.crnti, res_grid[0].result.dl.ue_grants)->context.k1, last_pdsch_ack_slot); } @@ -441,7 +453,8 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); // Ensure next PDSCH to be allocated slot is after wrap around of 1024 SFNs (large gap to last allocated PDSCH slot) // and current slot value is less than last allocated PDSCH slot. e.g. next PDSCH to be allocated slot=SFN 2, slot 2 @@ -456,8 +469,9 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant2).status == alloc_status::success; }, - nof_slot_until_pdsch_is_allocated_threshold)); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant2, dummy_slice_id).status == alloc_status::success; }, + nof_slot_until_pdsch_is_allocated_threshold)); } TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_gap_to_last_pusch_slot_allocated) @@ -481,7 +495,8 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga .h_id = to_harq_id(0), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); // Ensure next PUSCH to be allocated slot is after wrap around of 1024 SFNs (large gap to last allocated PUSCH slot) // and current slot value is less than last allocated PUSCH slot. e.g. next PUSCH to be allocated slot=SFN 2, slot 2 @@ -496,8 +511,9 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga .h_id = to_harq_id(1), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant2).status == alloc_status::success; }, - nof_slot_until_pusch_is_allocated_threshold)); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; }, + nof_slot_until_pusch_is_allocated_threshold)); } class ue_grid_allocator_remaining_rbs_alloc_tester : public ue_grid_allocator_tester @@ -539,8 +555,8 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_dl_rbs_are_alloca .recommended_nof_bytes = sched_bytes}; ASSERT_TRUE(run_until([&]() { - return alloc.allocate_dl_grant(grant1).status == alloc_status::success and - alloc.allocate_dl_grant(grant2).status == alloc_status::success; + return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success and + alloc.allocate_dl_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr and @@ -584,8 +600,8 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_ul_rbs_are_alloca .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { - return alloc.allocate_ul_grant(grant1).status == alloc_status::success and - alloc.allocate_ul_grant(grant2).status == alloc_status::success; + return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success and + alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr and find_ue_pusch(u2.crnti, res_grid[0].result.ul); @@ -633,7 +649,8 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); // Successfully allocates PDSCH. ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), @@ -659,7 +676,8 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); // Successfully allocates PDSCH. ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), @@ -685,7 +703,8 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), @@ -711,7 +730,8 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), @@ -760,7 +780,8 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_dl_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); // Successfully allocates PDSCH within RB limits. ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1(), pdsch_vrb_limits); @@ -784,7 +805,8 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE( + run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH within RB limits. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1(), pusch_vrb_limits); From 21b14595bda5d9e6851f8ad0faa988b729934961 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 9 Aug 2024 09:24:32 +0200 Subject: [PATCH 164/407] sched: minor refactor as per coding guidelines --- lib/scheduler/slicing/slice_ue_repository.cpp | 10 +++++----- lib/scheduler/ue_scheduling/ue.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index a6934ef840..0bfc372e1e 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -29,7 +29,7 @@ void slice_ue::rem_logical_channel(lcid_t lcid) lcg_id_t lcg_id_to_rem = get_lcg_id_for_bearer(lcid); srsran_assert(lcg_id_to_rem < MAX_NOF_LCGS, "Unable to fetch LCG ID for bearer with LCID={}", lcid); // Check whether there are bearers with same LCG ID. If not, remove LCG ID from slice. - for (unsigned lcid_idx = 0; lcid_idx < bearers.size(); ++lcid_idx) { + for (unsigned lcid_idx = 0, e = bearers.size(); lcid_idx != e; ++lcid_idx) { if (bearers.test(uint_to_lcid(lcid_idx))) { lcg_id_t other_lcg_id = get_lcg_id_for_bearer(uint_to_lcid(lcid_idx)); if (lcg_id_to_rem == other_lcg_id) { @@ -42,7 +42,7 @@ void slice_ue::rem_logical_channel(lcid_t lcid) bool slice_ue::has_pending_dl_newtx_bytes() const { - for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { + for (unsigned lcid = 0, e = bearers.size(); lcid != e; ++lcid) { if (bearers.test(lcid) and u.has_pending_dl_newtx_bytes(uint_to_lcid(lcid))) { return true; } @@ -53,7 +53,7 @@ bool slice_ue::has_pending_dl_newtx_bytes() const unsigned slice_ue::pending_dl_newtx_bytes() const { unsigned pending_bytes = 0; - for (unsigned lcid = 0; lcid < bearers.size(); ++lcid) { + for (unsigned lcid = 0, e = bearers.size(); lcid != e; ++lcid) { if (bearers.test(lcid)) { pending_bytes += u.pending_dl_newtx_bytes(uint_to_lcid(lcid)); } @@ -66,13 +66,13 @@ unsigned slice_ue::pending_ul_newtx_bytes() const constexpr static unsigned SR_GRANT_BYTES = 512; unsigned pending_bytes = 0; - for (unsigned lcg_id = 0; lcg_id < lcg_ids.size(); ++lcg_id) { + for (unsigned lcg_id = 0, e = lcg_ids.size(); lcg_id != e; ++lcg_id) { if (lcg_ids.test(lcg_id)) { pending_bytes += u.pending_ul_newtx_bytes(uint_to_lcg_id(lcg_id)); } } // Subtract the bytes already allocated in UL HARQs. - for (unsigned cell_idx = 0; cell_idx < nof_cells(); ++cell_idx) { + for (unsigned cell_idx = 0, e = nof_cells(); cell_idx != e; ++cell_idx) { const ue_cell& ue_cc = get_cell(to_ue_cell_index(cell_idx)); if (pending_bytes == 0) { break; diff --git a/lib/scheduler/ue_scheduling/ue.cpp b/lib/scheduler/ue_scheduling/ue.cpp index af2bbd5705..8a1089e1bc 100644 --- a/lib/scheduler/ue_scheduling/ue.cpp +++ b/lib/scheduler/ue_scheduling/ue.cpp @@ -183,7 +183,7 @@ unsigned ue::build_dl_transport_block_info(dl_msg_tb_info& { unsigned total_subpdu_bytes = 0; total_subpdu_bytes += allocate_mac_ces(tb_info, dl_lc_ch_mgr, tb_size_bytes); - for (unsigned lcid = 0; lcid < lcids.size(); ++lcid) { + for (unsigned lcid = 0, e = lcids.size(); lcid != e; ++lcid) { if (lcids.test(lcid)) { total_subpdu_bytes += allocate_mac_sdus(tb_info, dl_lc_ch_mgr, tb_size_bytes - total_subpdu_bytes, uint_to_lcid(lcid)); From ba6ce9c1f89249eba1a4cd8023f35d964c116c6c Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 18 Jul 2024 17:28:45 +0200 Subject: [PATCH 165/407] sched: fix multiplexing for harq_bits <= 2 and csi Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 29 +++++------------ .../pucch_alloc_harq_sr_csi_test.cpp | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index df7fd99f0e..8d988b54f3 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1811,10 +1811,9 @@ pucch_allocator_impl::merge_pucch_resources(spanformat != pucch_format::FORMAT_0 and r_harq_ptr->format != pucch_format::FORMAT_1) { new_resource = *r_harq_ptr; } else { - pucch_harq_resource_alloc_record res_alloc = - resource_manager.reserve_next_set_1_harq_res_available(slot_harq, crnti, pucch_cfg); + const pucch_resource* pucch_res = resource_manager.reserve_set_1_res_by_res_indicator( + slot_harq, crnti, r_harq_ptr->harq_id.pucch_res_ind, pucch_cfg); resource_manager.set_new_resource_allocation(crnti, pucch_resource_usage::HARQ_SET_1); - if (res_alloc.pucch_res == nullptr) { + if (pucch_res == nullptr) { return std::nullopt; } new_resource.harq_id.pucch_set_idx = pucch_res_set_idx::set_1; - new_resource.harq_id.pucch_res_ind = res_alloc.pucch_res_indicator; - new_resource.set_res_config(*res_alloc.pucch_res); + new_resource.harq_id.pucch_res_ind = r_harq_ptr->harq_id.pucch_res_ind; + new_resource.set_res_config(*pucch_res); } new_resource.bits.harq_ack_nof_bits = r_harq_ptr->bits.harq_ack_nof_bits; new_resource.bits.sr_bits = r_sr_ptr->bits.sr_bits; diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index f972f036fb..1dd02f8d9e 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -718,6 +718,37 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_4bits_over_sr_and_csi ASSERT_FALSE(test_pucch_res_indicator.has_value()); } +TEST_F(test_pucch_allocator_ded_resources, when_converting_harq_f1_to_f2_during_mplexing_csi_preserve_res_indicator) +{ + // This makes PUCCH resource indicator 0 busy for PUCCH resource set 0. + add_ue_with_harq_grant(); + add_csi_grant(); + + // At the end of the PUCCH allocation with Format 2, we expect the same PUCCH as for PUCCH format 1. + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + // PUCCH resource indicator 0 is used by the first UE that got allocated. + ASSERT_EQ(1U, test_pucch_res_indicator.value()); +} + +TEST_F(test_pucch_allocator_ded_resources, when_converting_harq_f1_to_f2_during_mplexing_sr_csi_preserve_res_indicator) +{ + // This makes PUCCH resource indicator 0 busy for PUCCH resource set 0. + add_ue_with_harq_grant(); + add_sr_grant(); + add_csi_grant(); + + // At the end of the PUCCH allocation with Format 2, we expect the same PUCCH as for PUCCH format 1. + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + // PUCCH resource indicator 0 is used by the first UE that got allocated. + ASSERT_EQ(1U, test_pucch_res_indicator.value()); +} + /////// Test allocation of common + dedicated resources. /////// TEST_F(test_pucch_allocator_ded_resources, test_common_plus_ded_resource_without_existing_grants) From ab17737a086379ad952b8fa842b533536f48c866 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 22 Jul 2024 11:21:35 +0200 Subject: [PATCH 166/407] sched: rename local variables in pucch allocator Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 8d988b54f3..2be3c4a97b 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1849,43 +1849,42 @@ pucch_allocator_impl::merge_pucch_resources(spanformat == pucch_format::FORMAT_0) { + srsran_assert(r_harq != nullptr and r_sr != nullptr and r_csi != nullptr, "The three resources must be present"); + if (r_sr->format == pucch_format::FORMAT_0) { srsran_assertion_failure("This case is not yet supported"); // SR and CSI are not supported on the same slot if SR uses Format 0. return std::nullopt; } - if (r_harq_ptr->format != pucch_format::FORMAT_0 and r_harq_ptr->format != pucch_format::FORMAT_1) { - new_resource = *r_harq_ptr; + if (r_harq->format != pucch_format::FORMAT_0 and r_harq->format != pucch_format::FORMAT_1) { + new_resource = *r_harq; } else { const pucch_resource* pucch_res = resource_manager.reserve_set_1_res_by_res_indicator( - slot_harq, crnti, r_harq_ptr->harq_id.pucch_res_ind, pucch_cfg); + slot_harq, crnti, r_harq->harq_id.pucch_res_ind, pucch_cfg); resource_manager.set_new_resource_allocation(crnti, pucch_resource_usage::HARQ_SET_1); if (pucch_res == nullptr) { return std::nullopt; } new_resource.harq_id.pucch_set_idx = pucch_res_set_idx::set_1; - new_resource.harq_id.pucch_res_ind = r_harq_ptr->harq_id.pucch_res_ind; + new_resource.harq_id.pucch_res_ind = r_harq->harq_id.pucch_res_ind; new_resource.set_res_config(*pucch_res); } - new_resource.bits.harq_ack_nof_bits = r_harq_ptr->bits.harq_ack_nof_bits; - new_resource.bits.sr_bits = r_sr_ptr->bits.sr_bits; - new_resource.bits.csi_part1_nof_bits = r_csi_ptr->bits.csi_part1_nof_bits; + new_resource.bits.harq_ack_nof_bits = r_harq->bits.harq_ack_nof_bits; + new_resource.bits.sr_bits = r_sr->bits.sr_bits; + new_resource.bits.csi_part1_nof_bits = r_csi->bits.csi_part1_nof_bits; // Check if the UCI payload fits in the PUCCH resource. if (new_resource.bits.get_total_bits() <= pucch_cfg.get_max_payload(new_resource.format)) { From 8705265f9d0e6b6bdd63a536c2d17462a06ee8f8 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 7 Aug 2024 12:27:40 +0200 Subject: [PATCH 167/407] sched: remove wrong PUCCH PDU filling Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 2be3c4a97b..f55da5bba4 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1968,52 +1968,6 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits); sr_grant_alloc_completed = true; } - // If there was a HARQ grant of the same PUCCH format, re-use the previous one and update the UCI bits HARQ/CSI/SR - // bits. - if (grants_to_tx.harq_resource.has_value() and existing_pucchs.pucch_grants.harq_resource.has_value() and - grants_to_tx.harq_resource.value().format == existing_pucchs.pucch_grants.harq_resource.value().format and - existing_pdus.harq_pdu != nullptr) { - // Update bits; - if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_0) { - logger.debug("rnti={}: PUCCH PDU allocated on F0 HARQ resource (updated): slot={} p_ind={} prbs={} sym={} " - "h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, - existing_pdus.harq_pdu->resources.prbs, - existing_pdus.harq_pdu->resources.symbols, - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits); - } else if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_1) { - logger.debug("rnti={}: PUCCH PDU allocated on F1 HARQ resource (updated): slot={} p_ind={} prbs={} sym={} cs={} " - "occ={} h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, - existing_pdus.harq_pdu->resources.prbs, - existing_pdus.harq_pdu->resources.symbols, - existing_pdus.harq_pdu->format_1.initial_cyclic_shift, - existing_pdus.harq_pdu->format_1.time_domain_occ, - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits); - } else { - logger.debug( - "rnti={}: PUCCH PDU allocated on F2 HARQ resource (updated): slot={} p_ind={} prbs={} sym={} h_bits={} " - "sr_bits={} cs_bits={}", - crnti, - pucch_slot_alloc.slot, - grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, - existing_pdus.harq_pdu->resources.prbs, - existing_pdus.harq_pdu->resources.symbols, - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits, - grants_to_tx.harq_resource.value().bits.csi_part1_nof_bits); - } - existing_pdus.update_harq_pdu_bits(grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits, - grants_to_tx.harq_resource.value().bits.csi_part1_nof_bits); - harq_grant_alloc_completed = true; - } pucch_uci_bits bits = grants_to_tx.get_uci_bits(); if (grants_to_tx.csi_resource.has_value() and not csi_grant_alloc_completed) { From d7bb12112294b39ecb698cde7d0ecb5dc2e549d6 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 7 Aug 2024 18:19:57 +0200 Subject: [PATCH 168/407] sched: improve pucch allocation for no mplex case Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 160 ++++++++++++------ .../pucch_scheduling/pucch_allocator_impl.h | 13 +- 2 files changed, 114 insertions(+), 59 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index f55da5bba4..4b42ae8aa4 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -287,11 +287,24 @@ std::optional pucch_allocator_impl::alloc_ded_pucch_harq_ack_ue(cell_r return std::nullopt; } - pucch_uci_bits new_bits = existing_grant_it->pucch_grants.get_uci_bits(); + const pucch_uci_bits current_uci_bits = existing_grant_it->pucch_grants.get_uci_bits(); + pucch_uci_bits new_bits = current_uci_bits; ++new_bits.harq_ack_nof_bits; + // As per TS 38.213, Section 9.2.1, we can infer that, when the HARQ-ACK bit count changes from 1 to 2, or when it + // changes from 3 to more than 3, the PUCCH resource for the HARQ-ACK is the same as the previous one; this means + // that the multiplexing would yield the same result as in the last UE's allocation; in this case, we skip the + // multiplexing. Refer to paragraph "If the UE transmits O_UCI UCI information bits, that include HARQ-ACK + // information bits, the UE determines a PUCCH resource set to be ...". + const bool is_multiplexing_needed = + not((current_uci_bits.harq_ack_nof_bits == 1U and new_bits.harq_ack_nof_bits == 2U) or + (current_uci_bits.harq_ack_nof_bits == 3U and new_bits.harq_ack_nof_bits > 3U)); + std::optional pucch_res_ind = - multiplex_and_allocate_pucch(pucch_slot_alloc, new_bits, *existing_grant_it, ue_cell_cfg); + is_multiplexing_needed + ? multiplex_and_allocate_pucch(pucch_slot_alloc, new_bits, *existing_grant_it, ue_cell_cfg) + : allocate_without_multiplexing(pucch_slot_alloc, new_bits, *existing_grant_it, ue_cell_cfg); + ; if (not pucch_res_ind) { resource_manager.cancel_last_ue_res_reservations(sl_ack, crnti, ue_cell_cfg); } @@ -614,7 +627,11 @@ class existing_pucch_pdus_handler void remove_unused_pdus(static_vector& pucchs, rnti_t rnti) const; void update_sr_pdu_bits(sr_nof_bits sr_bits, unsigned harq_ack_bits); void update_csi_pdu_bits(unsigned csi_part1_bits, sr_nof_bits sr_bits); - void update_harq_pdu_bits(unsigned harq_ack_bits, sr_nof_bits sr_bits, unsigned csi_part1_bits); + void update_harq_pdu_bits(unsigned harq_ack_bits, + sr_nof_bits sr_bits, + unsigned csi_part1_bits, + const pucch_resource& pucch_res_cfg, + const float max_pucch_code_rate = 1.0F); pucch_info* sr_pdu{nullptr}; pucch_info* harq_pdu{nullptr}; @@ -750,9 +767,11 @@ void existing_pucch_pdus_handler::update_csi_pdu_bits(unsigned csi_part1_bits, s } } -void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned harq_ack_bits, - sr_nof_bits sr_bits, - unsigned csi_part1_bits) +void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned harq_ack_bits, + sr_nof_bits sr_bits, + unsigned csi_part1_bits, + const pucch_resource& pucch_res_cfg, + const float max_pucch_code_rate) { if (harq_pdu->format == pucch_format::FORMAT_0) { harq_pdu->format_0.harq_ack_nof_bits = harq_ack_bits; @@ -773,6 +792,18 @@ void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned harq_ack_bits harq_pdu->format_2.sr_bits = sr_bits; harq_pdu->format_2.csi_part1_bits = csi_part1_bits; harq_pdu->pdu_context.id = pdu_id++; + // After updating the UCI bits, we need to recompute the number of PRBs for PUCCH format 2, as per TS 38.213, + // Section 9.2.5.2. + const auto& f2_cfg = std::get(pucch_res_cfg.format_params); + const unsigned nof_prbs = get_pucch_format2_nof_prbs(harq_ack_bits + sr_nof_bits_to_uint(sr_bits) + csi_part1_bits, + f2_cfg.nof_prbs, + f2_cfg.nof_symbols, + max_pucch_code_rate); + harq_pdu->resources.prbs.set(pucch_res_cfg.starting_prb, pucch_res_cfg.starting_prb + nof_prbs); + if (pucch_res_cfg.second_hop_prb.has_value()) { + harq_pdu->resources.second_hop_prbs.set(pucch_res_cfg.second_hop_prb.value(), + pucch_res_cfg.second_hop_prb.value() + nof_prbs); + } // Once the grant is updated, set the pointer to null, as we don't want to process this again. harq_pdu = nullptr; --pdus_cnt; @@ -1393,23 +1424,8 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& return std::nullopt; } - // As per TS 38.213, Section 9.2.1, we can infer that, when the HARQ-ACK bit count changes from 1 to 2, or when it - // changes from 3 to more than 3, the PUCCH resource for the HARQ-ACK is the same as the previous one; this means - // that the multiplexing would yield the same result as in the last UE's allocation; in this case, we skip the - // multiplexing. Refer to paragraph "If the UE transmits O_UCI UCI information bits, that include HARQ-ACK - // information bits, the UE determines a PUCCH resource set to be ...". - const pucch_uci_bits current_uci_bits = current_grants.pucch_grants.get_uci_bits(); - const bool is_multiplexing_needed = - new_bits.sr_bits != sr_nof_bits::no_sr or new_bits.csi_part1_nof_bits != 0U or - not((current_uci_bits.harq_ack_nof_bits == 1U and new_bits.harq_ack_nof_bits == 2U) or - (current_uci_bits.harq_ack_nof_bits == 3U and new_bits.harq_ack_nof_bits > 3U)); - pucch_grant_list grants_to_tx = - is_multiplexing_needed - ? multiplex_resources( - sl_ack, current_grants.rnti, candidate_grants.value(), ue_cell_cfg, preserve_res_indicator) - : update_grants_no_multiplexing( - sl_ack, current_grants.rnti, candidate_grants.value(), ue_cell_cfg, current_grants); + multiplex_resources(sl_ack, current_grants.rnti, candidate_grants.value(), ue_cell_cfg, preserve_res_indicator); if (grants_to_tx.is_emtpy()) { return std::nullopt; @@ -1543,41 +1559,81 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point return candidate_resources; } -pucch_allocator_impl::pucch_grant_list -pucch_allocator_impl::update_grants_no_multiplexing(slot_point sl_tx, - rnti_t crnti, - pucch_grant_list candidate_grants, - const ue_cell_configuration& ue_cell_cfg, - ue_grants ue_current_grants) +std::optional +pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator& pucch_slot_alloc, + pucch_uci_bits new_bits, + ue_grants& current_grants, + const ue_cell_configuration& ue_cell_cfg) { - pucch_grant_list grants_to_tx; - - srsran_assert(candidate_grants.harq_resource.has_value(), "PUCCH HARQ-ACK resource must be present"); - pucch_grant harq_grant = candidate_grants.harq_resource.value(); + slot_point sl_tx = pucch_slot_alloc.slot; - // If the PUCCH is from PUCCH resource set 1 and the total UCI bits exceeds the PUCCH payload, we abort the - // allocation. - if (harq_grant.harq_id.pucch_set_idx != pucch_res_set_idx::set_0 and - candidate_grants.get_uci_bits().get_total_bits() > - ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().get_max_payload( - harq_grant.format)) { - logger.debug( - "rnti={}: PUCCH allocation (HARQ-ACK) for slot={} skipped. Cause: UCI bits exceed PUCCH payload", crnti, sl_tx); - return grants_to_tx; - } + const pucch_config& pucch_cfg = ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value(); - // In the case, the only elements that might have changed since the last allocation are the UCI bits and (possibly) - // the pointers to PUCCH resources. - srsran_assert(ue_current_grants.pucch_grants.harq_resource.has_value(), - "PUCCH HARQ resource must be present in the current allocation list"); - grants_to_tx = ue_current_grants.pucch_grants; + auto& pucch_pdus = pucch_slot_alloc.result.ul.pucchs; - // Update the grants with the new UCI bits and PUCCH resource configurations (this is to prevent the pointers have - // changed since the last allocation). - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits = harq_grant.bits.harq_ack_nof_bits; - grants_to_tx.harq_resource.value().set_res_config(*harq_grant.pucch_res_cfg); + // Retrieve the existing PUCCH PDUs. + existing_pucch_pdus_handler existing_pdus(current_grants.rnti, pucch_pdus, get_sr_pucch_res_cfg(pucch_cfg)); + + srsran_assert(existing_pdus.harq_pdu != nullptr and current_grants.pucch_grants.harq_resource.has_value(), + "rnti={}: expected HARQ-ACK PUCCH grant and PDU not found", + current_grants.rnti); + + pucch_uci_bits current_bits = current_grants.pucch_grants.get_uci_bits(); + + // If the HARQ PDU uses F0, there can be 1 HARQ PDU + an optional SR (F0) or CSI (F2). In any case, we only need to + // update the HARQ-ACK bits in the HARQ-ACK PDU. + if (existing_pdus.harq_pdu->format == pucch_format::FORMAT_0) { + const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_0_res_by_res_indicator( + sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); + srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + existing_pdus.update_harq_pdu_bits( + new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, 0U, *pucch_res_cfg); + // Update the current grant with the new UCI (HARQ) bits. + current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; + } + // If the HARQ PDU uses F1, there can be 1 HARQ PDU + an optional SR (F1). In the latter case, we need to update the + // HARQ-ACK bits in the SR PDU as well. + else if (existing_pdus.harq_pdu->format == pucch_format::FORMAT_1) { + const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_0_res_by_res_indicator( + sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); + srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, sr_nof_bits::no_sr, 0U, *pucch_res_cfg); + // Update the current grants with the new UCI (HARQ) bits. + current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; + if (existing_pdus.sr_pdu != nullptr) { + existing_pdus.update_sr_pdu_bits(current_bits.sr_bits, new_bits.harq_ack_nof_bits); + // Update the current grants with the new UCI (HARQ) bits. + current_grants.pucch_grants.sr_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; + } + } + // If the HARQ PDU uses F2, there can be 1 HARQ PDU + an optional CSI (F2). In any case, we only need to update the + // HARQ-ACK bits in the HARQ-ACK PDU. + else if (existing_pdus.harq_pdu->format == pucch_format::FORMAT_2) { + if (current_grants.pucch_grants.get_uci_bits().get_total_bits() >= + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().get_max_payload( + pucch_format::FORMAT_2)) { + logger.debug("rnti={}: PUCCH allocation (HARQ-ACK) for slot={} skipped. Cause: UCI bits exceed PUCCH payload", + current_grants.rnti, + sl_tx); + return std::nullopt; + } + const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_1_res_by_res_indicator( + sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); + srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, + current_grants.pucch_grants.harq_resource.value().bits.sr_bits, + current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits, + *pucch_res_cfg, + to_max_code_rate_float(ue_cell_cfg.cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .format_2_common_param->max_c_rate)); + current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; + } else { + srsran_assertion_failure("rnti={}: unexpected PUCCH format", current_grants.rnti); + } - return grants_to_tx; + return current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind; } pucch_allocator_impl::pucch_grant_list diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h index b112ee4218..2dc2152dfd 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h @@ -166,6 +166,12 @@ class pucch_allocator_impl final : public pucch_allocator const ue_cell_configuration& ue_cell_cfg, unsigned csi_part1_bits); + // Update the grants data for the case in which multiplexing is not needed. + std::optional allocate_without_multiplexing(cell_slot_resource_allocator& pucch_slot_alloc, + pucch_uci_bits new_bits, + ue_grants& current_grants, + const ue_cell_configuration& ue_cell_cfg); + // Implements the main steps of the multiplexing procedure as defined in TS 38.213, Section 9.2.5. std::optional multiplex_and_allocate_pucch(cell_slot_resource_allocator& pucch_slot_alloc, pucch_uci_bits new_bits, @@ -179,13 +185,6 @@ class pucch_allocator_impl final : public pucch_allocator ue_grants ue_current_grants, const ue_cell_configuration& ue_cell_cfg); - // Update the grants data for the case in which multiplexing is not needed. - pucch_grant_list update_grants_no_multiplexing(slot_point sl_tx, - rnti_t crnti, - pucch_grant_list candidate_grants, - const ue_cell_configuration& ue_cell_cfg, - ue_grants ue_current_grants); - // Execute the multiplexing algorithm as defined in TS 38.213, Section 9.2.5. pucch_grant_list multiplex_resources(slot_point sl_tx, rnti_t crnti, From 3a97edf6370c5e26a71e3586080aad14ec285953 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 7 Aug 2024 18:49:32 +0200 Subject: [PATCH 169/407] sched: add unittest for PUCCH allocator Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 42 +++++++++++++++++++ .../pucch_alloc_harq_sr_csi_test.cpp | 39 +++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 4b42ae8aa4..5e27b4149f 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1586,6 +1586,15 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_0_res_by_res_indicator( sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + logger.debug("rnti={}: PUCCH PDU on F0 HARQ resource updated: slot={} p_ind={} prbs={} sym={} " + "h_bits={} sr_bits={}", + current_grants.rnti, + pucch_slot_alloc.slot, + current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, + existing_pdus.harq_pdu->resources.prbs, + existing_pdus.harq_pdu->resources.symbols, + new_bits.harq_ack_nof_bits, + current_grants.pucch_grants.harq_resource.value().bits.sr_bits); existing_pdus.update_harq_pdu_bits( new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, 0U, *pucch_res_cfg); // Update the current grant with the new UCI (HARQ) bits. @@ -1597,14 +1606,36 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_0_res_by_res_indicator( sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + logger.debug("rnti={}: PUCCH PDU on F1 HARQ resource updated: slot={} p_ind={} prbs={} sym={} cs={} occ={} " + "h_bits={} sr_bits={}", + current_grants.rnti, + pucch_slot_alloc.slot, + current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, + existing_pdus.harq_pdu->resources.prbs, + existing_pdus.harq_pdu->resources.symbols, + existing_pdus.harq_pdu->format_1.initial_cyclic_shift, + existing_pdus.harq_pdu->format_1.time_domain_occ, + new_bits.harq_ack_nof_bits, + existing_pdus.harq_pdu->format_1.sr_bits); existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, sr_nof_bits::no_sr, 0U, *pucch_res_cfg); // Update the current grants with the new UCI (HARQ) bits. current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; if (existing_pdus.sr_pdu != nullptr) { + logger.debug("rnti={}: PUCCH PDU on SR F1 resource updated: slot={} prbs={} sym={} cs={} occ={} " + "h_bits={} sr_bits={}", + current_grants.rnti, + pucch_slot_alloc.slot, + existing_pdus.sr_pdu->resources.prbs, + existing_pdus.sr_pdu->resources.symbols, + existing_pdus.sr_pdu->format_1.initial_cyclic_shift, + existing_pdus.sr_pdu->format_1.time_domain_occ, + new_bits.harq_ack_nof_bits, + existing_pdus.sr_pdu->format_1.sr_bits); existing_pdus.update_sr_pdu_bits(current_bits.sr_bits, new_bits.harq_ack_nof_bits); // Update the current grants with the new UCI (HARQ) bits. current_grants.pucch_grants.sr_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; } + } // If the HARQ PDU uses F2, there can be 1 HARQ PDU + an optional CSI (F2). In any case, we only need to update the // HARQ-ACK bits in the HARQ-ACK PDU. @@ -1620,6 +1651,17 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_1_res_by_res_indicator( sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + logger.debug("rnti={}: PUCCH PDU on F2 HARQ resource updated: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " + "sr_bits={} cs_bits={}", + current_grants.rnti, + pucch_slot_alloc.slot, + current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, + existing_pdus.harq_pdu->format, + existing_pdus.harq_pdu->resources.prbs, + existing_pdus.harq_pdu->resources.symbols, + new_bits.harq_ack_nof_bits, + current_grants.pucch_grants.harq_resource.value().bits.sr_bits, + current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits); existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits, diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index 1dd02f8d9e..27b1b22672 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -749,6 +749,45 @@ TEST_F(test_pucch_allocator_ded_resources, when_converting_harq_f1_to_f2_during_ ASSERT_EQ(1U, test_pucch_res_indicator.value()); } +TEST_F(test_pucch_allocator_ded_resources, with_f2_res_1_harq_bit_adding_adding_extra_bit_doesnt_change_res_indicator) +{ + // This makes PUCCH resource indicator 0 busy for PUCCH resource set 0. + add_ue_with_harq_grant(); + add_csi_grant(); + + // At the end of the PUCCH allocation with Format 2, we expect the same PUCCH as for PUCCH format 1. + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + // PUCCH resource indicator 0 is used by the first UE that got allocated. + ASSERT_EQ(1U, test_pucch_res_indicator.value()); + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + const auto first_alloc = + std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { return pdu.crnti == rnti; }); + ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); + + std::optional test_pucch_res_indicator_new = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator_new.has_value()); + // PUCCH resource indicator after the second allocation should not have changed. + ASSERT_EQ(test_pucch_res_indicator.value(), test_pucch_res_indicator_new.has_value()); + + const auto second_alloc = + std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { return pdu.crnti == rnti; }); + ASSERT_TRUE(second_alloc != slot_grid.result.ul.pucchs.end()); + ASSERT_EQ(first_alloc->resources.prbs, second_alloc->resources.prbs); + ASSERT_EQ(first_alloc->resources.symbols, second_alloc->resources.symbols); + ASSERT_EQ(first_alloc->resources.second_hop_prbs, second_alloc->resources.second_hop_prbs); +} + /////// Test allocation of common + dedicated resources. /////// TEST_F(test_pucch_allocator_ded_resources, test_common_plus_ded_resource_without_existing_grants) From aec1a78ae1374cbfff6092110bd0c1facbe8bf1d Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 8 Aug 2024 11:56:56 +0200 Subject: [PATCH 170/407] sched: add unittests for pucch alloc w/out mplexing Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 38 +++--- .../pucch_alloc_harq_sr_csi_test.cpp | 115 +++++++++++++++--- 2 files changed, 116 insertions(+), 37 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 5e27b4149f..213567bd63 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1652,7 +1652,7 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); logger.debug("rnti={}: PUCCH PDU on F2 HARQ resource updated: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " - "sr_bits={} cs_bits={}", + "sr_bits={} csi1_bits={}", current_grants.rnti, pucch_slot_alloc.slot, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, @@ -2025,14 +2025,15 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource // If there was a CSI grant, re-use the previous one and update the UCI bits with SR. if (grants_to_tx.csi_resource.has_value() and existing_pucchs.pucch_grants.csi_resource.has_value() and existing_pdus.csi_pdu != nullptr) { - logger.debug("rnti={}: PUCCH PDU allocated on CSI resource: slot={} prbs={} sym={} h_bits={} sr_bits={} cs_bits={}", - crnti, - pucch_slot_alloc.slot, - existing_pdus.csi_pdu->resources.prbs, - existing_pdus.csi_pdu->resources.symbols, - existing_pdus.csi_pdu->format_2.harq_ack_nof_bits, - grants_to_tx.csi_resource.value().bits.sr_bits, - grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on CSI resource: slot={} prbs={} sym={} h_bits={} sr_bits={} csi1_bits={}", + crnti, + pucch_slot_alloc.slot, + existing_pdus.csi_pdu->resources.prbs, + existing_pdus.csi_pdu->resources.symbols, + existing_pdus.csi_pdu->format_2.harq_ack_nof_bits, + grants_to_tx.csi_resource.value().bits.sr_bits, + grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits); existing_pdus.update_csi_pdu_bits(grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits, grants_to_tx.csi_resource.value().bits.sr_bits); csi_grant_alloc_completed = true; @@ -2081,14 +2082,15 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource 0U, grants_to_tx.csi_resource.value().bits.sr_bits, grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits); - logger.debug("rnti={}: PUCCH PDU allocated on CSI resource: slot={} prbs={} sym={} h_bits={} sr_bits={} cs_bits={}", - crnti, - pucch_slot_alloc.slot, - grant->resources.prbs, - grant->resources.symbols, - grant->format_2.harq_ack_nof_bits, - grant->format_2.sr_bits, - grant->format_2.csi_part1_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on CSI resource: slot={} prbs={} sym={} h_bits={} sr_bits={} csi1_bits={}", + crnti, + pucch_slot_alloc.slot, + grant->resources.prbs, + grant->resources.symbols, + grant->format_2.harq_ack_nof_bits, + grant->format_2.sr_bits, + grant->format_2.csi_part1_bits); } if (grants_to_tx.sr_resource.has_value() and not sr_grant_alloc_completed) { pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); @@ -2175,7 +2177,7 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource } else { logger.debug( "rnti={}: PUCCH PDU allocated on F2 HARQ resource: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " - "sr_bits={} cs_bits={}", + "sr_bits={} csi1_bits={}", crnti, pucch_slot_alloc.slot, grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index 27b1b22672..836e50e013 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -409,34 +409,61 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_allocation_over_sr) TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_2bits) { - add_harq_grant(); - pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 2; const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - - auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; - // Expect 1 HARQ. ASSERT_TRUE(test_pucch_res_indicator.has_value()); ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator.value()); + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + const auto first_alloc = slot_grid.result.ul.pucchs.front(); + + pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 2; + const std::optional test_pucch_res_indicator_1 = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator_1.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator_1.value()); + // Expect 1 PUCCH HARQ. ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f1_harq](const auto& pdu) { return pucch_info_match(expected, pdu); })); + + // Make sure the second PUCCH allocation uses the same PRBs and symbols as the first one. + const auto second_alloc = slot_grid.result.ul.pucchs.front(); + ASSERT_EQ(first_alloc.resources.prbs, second_alloc.resources.prbs); + ASSERT_EQ(first_alloc.resources.symbols, second_alloc.resources.symbols); + ASSERT_EQ(first_alloc.resources.second_hop_prbs, second_alloc.resources.second_hop_prbs); } TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_2bits_over_sr) { add_sr_grant(); - add_harq_grant(); - pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 2; - pucch_expected_f1_sr.format_1.harq_ack_nof_bits = 2; + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator.value()); auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + const auto first_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { + return pdu.crnti == rnti and pdu.format_1.harq_ack_nof_bits == 1U and + pdu.format_1.sr_bits == sr_nof_bits::no_sr; + }); + ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); + + pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 2; + pucch_expected_f1_sr.format_1.harq_ack_nof_bits = 2; + const std::optional test_pucch_res_indicator_1 = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + // Expect 1 HARQ and 1 SR. - ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator.value()); + ASSERT_TRUE(test_pucch_res_indicator_1.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator_1.value()); ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); // Verify that the UCI bits grants are correct. ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f1_sr](const auto& pdu) { @@ -445,6 +472,18 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_2bits_over_sr) ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f1_harq](const auto& pdu) { return pucch_info_match(expected, pdu); })); + + // Make sure the second PUCCH allocation uses the same PRBs and symbols as the first one. + const auto second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { + return pdu.crnti == rnti and pdu.format_1.harq_ack_nof_bits == 2U and + pdu.format_1.sr_bits == sr_nof_bits::no_sr; + }); + ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); + ASSERT_EQ(first_alloc->resources.prbs, second_alloc->resources.prbs); + ASSERT_EQ(first_alloc->resources.symbols, second_alloc->resources.symbols); + ASSERT_EQ(first_alloc->resources.second_hop_prbs, second_alloc->resources.second_hop_prbs); } /////// Test HARQ-ACK allocation on ded. resources - Format 1 - Multi UEs /////// @@ -755,7 +794,8 @@ TEST_F(test_pucch_allocator_ded_resources, with_f2_res_1_harq_bit_adding_adding_ add_ue_with_harq_grant(); add_csi_grant(); - // At the end of the PUCCH allocation with Format 2, we expect the same PUCCH as for PUCCH format 1. + // After the second PUCCH allocation with Format 2, we expect the same PUCCH res indicator as for the first + // allocation of HARQ-ACK bit. std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); @@ -776,8 +816,9 @@ TEST_F(test_pucch_allocator_ded_resources, with_f2_res_1_harq_bit_adding_adding_ ASSERT_TRUE(test_pucch_res_indicator_new.has_value()); // PUCCH resource indicator after the second allocation should not have changed. - ASSERT_EQ(test_pucch_res_indicator.value(), test_pucch_res_indicator_new.has_value()); + ASSERT_EQ(test_pucch_res_indicator.value(), test_pucch_res_indicator_new.value()); + // Make sure the second PUCCH allocation uses the same PRBs and symbols as the first one. const auto second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), slot_grid.result.ul.pucchs.end(), @@ -1703,19 +1744,31 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_only) TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits) { auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; - t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( - t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); + const auto first_alloc = slot_grid.result.ul.pucchs.front(); + + const std::optional test_pucch_res_indicator_1 = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; + ASSERT_TRUE(test_pucch_res_indicator_1.has_value()); + // PUCCH resource indicator after the second allocation should not have changed. + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator_1); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { return pucch_info_match(expected, pdu); })); + + const auto second_alloc = slot_grid.result.ul.pucchs.front(); + ASSERT_EQ(first_alloc.resources.prbs, second_alloc.resources.prbs); + ASSERT_EQ(first_alloc.resources.symbols, second_alloc.resources.symbols); + ASSERT_EQ(first_alloc.resources.second_hop_prbs, second_alloc.resources.second_hop_prbs); } TEST_F(test_pucch_allocator_format_0, test_harq_allocation_over_sr) @@ -1750,17 +1803,28 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_sr) t_bench.pucch_alloc.pucch_allocate_sr_opportunity( slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg()); - t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( - t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + + const auto first_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { + return pdu.crnti == rnti and pdu.format_0.harq_ack_nof_bits == 1U and + pdu.format_0.sr_bits == sr_nof_bits::no_sr; + }); + ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); + + const std::optional test_pucch_res_indicator_1 = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; pucch_expected_f0_harq.format_0.sr_bits = srsran::sr_nof_bits::no_sr; pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; - ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_TRUE(test_pucch_res_indicator_1.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator_1); ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { return pucch_info_match(expected, pdu); @@ -1768,6 +1832,19 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_sr) ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { return pucch_info_match(expected, pdu); })); + + // Make sure the resource used for the second HARQ-ACK allocation uses the same PRBs and symbols as the first + // allocation. + const auto second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { + return pdu.crnti == rnti and pdu.format_0.harq_ack_nof_bits == 2U and + pdu.format_0.sr_bits == sr_nof_bits::no_sr; + }); + ASSERT_TRUE(second_alloc != slot_grid.result.ul.pucchs.end()); + ASSERT_EQ(first_alloc->resources.prbs, second_alloc->resources.prbs); + ASSERT_EQ(first_alloc->resources.symbols, second_alloc->resources.symbols); + ASSERT_EQ(first_alloc->resources.second_hop_prbs, second_alloc->resources.second_hop_prbs); } TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_sr) From fd51ebf5c28ca19e7a2662a48bb4c782e116980f Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 17:57:40 +0200 Subject: [PATCH 171/407] FAPI: Remove bitmap_utils header from ADT --- include/srsran/adt/bitmap_utils.h | 51 ------------------ include/srsran/fapi/message_builders.h | 53 +++++++++++++++---- .../fapi/message_builder_helpers.cpp | 1 - 3 files changed, 44 insertions(+), 61 deletions(-) delete mode 100644 include/srsran/adt/bitmap_utils.h diff --git a/include/srsran/adt/bitmap_utils.h b/include/srsran/adt/bitmap_utils.h deleted file mode 100644 index 43b1f3fe8e..0000000000 --- a/include/srsran/adt/bitmap_utils.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * \section COPYRIGHT - * - * 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/support/srsran_assert.h" - -namespace srsran { - -/// \brief Sets the value of a bit in the bitmap. When enable is true, it sets the bit, otherwise it clears the bit. -/// \param[in] bitmap Bitmap to modify. -/// \param[in] bit Bit to change. -/// \param[in] enable Value to set. If true, sets the bit(1), otherwise clears it(0). -/// \note Use this function with integer data types, otherwise it produces undefined behaviour. -template -void set_bitmap_bit(Integer& bitmap, unsigned bit, bool enable) -{ - static_assert(std::is_integral::value, "Integral required"); - srsran_assert(sizeof(bitmap) * 8 > bit, "Requested bit ({}), exceeds the bitmap size({})", bit, sizeof(bitmap) * 8); - - if (enable) { - bitmap |= (1U << bit); - } else { - bitmap &= ~(1U << bit); - } -} - -/// \brief Checks the value of a bit in the bitmap and returns a true if the bit is set, otherwise false. -/// \param[in] bitmap Bitmap to check. -/// \param[in] bit Bit to check. -/// \return True when the bit equals 1, otherwise false. -/// \note Use this function with integer data types, otherwise it produces undefined behaviour. -template -bool check_bitmap_bit(Integer bitmap, unsigned bit) -{ - static_assert(std::is_integral::value, "Integral required"); - srsran_assert(sizeof(bitmap) * 8 > bit, "Requested bit ({}), exceeds the bitmap size({})", bit, sizeof(bitmap) * 8); - - return (bitmap & (1U << bit)); -} - -} // namespace srsran diff --git a/include/srsran/fapi/message_builders.h b/include/srsran/fapi/message_builders.h index 83b8e4cd16..9cdb737ba5 100644 --- a/include/srsran/fapi/message_builders.h +++ b/include/srsran/fapi/message_builders.h @@ -10,7 +10,6 @@ #pragma once -#include "srsran/adt/bitmap_utils.h" #include "srsran/adt/optional.h" #include "srsran/adt/span.h" #include "srsran/fapi/messages.h" @@ -23,6 +22,42 @@ namespace srsran { namespace fapi { +namespace detail { + +/// \brief Sets the value of a bit in the bitmap. When enable is true, it sets the bit, otherwise it clears the bit. +/// \param[in] bitmap Bitmap to modify. +/// \param[in] bit Bit to change. +/// \param[in] enable Value to set. If true, sets the bit(1), otherwise clears it(0). +/// \note Use this function with integer data types, otherwise it produces undefined behaviour. +template +void set_bitmap_bit(Integer& bitmap, unsigned bit, bool enable) +{ + static_assert(std::is_integral::value, "Integral required"); + srsran_assert(sizeof(bitmap) * 8 > bit, "Requested bit ({}), exceeds the bitmap size({})", bit, sizeof(bitmap) * 8); + + if (enable) { + bitmap |= (1U << bit); + } else { + bitmap &= ~(1U << bit); + } +} + +/// \brief Checks the value of a bit in the bitmap and returns a true if the bit is set, otherwise false. +/// \param[in] bitmap Bitmap to check. +/// \param[in] bit Bit to check. +/// \return True when the bit equals 1, otherwise false. +/// \note Use this function with integer data types, otherwise it produces undefined behaviour. +template +bool check_bitmap_bit(Integer bitmap, unsigned bit) +{ + static_assert(std::is_integral::value, "Integral required"); + srsran_assert(sizeof(bitmap) * 8 > bit, "Requested bit ({}), exceeds the bitmap size({})", bit, sizeof(bitmap) * 8); + + return (bitmap & (1U << bit)); +} + +} // namespace detail + // :TODO: Review the builders documentation so it matches the UCI builder. /// Helper class to fill the transmission precoding and beamforming parameters specified in SCF-222 v4.0 @@ -516,9 +551,9 @@ class dl_pdsch_pdu_builder { pdu.pdu_bitmap.set(dl_pdsch_pdu::PDU_BITMAP_CBG_RETX_CTRL_BIT); - set_bitmap_bit( + detail::set_bitmap_bit( pdu.is_last_cb_present, dl_pdsch_pdu::LAST_CB_BITMAP_FIRST_TB_BIT, last_cb_present_first_tb); - set_bitmap_bit( + detail::set_bitmap_bit( pdu.is_last_cb_present, dl_pdsch_pdu::LAST_CB_BITMAP_SECOND_TB_BIT, last_cb_present_second_tb); pdu.is_inline_tb_crc = tb_crc; @@ -556,12 +591,12 @@ class dl_pdsch_pdu_builder pdu.pdsch_maintenance_v3.tb_size_lbrm_bytes = tb_size_lbrm_bytes; // Fill the bitmap. - set_bitmap_bit(pdu.pdsch_maintenance_v3.tb_crc_required, - dl_pdsch_maintenance_parameters_v3::TB_BITMAP_FIRST_TB_BIT, - tb_crc_first_tb_required); - set_bitmap_bit(pdu.pdsch_maintenance_v3.tb_crc_required, - dl_pdsch_maintenance_parameters_v3::TB_BITMAP_SECOND_TB_BIT, - tb_crc_second_tb_required); + detail::set_bitmap_bit(pdu.pdsch_maintenance_v3.tb_crc_required, + dl_pdsch_maintenance_parameters_v3::TB_BITMAP_FIRST_TB_BIT, + tb_crc_first_tb_required); + detail::set_bitmap_bit(pdu.pdsch_maintenance_v3.tb_crc_required, + dl_pdsch_maintenance_parameters_v3::TB_BITMAP_SECOND_TB_BIT, + tb_crc_second_tb_required); return *this; } diff --git a/tests/unittests/fapi/message_builder_helpers.cpp b/tests/unittests/fapi/message_builder_helpers.cpp index a955f2f4fa..cdb79f985c 100644 --- a/tests/unittests/fapi/message_builder_helpers.cpp +++ b/tests/unittests/fapi/message_builder_helpers.cpp @@ -9,7 +9,6 @@ */ #include "message_builder_helpers.h" -#include "srsran/adt/bitmap_utils.h" #include static std::mt19937 gen(0); From 4d2e7130daa95f591bbbba1a672b87954ba095b4 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 14:31:08 +0200 Subject: [PATCH 172/407] cu_cp: use drb to be modified in ue context modification for reestablishment to align to oran spec --- ...blishment_context_modification_routine.cpp | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 224b5ac125..fe061138ef 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -11,6 +11,7 @@ #include "reestablishment_context_modification_routine.h" #include "pdu_session_routine_helpers.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" +#include "srsran/f1ap/common/ue_context_config.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -182,11 +183,6 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat const slotted_id_vector& e1ap_pdu_session_resource_modify_list) { - // Set up SRB2 in DU - f1ap_srb_to_setup srb2; - srb2.srb_id = srb_id_t::srb2; - ue_context_mod_req.srbs_to_be_setup_mod_list.push_back(srb2); - for (const auto& e1ap_item : e1ap_pdu_session_resource_modify_list) { cu_cp_pdu_session_resource_modify_response_item item; item.pdu_session_id = e1ap_item.pdu_session_id; @@ -217,31 +213,15 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat // Fill UE context modification for DU { - f1ap_drb_to_setup drb_setup_mod_item; - drb_setup_mod_item.drb_id = e1ap_drb_item.drb_id; + f1ap_drb_to_modify drb_modified_item; + drb_modified_item.drb_id = e1ap_drb_item.drb_id; // Add up tnl info for (const auto& ul_up_transport_param : e1ap_drb_item.ul_up_transport_params) { - drb_setup_mod_item.uluptnl_info_list.push_back(ul_up_transport_param.up_tnl_info); + drb_modified_item.uluptnl_info_list.push_back(ul_up_transport_param.up_tnl_info); } - // Add rlc mode - drb_setup_mod_item.mode = drb_up_context.rlc_mod; - drb_setup_mod_item.pdcp_sn_len = drb_up_context.pdcp_cfg.tx.sn_size; - - // fill QoS info - drb_setup_mod_item.qos_info.drb_qos = drb_up_context.qos_params; - drb_setup_mod_item.qos_info.s_nssai = drb_up_context.s_nssai; - drb_setup_mod_item.qos_info.notif_ctrl = drb_notification_control::active; - // Fill QoS flows for UE context modification. - for (const auto& flow : drb_up_context.qos_flows) { - // Add mapped flows and extract required QoS info from original NGAP request - flow_mapped_to_drb mapped_flow_item; - mapped_flow_item.qos_flow_id = flow.first; - mapped_flow_item.qos_flow_level_qos_params = drb_up_context.qos_params; - drb_setup_mod_item.qos_info.flows_mapped_to_drb_list.push_back(mapped_flow_item); - } - ue_context_mod_req.drbs_to_be_setup_mod_list.push_back(drb_setup_mod_item); + ue_context_mod_req.drbs_to_be_modified_list.push_back(drb_modified_item); } } @@ -297,7 +277,7 @@ bool reestablishment_context_modification_routine::generate_bearer_context_modif e1ap_pdu_session_res_to_modify_item e1ap_mod_item; e1ap_mod_item.pdu_session_id = pdu_session.pdu_session_id; - for (const auto& drb_item : ue_context_modification_resp.drbs_setup_list) { + for (const auto& drb_item : ue_context_modification_resp.drbs_modified_list) { // Only include the DRB if it belongs to the this session. if (pdu_session.drb_modified_list_ng_ran.contains(drb_item.drb_id)) { // DRB belongs to this PDU session From b9763249122337ec7686088a1b71f6eca4893f58 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 1 Aug 2024 14:31:35 +0200 Subject: [PATCH 173/407] cu_cp: improve reestablishment unittest to make sure ue context modification contains drb to be modified --- tests/unittests/cu_cp/cu_cp_test_environment.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index e71031ceb3..ff512804f0 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -978,6 +978,11 @@ bool cu_cp_test_environment::reestablish_ue(unsigned du_idx, // STATUS: CU-CP sends F1AP UE Context Modification Request to DU. report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), "F1AP UEContextModificationRequest NOT sent"); + report_fatal_error_if_not(f1ap_pdu.pdu.init_msg().value.ue_context_mod_request()->drbs_to_be_modified_list_present, + "UE Context Modification Request for RRC Reestablishment must contain DRBs to be modified"); + report_fatal_error_if_not( + not f1ap_pdu.pdu.init_msg().value.ue_context_mod_request()->drbs_to_be_setup_mod_list_present, + "UE Context Modification Request for RRC Reestablishment must not contain DRBs to be setup"); // EVENT: Inject F1AP UE Context Modification Response get_du(du_idx).push_ul_pdu(test_helpers::generate_ue_context_modification_response( From 0e2b9e172bbc43f0b1817cd175a9f756ce1a37ce Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 9 Aug 2024 16:41:39 +0200 Subject: [PATCH 174/407] f1ap: handle optional qos_info case for drb-to-be-modified case --- .../procedures/f1ap_du_ue_context_common.cpp | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp index 4dbe66fbc2..be41e9c445 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp @@ -38,29 +38,36 @@ static void fill_common_drb_config_request_fields(f1ap_drb_to_setup& drb_obj, co drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(drb_item.ul_up_tnl_info_to_be_setup_list); // TODO: Handle Dynamic 5QI. - const auto& asn1_drbinfo = drb_item.qos_info.choice_ext().value().drb_info(); - drb_obj.qos_info.drb_qos.qos_characteristics.non_dyn_5qi.emplace(); - auto& nondyn_5qi = drb_obj.qos_info.drb_qos.qos_characteristics.non_dyn_5qi.value(); - nondyn_5qi.five_qi = uint_to_five_qi(asn1_drbinfo.drb_qos.qos_characteristics.non_dyn_5qi().five_qi); - drb_obj.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = - asn1_drbinfo.drb_qos.ngra_nalloc_retention_prio.prio_level; - drb_obj.qos_info.s_nssai.sst = asn1_drbinfo.snssai.sst.to_number(); - if (asn1_drbinfo.snssai.sd_present) { - drb_obj.qos_info.s_nssai.sd = drb_item.qos_info.choice_ext().value().drb_info().snssai.sd.to_number(); + const asn1::f1ap::drb_info_s* asn1_drb_info = nullptr; + if constexpr (std::is_same_v) { + if (drb_item.qos_info_present) { + asn1_drb_info = &drb_item.qos_info.choice_ext().value().drb_info(); + } + } else { + asn1_drb_info = &drb_item.qos_info.choice_ext().value().drb_info(); } - // TODO: Do not populate gbr_flow_info for non-GBR flows. - if (asn1_drbinfo.drb_qos.gbr_qos_flow_info_present) { - drb_obj.qos_info.drb_qos.gbr_qos_info.emplace(); - auto& gbr = drb_obj.qos_info.drb_qos.gbr_qos_info.value(); - gbr.max_br_dl = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; - gbr.max_br_ul = asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; - gbr.gbr_dl = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; - gbr.gbr_ul = asn1_drbinfo.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; - if (asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { - gbr.max_packet_loss_rate_dl.emplace(asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); + if (asn1_drb_info != nullptr) { + auto& nondyn_5qi = drb_obj.qos_info.drb_qos.qos_characteristics.non_dyn_5qi.emplace(); + nondyn_5qi.five_qi = uint_to_five_qi(asn1_drb_info->drb_qos.qos_characteristics.non_dyn_5qi().five_qi); + drb_obj.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = + asn1_drb_info->drb_qos.ngra_nalloc_retention_prio.prio_level; + drb_obj.qos_info.s_nssai.sst = asn1_drb_info->snssai.sst.to_number(); + if (asn1_drb_info->snssai.sd_present) { + drb_obj.qos_info.s_nssai.sd = asn1_drb_info->snssai.sd.to_number(); } - if (asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present) { - gbr.max_packet_loss_rate_dl.emplace(asn1_drbinfo.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul); + // TODO: Do not populate gbr_flow_info for non-GBR flows. + if (asn1_drb_info->drb_qos.gbr_qos_flow_info_present) { + auto& gbr = drb_obj.qos_info.drb_qos.gbr_qos_info.emplace(); + gbr.max_br_dl = asn1_drb_info->drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; + gbr.max_br_ul = asn1_drb_info->drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; + gbr.gbr_dl = asn1_drb_info->drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; + gbr.gbr_ul = asn1_drb_info->drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; + if (asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { + gbr.max_packet_loss_rate_dl.emplace(asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); + } + if (asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present) { + gbr.max_packet_loss_rate_dl.emplace(asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul); + } } } } From c91c136bd2cd5dbcf0960d6a0b1ef41db74fb0c5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sun, 11 Aug 2024 09:48:16 +0200 Subject: [PATCH 175/407] du manager: make sure all previous SRBs are configured during reestablishment --- .../procedures/ue_configuration_procedure.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index ba55fd8389..4060d9c02d 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -75,21 +75,19 @@ async_task ue_configuration_procedure::stop_drbs_to_rem() void ue_configuration_procedure::update_ue_context() { // > Create DU UE SRB objects. - for (srb_id_t srbid : request.srbs_to_setup) { + for (const auto& bearer : ue->resources->rlc_bearers) { + if (bearer.drb_id.has_value()) { + continue; + } + srb_id_t srbid = to_srb_id(bearer.lcid); if (ue->bearers.srbs().contains(srbid)) { // >> In case the SRB already exists, we ignore the request for its configuration. continue; } srbs_added.push_back(srbid); - lcid_t lcid = srb_id_to_lcid(srbid); - auto it = std::find_if(ue->resources->rlc_bearers.begin(), - ue->resources->rlc_bearers.end(), - [lcid](const rlc_bearer_config& e) { return e.lcid == lcid; }); - srsran_assert(it != ue->resources->rlc_bearers.end(), "SRB should have been allocated at this point"); - // >> Create SRB bearer. - du_ue_srb& srb = ue->bearers.add_srb(srbid, it->rlc_cfg); + du_ue_srb& srb = ue->bearers.add_srb(srbid, bearer.rlc_cfg); // >> Create RLC SRB entity. srb.rlc_bearer = create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, From f8300fa839f8f560ae6cbb96658328aa19294af2 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 1 Aug 2024 16:29:35 +0100 Subject: [PATCH 176/407] rlc: start adding a byte limit to the RLC queue --- include/srsran/rlc/rlc_tx.h | 2 +- lib/du_manager/du_ue/du_ue_adapters.h | 4 ++-- lib/rlc/rlc_sdu_queue_lockfree.h | 17 +++++++++---- lib/rlc/rlc_tx_am_entity.cpp | 11 +++++---- lib/rlc/rlc_tx_tm_entity.cpp | 8 ++++--- lib/rlc/rlc_tx_um_entity.cpp | 16 +++++++++---- tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp | 2 +- .../rlc/rlc_handle_status_report.cpp | 2 +- .../integrationtests/rlc/rlc_stress_test_f1.h | 2 +- .../rlc/rlc_sdu_queue_lockfree_test.cpp | 24 ++++++++++++------- tests/unittests/rlc/rlc_tx_am_test.cpp | 4 +++- tests/unittests/rlc/rlc_tx_tm_test.cpp | 2 +- tests/unittests/rlc/rlc_um_test.cpp | 4 +++- 13 files changed, 65 insertions(+), 33 deletions(-) diff --git a/include/srsran/rlc/rlc_tx.h b/include/srsran/rlc/rlc_tx.h index 978510b01f..4e8b89ec99 100644 --- a/include/srsran/rlc/rlc_tx.h +++ b/include/srsran/rlc/rlc_tx.h @@ -89,7 +89,7 @@ class rlc_tx_upper_layer_data_notifier /// lower layers. /// /// \param max_tx_pdcp_sn Highest transmitted PDCP PDU sequence number. - virtual void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) = 0; + virtual void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t bytes_free_in_queue) = 0; /// \brief Informs upper layer about the highest PDCP PDU sequence number of the PDCP PDU that was successfully /// delivered in sequence towards the UE. diff --git a/lib/du_manager/du_ue/du_ue_adapters.h b/lib/du_manager/du_ue/du_ue_adapters.h index a17346a1be..2ab5f152f0 100644 --- a/lib/du_manager/du_ue/du_ue_adapters.h +++ b/lib/du_manager/du_ue/du_ue_adapters.h @@ -127,7 +127,7 @@ class rlc_f1c_tx_data_notifier : public rlc_tx_upper_layer_data_notifier void disconnect(); - void on_transmitted_sdu(uint32_t max_deliv_pdcp_sn) override + void on_transmitted_sdu(uint32_t max_deliv_pdcp_sn, uint32_t queue_free_bytes) override { f1c_bearer* b = bearer.load(std::memory_order_relaxed); srsran_assert(b != nullptr, "RLC to F1-C TX data notifier is disconnected"); @@ -166,7 +166,7 @@ class rlc_f1u_tx_data_notifier : public rlc_tx_upper_layer_data_notifier void disconnect(); - void on_transmitted_sdu(uint32_t max_deliv_pdcp_sn) override + void on_transmitted_sdu(uint32_t max_deliv_pdcp_sn, uint32_t queue_free_bytes) override { f1u_tx_delivery_handler* h = handler.load(std::memory_order_relaxed); srsran_assert(h != nullptr, "RLC to F1-U TX data notifier is disconnected"); diff --git a/lib/rlc/rlc_sdu_queue_lockfree.h b/lib/rlc/rlc_sdu_queue_lockfree.h index fb119d95c5..8fa7aae568 100644 --- a/lib/rlc/rlc_sdu_queue_lockfree.h +++ b/lib/rlc/rlc_sdu_queue_lockfree.h @@ -35,7 +35,8 @@ namespace srsran { class rlc_sdu_queue_lockfree { public: - explicit rlc_sdu_queue_lockfree(uint16_t capacity_, rlc_bearer_logger& logger_) : logger(logger_), capacity(capacity_) + explicit rlc_sdu_queue_lockfree(uint16_t capacity_, uint32_t byte_limit_, rlc_bearer_logger& logger_) : + logger(logger_), capacity(capacity_), byte_limit(byte_limit_) { sdu_states = std::make_unique[]>(capacity); sdu_sizes = std::make_unique[]>(capacity); @@ -56,11 +57,18 @@ class rlc_sdu_queue_lockfree /// The write fails (returns false) in the following cases: /// - The internal queue is full. /// - Another SDU with same value of [PDCP_SN mod capacity] exists (either valid or discarded) in the queue. + /// - The new SDU makes the queue exceed a preconfigured limit of buffered bytes. /// /// \param sdu The RLC SDU that shall be written. /// \return True if the RLC SDU was successfully written to the queue, otherwise false. bool write(rlc_sdu sdu) { + // first check if we do not exeed the byte limit + state_t st = get_state(); + if (sdu.buf.length() + st.n_bytes >= byte_limit) { + return false; + } + // if the SDU has a PDCP SN, first check the slot is available std::optional pdcp_sn = sdu.pdcp_sn; const size_t sdu_size = sdu.buf.length(); @@ -267,7 +275,8 @@ class rlc_sdu_queue_lockfree rlc_bearer_logger& logger; - uint16_t capacity; + const uint16_t capacity; + const uint32_t byte_limit; /// Combined atomic state of the queue reflecting the number of SDUs and the number of bytes. /// Upper 32 bit: n_sdus; Lower 32 bit: n_bytes @@ -309,8 +318,8 @@ struct formatter { } template - auto format(const srsran::rlc_sdu_queue_lockfree::state_t& state, FormatContext& ctx) - -> decltype(std::declval().out()) + auto format(const srsran::rlc_sdu_queue_lockfree::state_t& state, + FormatContext& ctx) -> decltype(std::declval().out()) { return format_to(ctx.out(), "queued_sdus={} queued_bytes={}", state.n_sdus, state.n_bytes); } diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index a929f679fe..0c347e2a40 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -19,6 +19,8 @@ using namespace srsran; +const uint32_t queue_bytes_limit = 6172672; + rlc_tx_am_entity::rlc_tx_am_entity(gnb_du_id_t gnb_du_id, du_ue_index_t ue_index, rb_id_t rb_id_, @@ -45,7 +47,7 @@ rlc_tx_am_entity::rlc_tx_am_entity(gnb_du_id_t gnb_du_i ue_executor_, timers), cfg(config), - sdu_queue(cfg.queue_size, logger), + sdu_queue(cfg.queue_size, queue_bytes_limit, logger), retx_queue(window_size(to_number(cfg.sn_field_length))), mod(cardinality(to_number(cfg.sn_field_length))), am_window_size(window_size(to_number(cfg.sn_field_length))), @@ -243,8 +245,9 @@ size_t rlc_tx_am_entity::build_new_pdu(span rlc_pdu_buf) } // Read new SDU from TX queue - rlc_sdu sdu; - logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue.get_state()); + rlc_sdu sdu; + rlc_sdu_queue_lockfree::state_t queue_state = sdu_queue.get_state(); + logger.log_debug("Reading SDU from sdu_queue. {}", queue_state); if (not sdu_queue.read(sdu)) { logger.log_debug("SDU queue empty. grant_len={}", grant_len); return 0; @@ -264,7 +267,7 @@ size_t rlc_tx_am_entity::build_new_pdu(span rlc_pdu_buf) if (sdu.is_retx) { upper_dn.on_retransmitted_sdu(sdu.pdcp_sn.value()); } else { - upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value()); + upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_state.n_bytes); } } diff --git a/lib/rlc/rlc_tx_tm_entity.cpp b/lib/rlc/rlc_tx_tm_entity.cpp index 44ad204b3b..f37f71e54b 100644 --- a/lib/rlc/rlc_tx_tm_entity.cpp +++ b/lib/rlc/rlc_tx_tm_entity.cpp @@ -12,6 +12,8 @@ using namespace srsran; +const uint32_t queue_bytes_limit = 6172672; + rlc_tx_tm_entity::rlc_tx_tm_entity(gnb_du_id_t du_id, du_ue_index_t ue_index, rb_id_t rb_id_, @@ -38,7 +40,7 @@ rlc_tx_tm_entity::rlc_tx_tm_entity(gnb_du_id_t du_id, ue_executor_, timers), cfg(config), - sdu_queue(cfg.queue_size, logger), + sdu_queue(cfg.queue_size, queue_bytes_limit, logger), pcap_context(ue_index, rb_id_, /* is_uplink */ false) { metrics_low.metrics_set_mode(rlc_mode::tm); @@ -87,13 +89,13 @@ size_t rlc_tx_tm_entity::pull_pdu(span mac_sdu_buf) // Get a new SDU, if none is currently being transmitted if (sdu.buf.empty()) { - logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue.get_state()); if (not sdu_queue.read(sdu)) { logger.log_debug("SDU queue empty. grant_len={}", grant_len); return 0; } logger.log_debug("Read SDU. pdcp_sn={} sdu_len={}", sdu.pdcp_sn, sdu.buf.length()); } + rlc_sdu_queue_lockfree::state_t queue_state = sdu_queue.get_state(); size_t sdu_len = sdu.buf.length(); if (sdu_len > grant_len) { @@ -104,7 +106,7 @@ size_t rlc_tx_tm_entity::pull_pdu(span mac_sdu_buf) // Notify the upper layer about the beginning of the transfer of the current SDU if (sdu.pdcp_sn.has_value()) { - upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value()); + upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_state.n_bytes); } // In TM there is no header, just pass the plain SDU diff --git a/lib/rlc/rlc_tx_um_entity.cpp b/lib/rlc/rlc_tx_um_entity.cpp index 2a41332320..23690caca7 100644 --- a/lib/rlc/rlc_tx_um_entity.cpp +++ b/lib/rlc/rlc_tx_um_entity.cpp @@ -15,6 +15,8 @@ using namespace srsran; +const uint32_t queue_bytes_limit = 6172672; + rlc_tx_um_entity::rlc_tx_um_entity(gnb_du_id_t du_id, du_ue_index_t ue_index, rb_id_t rb_id_, @@ -41,7 +43,7 @@ rlc_tx_um_entity::rlc_tx_um_entity(gnb_du_id_t du_id, ue_executor_, timers), cfg(config), - sdu_queue(cfg.queue_size, logger), + sdu_queue(cfg.queue_size, queue_bytes_limit, logger), mod(cardinality(to_number(cfg.sn_field_length))), head_len_full(rlc_um_pdu_header_size_complete_sdu), head_len_first(rlc_um_pdu_header_size_no_so(cfg.sn_field_length)), @@ -129,16 +131,22 @@ size_t rlc_tx_um_entity::pull_pdu(span mac_sdu_buf) // Get a new SDU, if none is currently being transmitted if (sdu.buf.empty()) { srsran_sanity_check(next_so == 0, "New TX SDU, but next_so={} > 0.", next_so); - logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue.get_state()); + + // Read new SDU if (not sdu_queue.read(sdu)) { logger.log_debug("SDU queue empty. grant_len={}", grant_len); return {}; } - logger.log_debug("Read SDU. sn={} pdcp_sn={} sdu_len={}", st.tx_next, sdu.pdcp_sn, sdu.buf.length()); + rlc_sdu_queue_lockfree::state_t queue_state = sdu_queue.get_state(); + logger.log_debug("Read SDU. sn={} pdcp_sn={} sdu_len={} queue_state=[{}]", + st.tx_next, + sdu.pdcp_sn, + sdu.buf.length(), + queue_state); // Notify the upper layer about the beginning of the transfer of the current SDU if (sdu.pdcp_sn.has_value()) { - upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value()); + upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_state.n_bytes); } } diff --git a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp index ee020da3f5..067c989a46 100644 --- a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp +++ b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp @@ -35,7 +35,7 @@ class rlc_tx_am_test_frame : public rlc_tx_upper_layer_data_notifier, rlc_tx_am_test_frame(rlc_am_sn_size sn_size_) : sn_size(sn_size_), status(sn_size_) {} // rlc_tx_upper_layer_data_notifier interface - void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) override {} + void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t queue_free_bytes) override {} void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override {} void on_retransmitted_sdu(uint32_t max_retx_pdcp_sn) override {} void on_delivered_retransmitted_sdu(uint32_t max_deliv_retx_pdcp_sn) override {} diff --git a/tests/benchmarks/rlc/rlc_handle_status_report.cpp b/tests/benchmarks/rlc/rlc_handle_status_report.cpp index 4a478f88e0..0ee8993d8f 100644 --- a/tests/benchmarks/rlc/rlc_handle_status_report.cpp +++ b/tests/benchmarks/rlc/rlc_handle_status_report.cpp @@ -34,7 +34,7 @@ class rlc_tx_am_test_frame : public rlc_tx_upper_layer_data_notifier, rlc_tx_am_test_frame(rlc_am_sn_size sn_size_) : sn_size(sn_size_), status(sn_size_) {} // rlc_tx_upper_layer_data_notifier interface - void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) override {} + void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t queue_free_bytes) override {} void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override {} void on_retransmitted_sdu(uint32_t max_retx_pdcp_sn) override {} void on_delivered_retransmitted_sdu(uint32_t max_deliv_retx_pdcp_sn) override {} diff --git a/tests/integrationtests/rlc/rlc_stress_test_f1.h b/tests/integrationtests/rlc/rlc_stress_test_f1.h index 6d1a6a9ace..308249ba60 100644 --- a/tests/integrationtests/rlc/rlc_stress_test_f1.h +++ b/tests/integrationtests/rlc/rlc_stress_test_f1.h @@ -45,7 +45,7 @@ class f1ap_dummy : public pdcp_tx_lower_notifier, } // RLC -> F1AP -> PDCP - void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) final + void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t queue_free_bytes) final { logger.log_debug("Transmitted SDU called"); // TODO diff --git a/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp b/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp index c14aa569dc..c7ac606cee 100644 --- a/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp +++ b/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp @@ -21,7 +21,9 @@ void queue_unqueue_test() { rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU queue unqueue test"}; - rlc_sdu_queue_lockfree tx_queue(4096, logger); + + const uint32_t queue_bytes_limit = 6172672; + rlc_sdu_queue_lockfree tx_queue(4096, queue_bytes_limit, logger); // Write 1 SDU byte_buffer buf = byte_buffer::create({0x00, 0x01}).value(); @@ -53,8 +55,10 @@ void full_capacity_test() { rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU capacity test"}; - unsigned capacity = 5; - rlc_sdu_queue_lockfree tx_queue(capacity, logger); + + unsigned capacity = 5; + const uint32_t queue_bytes_limit = 6172672; + rlc_sdu_queue_lockfree tx_queue(capacity, queue_bytes_limit, logger); // Write Capacity + 1 SDUs for (uint32_t pdcp_sn = 0; pdcp_sn < capacity + 1; pdcp_sn++) { @@ -95,9 +99,10 @@ void discard_test() { rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU discard test"}; - unsigned capacity = 10; - unsigned n_sdus = capacity; - rlc_sdu_queue_lockfree tx_queue(capacity, logger); + unsigned capacity = 10; + unsigned n_sdus = capacity; + const uint32_t queue_bytes_limit = 6172672; + rlc_sdu_queue_lockfree tx_queue(capacity, queue_bytes_limit, logger); // Fill SDU queue with SDUs for (uint32_t pdcp_sn = 0; pdcp_sn < n_sdus; pdcp_sn++) { @@ -138,9 +143,10 @@ void discard_all_test() { rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU discard all test"}; - unsigned capacity = 10; - unsigned n_sdus = capacity / 2; - rlc_sdu_queue_lockfree tx_queue(capacity, logger); + unsigned capacity = 10; + unsigned n_sdus = capacity / 2; + const uint32_t queue_bytes_limit = 6172672; + rlc_sdu_queue_lockfree tx_queue(capacity, queue_bytes_limit, logger); // Fill SDU queue with SDUs for (uint32_t pdcp_sn = 0; pdcp_sn < n_sdus; pdcp_sn++) { diff --git a/tests/unittests/rlc/rlc_tx_am_test.cpp b/tests/unittests/rlc/rlc_tx_am_test.cpp index bb0adad0e0..eb95e12e73 100644 --- a/tests/unittests/rlc/rlc_tx_am_test.cpp +++ b/tests/unittests/rlc/rlc_tx_am_test.cpp @@ -29,6 +29,7 @@ class rlc_tx_am_test_frame : public rlc_tx_upper_layer_data_notifier, std::list highest_delivered_pdcp_sn_list; std::list highest_retransmitted_pdcp_sn_list; std::list highest_delivered_retransmitted_pdcp_sn_list; + std::list queue_free_size_list; rlc_am_sn_size sn_size; rlc_am_status_pdu status; bool status_required = false; @@ -40,10 +41,11 @@ class rlc_tx_am_test_frame : public rlc_tx_upper_layer_data_notifier, rlc_tx_am_test_frame(rlc_am_sn_size sn_size_) : sn_size(sn_size_), status(sn_size_) {} // rlc_tx_upper_layer_data_notifier interface - void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) override + void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t queue_free_size) override { // store in list highest_transmitted_pdcp_sn_list.push_back(max_tx_pdcp_sn); + queue_free_size_list.push_back(queue_free_size); } void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override diff --git a/tests/unittests/rlc/rlc_tx_tm_test.cpp b/tests/unittests/rlc/rlc_tx_tm_test.cpp index 55039dd779..0cfa01005b 100644 --- a/tests/unittests/rlc/rlc_tx_tm_test.cpp +++ b/tests/unittests/rlc/rlc_tx_tm_test.cpp @@ -31,7 +31,7 @@ class rlc_tx_tm_test_frame : public rlc_tx_upper_layer_data_notifier, uint32_t bsr_count = 0; // rlc_tx_upper_layer_data_notifier interface - void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) override {} + void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t queue_free_bytes) override {} void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override {} void on_retransmitted_sdu(uint32_t max_retx_pdcp_sn) override {} void on_delivered_retransmitted_sdu(uint32_t max_deliv_retx_pdcp_sn) override {} diff --git a/tests/unittests/rlc/rlc_um_test.cpp b/tests/unittests/rlc/rlc_um_test.cpp index aa8284cc6e..25b1e52956 100644 --- a/tests/unittests/rlc/rlc_um_test.cpp +++ b/tests/unittests/rlc/rlc_um_test.cpp @@ -28,6 +28,7 @@ class rlc_test_frame : public rlc_rx_upper_layer_data_notifier, std::queue sdu_queue; uint32_t sdu_counter = 0; std::list transmitted_pdcp_sn_list; + std::list queue_free_bytes_list; uint32_t bsr = 0; uint32_t bsr_count = 0; @@ -39,10 +40,11 @@ class rlc_test_frame : public rlc_rx_upper_layer_data_notifier, } // rlc_tx_upper_layer_data_notifier interface - void on_transmitted_sdu(uint32_t max_tx_pdcp_sn) override + void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t queue_free_bytes) override { // store in list transmitted_pdcp_sn_list.push_back(max_tx_pdcp_sn); + transmitted_pdcp_sn_list.push_back(queue_free_bytes); } void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override {} void on_retransmitted_sdu(uint32_t max_retx_pdcp_sn) override {} From 8659322f549a77addcb5267bd55f6dbebccb9b78 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 1 Aug 2024 17:31:32 +0100 Subject: [PATCH 177/407] f1u,f1c: pass rlc queue free size to upper layers --- include/srsran/f1ap/du/f1c_bearer.h | 2 +- .../srsran/f1u/du/f1u_tx_delivery_handler.h | 2 +- lib/du_manager/du_ue/du_ue_adapters.cpp | 4 ++-- lib/du_manager/du_ue/du_ue_adapters.h | 4 ++-- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 4 ++-- lib/f1ap/du/ue_context/f1c_du_bearer_impl.h | 4 ++-- lib/f1u/du/f1u_bearer_impl.cpp | 20 +++++++++++++++++-- lib/f1u/du/f1u_bearer_impl.h | 10 +++++++++- lib/rlc/rlc_sdu_queue_lockfree.h | 3 +-- lib/rlc/rlc_tx_am_entity.cpp | 2 +- .../du_manager/du_manager_test_helpers.h | 2 +- .../f1ap/du/f1ap_du_test_helpers.cpp | 2 +- ...1ap_du_ue_context_setup_procedure_test.cpp | 2 +- tests/unittests/f1u/du/f1u_du_bearer_test.cpp | 10 +++++----- 14 files changed, 47 insertions(+), 24 deletions(-) diff --git a/include/srsran/f1ap/du/f1c_bearer.h b/include/srsran/f1ap/du/f1c_bearer.h index 2b79e5f3cf..d5ed84baff 100644 --- a/include/srsran/f1ap/du/f1c_bearer.h +++ b/include/srsran/f1ap/du/f1c_bearer.h @@ -38,7 +38,7 @@ class f1c_tx_delivery_handler /// the lower layers (i.e. by the RLC). /// /// \param highest_sn Highest transmitted PDCP PDU sequence number. - virtual void handle_transmit_notification(uint32_t highest_pdcp_sn) = 0; + virtual void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) = 0; /// \brief Informs the F1-C bearer about the highest PDCP PDU sequence number that was successfully /// delivered in sequence towards the UE. diff --git a/include/srsran/f1u/du/f1u_tx_delivery_handler.h b/include/srsran/f1u/du/f1u_tx_delivery_handler.h index 428437fb22..3d66504257 100644 --- a/include/srsran/f1u/du/f1u_tx_delivery_handler.h +++ b/include/srsran/f1u/du/f1u_tx_delivery_handler.h @@ -34,7 +34,7 @@ class f1u_tx_delivery_handler /// Safe execution from: pcell_executor /// /// \param highest_pdcp_sn The highest transmitted PDCP sequence number - virtual void handle_transmit_notification(uint32_t highest_pdcp_sn) = 0; + virtual void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) = 0; /// \brief Handles a delivery notification from lower layers (i.e. from RLC AM). /// diff --git a/lib/du_manager/du_ue/du_ue_adapters.cpp b/lib/du_manager/du_ue/du_ue_adapters.cpp index 1b62a6f8cf..ff918e6aab 100644 --- a/lib/du_manager/du_ue/du_ue_adapters.cpp +++ b/lib/du_manager/du_ue/du_ue_adapters.cpp @@ -23,7 +23,7 @@ class null_sink_f1c_bearer : public f1c_bearer void handle_pdu(byte_buffer pdu) override {} async_task handle_pdu_and_await_delivery(byte_buffer pdu) override { return launch_no_op_task(); } async_task handle_pdu_and_await_transmission(byte_buffer pdu) override { return launch_no_op_task(); } - void handle_transmit_notification(uint32_t highest_pdcp_sn) override {} + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_bytes_free) override {} void handle_delivery_notification(uint32_t highest_pdcp_sn) override {} void handle_sdu(byte_buffer_chain sdu) override {} } null_f1c_bearer; @@ -40,7 +40,7 @@ class null_sink_f1u_bearer : public f1u_bearer, f1u_tx_sdu_handler& get_tx_sdu_handler() override { return *this; } void handle_pdu(nru_dl_message msg) override {} - void handle_transmit_notification(uint32_t highest_pdcp_sn) override {} + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_bytes_free) override {} void handle_delivery_notification(uint32_t highest_pdcp_sn) override {} void handle_retransmit_notification(uint32_t highest_pdcp_sn) override {} void handle_delivery_retransmitted_notification(uint32_t highest_pdcp_sn) override {} diff --git a/lib/du_manager/du_ue/du_ue_adapters.h b/lib/du_manager/du_ue/du_ue_adapters.h index 2ab5f152f0..fd1ab21b37 100644 --- a/lib/du_manager/du_ue/du_ue_adapters.h +++ b/lib/du_manager/du_ue/du_ue_adapters.h @@ -131,7 +131,7 @@ class rlc_f1c_tx_data_notifier : public rlc_tx_upper_layer_data_notifier { f1c_bearer* b = bearer.load(std::memory_order_relaxed); srsran_assert(b != nullptr, "RLC to F1-C TX data notifier is disconnected"); - b->handle_transmit_notification(max_deliv_pdcp_sn); + b->handle_transmit_notification(max_deliv_pdcp_sn, queue_free_bytes); } void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override @@ -170,7 +170,7 @@ class rlc_f1u_tx_data_notifier : public rlc_tx_upper_layer_data_notifier { f1u_tx_delivery_handler* h = handler.load(std::memory_order_relaxed); srsran_assert(h != nullptr, "RLC to F1-U TX data notifier is disconnected"); - h->handle_transmit_notification(max_deliv_pdcp_sn); + h->handle_transmit_notification(max_deliv_pdcp_sn, queue_free_bytes); } void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp index b8c00b5add..0f24cffca1 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -73,7 +73,7 @@ void f1c_srb0_du_bearer::handle_sdu(byte_buffer_chain sdu) } } -void f1c_srb0_du_bearer::handle_transmit_notification(uint32_t highest_pdcp_sn) +void f1c_srb0_du_bearer::handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) { report_fatal_error("Transmission notifications do not exist for SRB0"); } @@ -205,7 +205,7 @@ async_task f1c_other_srb_du_bearer::handle_pdu_and_await_delivery(byte_buf return handle_pdu_and_await(std::move(pdu), false); } -void f1c_other_srb_du_bearer::handle_transmit_notification(uint32_t highest_pdcp_sn) +void f1c_other_srb_du_bearer::handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) { if (not ue_exec.defer([this, highest_pdcp_sn]() { handle_notification(highest_pdcp_sn, true); })) { logger.warning("Discarded transmit notification for SRB{} because the task executor queue is full.", diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h index 8d7fc85068..014d4f856b 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h @@ -39,7 +39,7 @@ class f1c_srb0_du_bearer final : public f1c_bearer /// transfer message. void handle_sdu(byte_buffer_chain sdu) override; - void handle_transmit_notification(uint32_t highest_pdcp_sn) override; + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) override; void handle_delivery_notification(uint32_t highest_pdcp_sn) override; void handle_pdu(byte_buffer pdu) override; @@ -73,7 +73,7 @@ class f1c_other_srb_du_bearer final : public f1c_bearer /// \param[in] sdu The message to be encoded in the RRC container of the UL RRC message transfer message to transmit. void handle_sdu(byte_buffer_chain sdu) override; - void handle_transmit_notification(uint32_t highest_pdcp_sn) override; + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) override; void handle_delivery_notification(uint32_t highest_pdcp_sn) override; void handle_pdu(byte_buffer sdu) override; diff --git a/lib/f1u/du/f1u_bearer_impl.cpp b/lib/f1u/du/f1u_bearer_impl.cpp index f5d6a5b87b..2958673357 100644 --- a/lib/f1u/du/f1u_bearer_impl.cpp +++ b/lib/f1u/du/f1u_bearer_impl.cpp @@ -93,11 +93,13 @@ void f1u_bearer_impl::handle_pdu_impl(nru_dl_message msg) } } -void f1u_bearer_impl::handle_transmit_notification(uint32_t highest_pdcp_sn) +void f1u_bearer_impl::handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_bytes_free) { // This function may be called from pcell_executor, since it only writes to an atomic variable - logger.log_debug("Storing highest transmitted pdcp_sn={}", highest_pdcp_sn); + logger.log_debug( + "Storing highest transmitted pdcp_sn={} and desired buffer size bs={}", highest_pdcp_sn, queue_bytes_free); highest_transmitted_pdcp_sn.store(highest_pdcp_sn, std::memory_order_relaxed); + desired_buffer_size_for_data_radio_bearer.store(queue_bytes_free, std::memory_order_relaxed); } void f1u_bearer_impl::handle_delivery_notification(uint32_t highest_pdcp_sn) @@ -121,6 +123,19 @@ void f1u_bearer_impl::handle_delivery_retransmitted_notification(uint32_t highes highest_delivered_retransmitted_pdcp_sn.store(highest_pdcp_sn, std::memory_order_relaxed); } +bool f1u_bearer_impl::fill_desired_buffer_size_of_data_radio_bearer(nru_dl_data_delivery_status& status) +{ + uint32_t cur_desired_buffer_size_for_data_radio_bearer = + desired_buffer_size_for_data_radio_bearer.load(std::memory_order_relaxed); + logger.log_debug("Adding desired buffer size for DRB. bs={}", cur_desired_buffer_size_for_data_radio_bearer); + status.desired_buffer_size_for_drb = cur_desired_buffer_size_for_data_radio_bearer; + if (cur_desired_buffer_size_for_data_radio_bearer != notif_desired_buffer_size_for_data_radio_bearer) { + notif_desired_buffer_size_for_data_radio_bearer = cur_desired_buffer_size_for_data_radio_bearer; + return true; + } + return false; +} + bool f1u_bearer_impl::fill_highest_transmitted_pdcp_sn(nru_dl_data_delivery_status& status) { uint32_t cur_highest_transmitted_pdcp_sn = highest_transmitted_pdcp_sn.load(std::memory_order_relaxed); @@ -175,6 +190,7 @@ void f1u_bearer_impl::fill_data_delivery_status(nru_ul_message& msg) nru_dl_data_delivery_status status = {}; bool status_changed = false; + status_changed |= fill_desired_buffer_size_of_data_radio_bearer(status); status_changed |= fill_highest_transmitted_pdcp_sn(status); status_changed |= fill_highest_delivered_pdcp_sn(status); status_changed |= fill_highest_retransmitted_pdcp_sn(status); diff --git a/lib/f1u/du/f1u_bearer_impl.h b/lib/f1u/du/f1u_bearer_impl.h index d6e4c80ce8..ea3fd3593e 100644 --- a/lib/f1u/du/f1u_bearer_impl.h +++ b/lib/f1u/du/f1u_bearer_impl.h @@ -22,6 +22,8 @@ namespace srsran { namespace srs_du { +const uint32_t queue_bytes_limit = 6172672; + class f1u_bearer_impl final : public f1u_bearer, public f1u_tx_sdu_handler, public f1u_tx_delivery_handler, @@ -44,7 +46,7 @@ class f1u_bearer_impl final : public f1u_bearer, f1u_rx_pdu_handler& get_rx_pdu_handler() override { return *this; } void handle_sdu(byte_buffer_chain sdu) override; - void handle_transmit_notification(uint32_t highest_pdcp_sn) override; + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_bytes_free) override; void handle_delivery_notification(uint32_t highest_pdcp_sn) override; void handle_retransmit_notification(uint32_t highest_pdcp_sn) override; void handle_delivery_retransmitted_notification(uint32_t highest_pdcp_sn) override; @@ -73,6 +75,8 @@ class f1u_bearer_impl final : public f1u_bearer, /// lower layers. unique_timer ul_notif_timer; + /// Holds the most recent information of the available space in the RLC SDU queue + std::atomic desired_buffer_size_for_data_radio_bearer{queue_bytes_limit}; /// Holds the most recent highest transmitted PDCP SN that is frequently updated by lower layers (i.e. by RLC AM/UM) std::atomic highest_transmitted_pdcp_sn{unset_pdcp_sn}; /// Holds the most recent highest delivered PDCP SN that is frequently updated by lower layers (i.e. by RLC AM) @@ -83,6 +87,9 @@ class f1u_bearer_impl final : public f1u_bearer, /// RLC AM) std::atomic highest_delivered_retransmitted_pdcp_sn{unset_pdcp_sn}; + /// Holds the latest information of the available space in the RLC SDU queue that was reported to the upper layers + /// (i.e. torward CU-UP) + uint32_t notif_desired_buffer_size_for_data_radio_bearer = queue_bytes_limit; /// Holds the last highest transmitted PDCP SN that was reported to upper layers (i.e. towards CU-UP) uint32_t notif_highest_transmitted_pdcp_sn = unset_pdcp_sn; /// Holds the last highest delivered PDCP SN that was reported to upper layers (i.e. towards CU-UP) @@ -92,6 +99,7 @@ class f1u_bearer_impl final : public f1u_bearer, /// Holds the last highest delivered retransmitted PDCP SN that was reported to upper layers (i.e. towards CU-UP) uint32_t notif_highest_delivered_retransmitted_pdcp_sn = unset_pdcp_sn; + bool fill_desired_buffer_size_of_data_radio_bearer(nru_dl_data_delivery_status& status); bool fill_highest_transmitted_pdcp_sn(nru_dl_data_delivery_status& status); bool fill_highest_delivered_pdcp_sn(nru_dl_data_delivery_status& status); bool fill_highest_retransmitted_pdcp_sn(nru_dl_data_delivery_status& status); diff --git a/lib/rlc/rlc_sdu_queue_lockfree.h b/lib/rlc/rlc_sdu_queue_lockfree.h index 8fa7aae568..de0f57bf61 100644 --- a/lib/rlc/rlc_sdu_queue_lockfree.h +++ b/lib/rlc/rlc_sdu_queue_lockfree.h @@ -318,8 +318,7 @@ struct formatter { } template - auto format(const srsran::rlc_sdu_queue_lockfree::state_t& state, - FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_sdu_queue_lockfree::state_t& state, FormatContext& ctx) { return format_to(ctx.out(), "queued_sdus={} queued_bytes={}", state.n_sdus, state.n_bytes); } diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index 0c347e2a40..ddb473c479 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -267,7 +267,7 @@ size_t rlc_tx_am_entity::build_new_pdu(span rlc_pdu_buf) if (sdu.is_retx) { upper_dn.on_retransmitted_sdu(sdu.pdcp_sn.value()); } else { - upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_state.n_bytes); + upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_bytes_limit - queue_state.n_bytes); } } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index c54ce58516..3d4350bd0a 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -81,7 +81,7 @@ class dummy_f1c_bearer : public f1c_bearer return launch_no_op_task(); } void handle_sdu(byte_buffer_chain sdu) override { last_tx_sdu = std::move(sdu); } - void handle_transmit_notification(uint32_t highest_pdcp_sn) override {} + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) override {} void handle_delivery_notification(uint32_t highest_pdcp_sn) override {} }; diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index faef15e77b..09e894aacd 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -343,7 +343,7 @@ void f1ap_du_test::run_ue_context_setup_procedure(du_ue_index_t ue_index, const // Report transmission notification back to F1AP. std::optional pdcp_sn = get_pdcp_sn(f1ap_req->rrc_container, pdcp_sn_size::size12bits, true, test_logger); - ue.f1c_bearers[LCID_SRB1].bearer->handle_transmit_notification(pdcp_sn.value()); + ue.f1c_bearers[LCID_SRB1].bearer->handle_transmit_notification(pdcp_sn.value(), 0); this->ctrl_worker.run_pending_tasks(); } diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index 6128b83693..d2427d0ca4 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -90,7 +90,7 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test void on_rrc_container_transmitted(uint32_t highest_pdcp_sn) { - this->test_ue->f1c_bearers[LCID_SRB1].bearer->handle_transmit_notification(highest_pdcp_sn); + this->test_ue->f1c_bearers[LCID_SRB1].bearer->handle_transmit_notification(highest_pdcp_sn, 0); this->ctrl_worker.run_pending_tasks(); } diff --git a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp index d1a1bb05fd..8daaa0d4e6 100644 --- a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp +++ b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp @@ -250,8 +250,8 @@ TEST_F(f1u_du_test, tx_pdcp_pdus_with_transmit_notification) constexpr uint32_t pdcp_sn = 123; constexpr uint32_t highest_pdcp_sn = 55; - f1u->handle_transmit_notification(highest_pdcp_sn); - f1u->handle_transmit_notification(highest_pdcp_sn + 1); + f1u->handle_transmit_notification(highest_pdcp_sn, 0); + f1u->handle_transmit_notification(highest_pdcp_sn + 1, 0); byte_buffer tx_pdcp_pdu1 = create_sdu_byte_buffer(pdu_size, pdcp_sn); auto chain1 = byte_buffer_chain::create(tx_pdcp_pdu1.deep_copy().value()); @@ -351,7 +351,7 @@ TEST_F(f1u_du_test, tx_pdcp_pdus_with_delivery_notification) EXPECT_TRUE(tester->tx_msg_list.empty()); // handle another transmit notification; check UL notif timer has been reset to full time - f1u->handle_transmit_notification(highest_pdcp_sn + 2); + f1u->handle_transmit_notification(highest_pdcp_sn + 2, 0); EXPECT_TRUE(tester->rx_discard_sdu_list.empty()); EXPECT_TRUE(tester->rx_sdu_list.empty()); @@ -385,8 +385,8 @@ TEST_F(f1u_du_test, tx_transmit_notification) { constexpr uint32_t highest_pdcp_sn = 123; - f1u->handle_transmit_notification(highest_pdcp_sn); - f1u->handle_transmit_notification(highest_pdcp_sn + 1); + f1u->handle_transmit_notification(highest_pdcp_sn, 0); + f1u->handle_transmit_notification(highest_pdcp_sn + 1, 0); EXPECT_TRUE(tester->rx_discard_sdu_list.empty()); EXPECT_TRUE(tester->rx_sdu_list.empty()); From 732c6f07a86ef0e55f9c3fe0ff1eddbdf816eed6 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 8 Aug 2024 14:42:09 +0100 Subject: [PATCH 178/407] rlc: added configuration options for queue byte limits --- .../flexible_du/du_high/du_high_config.h | 10 +-- .../du_high/du_high_config_cli11_schema.cpp | 8 ++- .../du_high/du_high_config_translators.cpp | 16 +++-- include/srsran/rlc/rlc_config.h | 71 ++++++++++--------- lib/rlc/rlc_tx_am_entity.cpp | 6 +- lib/rlc/rlc_tx_um_entity.cpp | 6 +- 6 files changed, 64 insertions(+), 53 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 eec64f7079..f764bde9ee 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -689,8 +689,9 @@ struct du_high_unit_rlc_tx_am_config { uint32_t max_retx_thresh; ///< Max retx threshold int32_t poll_pdu; ///< Insert poll bit after this many PDUs int32_t poll_byte; ///< Insert poll bit after this much data (bytes) - uint32_t max_window = 0; ///< Custom parameter to limit the maximum window size for memory reasons. 0 means no limit. - uint32_t queue_size = 4096; ///< RLC SDU queue size + uint32_t max_window = 0; ///< Custom parameter to limit the maximum window size for memory reasons. 0 means no limit. + uint32_t queue_size = 4096; ///< RLC SDU queue size + uint32_t queue_bytes = 4096 * 1507; ///< RLC SDU queue size in bytes }; /// RLC UM RX configuration @@ -724,8 +725,9 @@ struct du_high_unit_f1u_du_config { /// RLC UM TX configuration struct du_high_unit_rlc_tx_um_config { - uint16_t sn_field_length; ///< Number of bits used for sequence number - uint32_t queue_size; ///< RLC SDU queue size + uint16_t sn_field_length; ///< Number of bits used for sequence number + uint32_t queue_size; ///< RLC SDU queue size in pdus + uint32_t queue_size_bytes; ///< RLC SDU queue size in bytes }; /// RLC UM RX configuration 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 94c222f653..22ed24380f 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 @@ -1334,7 +1334,9 @@ static void configure_cli11_rlc_am_args(CLI::App& app, du_high_unit_rlc_am_confi rlc_am_params.tx.max_window, "Non-standard parameter that limits the tx window size. Can be used for limiting memory usage with " "large windows. 0 means no limits other than the SN size (i.e. 2^[sn_size-1])."); - add_option(*rlc_tx_am_subcmd, "--queue-size", rlc_am_params.tx.queue_size, "RLC AM TX SDU queue size") + add_option(*rlc_tx_am_subcmd, "--queue-size", rlc_am_params.tx.queue_size, "RLC AM TX SDU queue size in PDUs") + ->capture_default_str(); + add_option(*rlc_tx_am_subcmd, "--queue-bytes", rlc_am_params.tx.queue_bytes, "RLC AM TX SDU queue size in bytes") ->capture_default_str(); CLI::App* rlc_rx_am_subcmd = add_subcommand(app, "rx", "AM RX parameters"); add_option(*rlc_rx_am_subcmd, "--sn", rlc_am_params.rx.sn_field_length, "RLC AM RX SN")->capture_default_str(); @@ -1486,7 +1488,9 @@ static void configure_cli11_rlc_um_args(CLI::App& app, du_high_unit_rlc_um_confi { CLI::App* rlc_tx_um_subcmd = app.add_subcommand("tx", "UM TX parameters"); rlc_tx_um_subcmd->add_option("--sn", rlc_um_params.tx.sn_field_length, "RLC UM TX SN")->capture_default_str(); - rlc_tx_um_subcmd->add_option("--queue-size", rlc_um_params.tx.queue_size, "RLC UM TX SDU queue size") + rlc_tx_um_subcmd->add_option("--queue-size", rlc_um_params.tx.queue_size, "RLC UM TX SDU queue limit in PDUs") + ->capture_default_str(); + rlc_tx_um_subcmd->add_option("--queue-bytes", rlc_um_params.tx.queue_size_bytes, "RLC UM TX SDU queue limit in bytes") ->capture_default_str(); CLI::App* rlc_rx_um_subcmd = app.add_subcommand("rx", "UM TX parameters"); rlc_rx_um_subcmd->add_option("--sn", rlc_um_params.rx.sn_field_length, "RLC UM RX SN")->capture_default_str(); 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 22c7163bba..cef5404219 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 @@ -639,12 +639,13 @@ static rlc_am_config generate_du_rlc_am_config(const du_high_unit_rlc_am_config& if (!from_number(out_rlc.tx.sn_field_length, in_cfg.tx.sn_field_length)) { report_error("Invalid RLC AM TX SN: SN={}\n", in_cfg.tx.sn_field_length); } - out_rlc.tx.t_poll_retx = in_cfg.tx.t_poll_retx; - out_rlc.tx.max_retx_thresh = in_cfg.tx.max_retx_thresh; - out_rlc.tx.poll_pdu = in_cfg.tx.poll_pdu; - out_rlc.tx.poll_byte = in_cfg.tx.poll_byte; - out_rlc.tx.max_window = in_cfg.tx.max_window; - out_rlc.tx.queue_size = in_cfg.tx.queue_size; + out_rlc.tx.t_poll_retx = in_cfg.tx.t_poll_retx; + out_rlc.tx.max_retx_thresh = in_cfg.tx.max_retx_thresh; + out_rlc.tx.poll_pdu = in_cfg.tx.poll_pdu; + out_rlc.tx.poll_byte = in_cfg.tx.poll_byte; + out_rlc.tx.max_window = in_cfg.tx.max_window; + out_rlc.tx.queue_size = in_cfg.tx.queue_size; + out_rlc.tx.queue_size_bytes = in_cfg.tx.queue_bytes; //< RX SN if (!from_number(out_rlc.rx.sn_field_length, in_cfg.rx.sn_field_length)) { report_error("Invalid RLC AM RX SN: SN={}\n", in_cfg.rx.sn_field_length); @@ -719,7 +720,8 @@ std::map srsran::generate_du_qos_config(const du_high_ if (!from_number(out_rlc.um.tx.sn_field_length, qos.rlc.um.tx.sn_field_length)) { report_error("Invalid RLC UM TX SN: {}, SN={}\n", qos.five_qi, qos.rlc.um.tx.sn_field_length); } - out_rlc.um.tx.queue_size = qos.rlc.um.tx.queue_size; + out_rlc.um.tx.queue_size = qos.rlc.um.tx.queue_size; + out_rlc.um.tx.queue_size_bytes = qos.rlc.um.tx.queue_size_bytes; } else if (out_rlc.mode == rlc_mode::am) { // AM Config out_rlc.am = generate_du_rlc_am_config(qos.rlc.am); diff --git a/include/srsran/rlc/rlc_config.h b/include/srsran/rlc/rlc_config.h index b94faad737..fc61d6db3b 100644 --- a/include/srsran/rlc/rlc_config.h +++ b/include/srsran/rlc/rlc_config.h @@ -661,7 +661,8 @@ struct rlc_tx_am_config { int32_t poll_byte; ///< Insert poll bit after this much data (bytes) // Implementation-specific parameters that are not specified by 3GPP - uint32_t queue_size; ///< SDU queue size + uint32_t queue_size; ///< SDU queue size in PDUs + uint32_t queue_size_bytes; ///< SDU queue size in bytes uint32_t max_window; ///< Custom parameter to limit the maximum window size for memory reasons. 0 means no limit. }; @@ -691,7 +692,8 @@ struct rlc_tx_um_config { pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; // Implementation-specific parameters that are not specified by 3GPP - uint32_t queue_size; ///< SDU queue size + uint32_t queue_size; ///< SDU queue size + uint32_t queue_size_bytes; ///< SDU queue size in bytes }; /// \brief Configurable parameters for RLC UM @@ -742,7 +744,7 @@ namespace fmt { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } @@ -820,13 +822,13 @@ struct formatter { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } template - auto format(srsran::rlc_tx_tm_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_tx_tm_config& cfg, FormatContext& ctx) -> decltype(std::declval().out()) { return format_to(ctx.out(), "queue_size={}", cfg.queue_size); } @@ -836,13 +838,13 @@ struct formatter { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } template - auto format(srsran::rlc_rx_tm_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_rx_tm_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), ""); } @@ -858,7 +860,7 @@ struct formatter { } template - auto format(srsran::rlc_tm_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_tm_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), "{} {}", cfg.tx, cfg.rx); } @@ -874,10 +876,14 @@ struct formatter { } template - auto format(srsran::rlc_tx_um_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_tx_um_config& cfg, FormatContext& ctx) { - return format_to( - ctx.out(), "tx_sn_size={} pdcp_sn_len={} queue_size={}", cfg.sn_field_length, cfg.pdcp_sn_len, cfg.queue_size); + return format_to(ctx.out(), + "tx_sn_size={} pdcp_sn_len={} queue_size={} queue_size_bytes={}", + cfg.sn_field_length, + cfg.pdcp_sn_len, + cfg.queue_size, + cfg.queue_size_bytes); } }; @@ -891,7 +897,7 @@ struct formatter { } template - auto format(srsran::rlc_rx_um_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_rx_um_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), "rx_sn_size={} t_reassembly={}", cfg.sn_field_length, cfg.t_reassembly); } @@ -901,13 +907,13 @@ struct formatter { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } template - auto format(srsran::rlc_um_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_um_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), "{} {}", cfg.tx, cfg.rx); } @@ -917,25 +923,26 @@ struct formatter { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } template - auto format(srsran::rlc_tx_am_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_tx_am_config& cfg, FormatContext& ctx) { - return format_to( - ctx.out(), - "tx_sn_size={} pdcp_sn_len={} t_poll_retx={} max_retx={} poll_pdu={} poll_byte={} queue_size={} max_window={}", - cfg.sn_field_length, - cfg.pdcp_sn_len, - cfg.t_poll_retx, - cfg.max_retx_thresh, - cfg.poll_pdu, - cfg.poll_byte, - cfg.queue_size, - cfg.max_window); + return format_to(ctx.out(), + "tx_sn_size={} pdcp_sn_len={} t_poll_retx={} max_retx={} poll_pdu={} poll_byte={} queue_size={} " + "queue_size_bytes={} max_window={}", + cfg.sn_field_length, + cfg.pdcp_sn_len, + cfg.t_poll_retx, + cfg.max_retx_thresh, + cfg.poll_pdu, + cfg.poll_byte, + cfg.queue_size, + cfg.queue_size_bytes, + cfg.max_window); } }; @@ -943,13 +950,13 @@ struct formatter { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } template - auto format(srsran::rlc_rx_am_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_rx_am_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), "rx_sn_size={} t_reassembly={} t_status_prohibit={} max_sn_per_status={}", @@ -970,7 +977,7 @@ struct formatter { } template - auto format(srsran::rlc_am_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_am_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), "{} {}", cfg.tx, cfg.rx); } @@ -980,13 +987,13 @@ struct formatter { template <> struct formatter { template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + auto parse(ParseContext& ctx) { return ctx.begin(); } template - auto format(srsran::rlc_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::rlc_config& cfg, FormatContext& ctx) { if (cfg.mode == srsran::rlc_mode::tm) { return format_to(ctx.out(), "{} {}", cfg.mode, cfg.tm); diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index ddb473c479..eb8ac93278 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -19,8 +19,6 @@ using namespace srsran; -const uint32_t queue_bytes_limit = 6172672; - rlc_tx_am_entity::rlc_tx_am_entity(gnb_du_id_t gnb_du_id, du_ue_index_t ue_index, rb_id_t rb_id_, @@ -47,7 +45,7 @@ rlc_tx_am_entity::rlc_tx_am_entity(gnb_du_id_t gnb_du_i ue_executor_, timers), cfg(config), - sdu_queue(cfg.queue_size, queue_bytes_limit, logger), + sdu_queue(cfg.queue_size, cfg.queue_size_bytes, logger), retx_queue(window_size(to_number(cfg.sn_field_length))), mod(cardinality(to_number(cfg.sn_field_length))), am_window_size(window_size(to_number(cfg.sn_field_length))), @@ -267,7 +265,7 @@ size_t rlc_tx_am_entity::build_new_pdu(span rlc_pdu_buf) if (sdu.is_retx) { upper_dn.on_retransmitted_sdu(sdu.pdcp_sn.value()); } else { - upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_bytes_limit - queue_state.n_bytes); + upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), cfg.queue_size_bytes - queue_state.n_bytes); } } diff --git a/lib/rlc/rlc_tx_um_entity.cpp b/lib/rlc/rlc_tx_um_entity.cpp index 23690caca7..7cfc178e13 100644 --- a/lib/rlc/rlc_tx_um_entity.cpp +++ b/lib/rlc/rlc_tx_um_entity.cpp @@ -15,8 +15,6 @@ using namespace srsran; -const uint32_t queue_bytes_limit = 6172672; - rlc_tx_um_entity::rlc_tx_um_entity(gnb_du_id_t du_id, du_ue_index_t ue_index, rb_id_t rb_id_, @@ -43,7 +41,7 @@ rlc_tx_um_entity::rlc_tx_um_entity(gnb_du_id_t du_id, ue_executor_, timers), cfg(config), - sdu_queue(cfg.queue_size, queue_bytes_limit, logger), + sdu_queue(cfg.queue_size, cfg.queue_size_bytes, logger), mod(cardinality(to_number(cfg.sn_field_length))), head_len_full(rlc_um_pdu_header_size_complete_sdu), head_len_first(rlc_um_pdu_header_size_no_so(cfg.sn_field_length)), @@ -146,7 +144,7 @@ size_t rlc_tx_um_entity::pull_pdu(span mac_sdu_buf) // Notify the upper layer about the beginning of the transfer of the current SDU if (sdu.pdcp_sn.has_value()) { - upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), queue_state.n_bytes); + upper_dn.on_transmitted_sdu(sdu.pdcp_sn.value(), cfg.queue_size_bytes - queue_state.n_bytes); } } From 64351032a1c7041f706e25787be33b4de8c4123f Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 8 Aug 2024 15:44:40 +0100 Subject: [PATCH 179/407] du: moved qos config helpers to their own file --- .../du_high/du_high_config_translators.cpp | 1 + include/srsran/du/du_cell_config_helpers.h | 133 -------------- include/srsran/du/du_qos_config_helpers.h | 164 ++++++++++++++++++ .../benchmarks/du_high/du_high_benchmark.cpp | 1 + .../test_utils/du_high_env_simulator.cpp | 1 + .../du_manager/du_manager_test_helpers.cpp | 1 + .../du_ran_resource_manager_test.cpp | 1 + 7 files changed, 169 insertions(+), 133 deletions(-) create mode 100644 include/srsran/du/du_qos_config_helpers.h 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 cef5404219..661a5703d4 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 @@ -12,6 +12,7 @@ #include "du_high_config.h" #include "srsran/du/du_cell_config_helpers.h" #include "srsran/du/du_cell_config_validation.h" +#include "srsran/du/du_qos_config_helpers.h" #include "srsran/du/du_update_config_helpers.h" #include "srsran/e2/e2ap_configuration_helpers.h" #include "srsran/ran/duplex_mode.h" diff --git a/include/srsran/du/du_cell_config_helpers.h b/include/srsran/du/du_cell_config_helpers.h index 63a3b9fc90..73920a0539 100644 --- a/include/srsran/du/du_cell_config_helpers.h +++ b/include/srsran/du/du_cell_config_helpers.h @@ -99,138 +99,5 @@ inline du_cell_config make_default_du_cell_config(const cell_config_builder_para return cfg; } -/// Generates default QoS configuration used by gNB DU. The default configuration should be valid. -/// Dependencies between RLC timers should be considered: -/// * t-Reassembly: How long it takes for the RLC to detect a lost PDU. If larger than the MAC SR, we may drop a -/// PDU prematurely in the case UM, or we may send NACKs prematurely for the case of AM. -/// -/// * t-StatusProhibit: This value dictates how often the RLC is allowed to send status reports. If this value is -/// shorter than the MAC's SR, it may take longer than t-StatusProhibit to send a control PDU. -/// -/// * t-PollRetransmission: This value should be slightly larger than t-StatusProhibit and also account for RTT. -/// Moreover this value should be slightly larger than the SR of the MAC -/// to avoid spurious RETX'es from late status reports. See t-StatusProhibit for details. -/// -/// Note: These three timers will have implications in picking the PDCP's t-Reordering. See the generation of -/// t-Reordering default configuration for details. -/// -/// Dependencies between F1-U timers should be considered: -/// * t-Notify: This value determines the maximum backoff time to aggregate notifications (towards CU_UP) of which -/// PDCP SDUs have been transmitted (RLC UM/AM) or delivered (RLC AM). Small values increase the number of -/// F1-U messages. Large values may trigger unnecessary discard notifications due to expiration of the -/// PDCP discard timer. -inline std::map make_default_du_qos_config_list(bool warn_on_drop, int rlc_metrics_report) -{ - std::map qos_list = {}; - { - // 5QI=1 - du_qos_config cfg{}; - // RLC - cfg.rlc.mode = rlc_mode::um_bidir; - cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; - cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; - cfg.rlc.um.rx.t_reassembly = 50; - cfg.rlc.um.tx.queue_size = 4096; - cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); - // F1-U - cfg.f1u.t_notify = 10; - // MAC - cfg.mac = make_default_drb_mac_lc_config(); - cfg.mac.priority = 4; - cfg.mac.lcg_id = uint_to_lcg_id(1); - - qos_list[uint_to_five_qi(1)] = cfg; - } - { - // 5QI=2 - du_qos_config cfg{}; - // RLC - cfg.rlc.mode = rlc_mode::um_bidir; - cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; - cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; - cfg.rlc.um.rx.t_reassembly = 50; - cfg.rlc.um.tx.queue_size = 4096; - cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); - // F1-U - cfg.f1u.t_notify = 10; - // MAC - cfg.mac = make_default_drb_mac_lc_config(); - cfg.mac.priority = 4; - cfg.mac.lcg_id = uint_to_lcg_id(1); - - qos_list[uint_to_five_qi(2)] = cfg; - } - { - // 5QI=5 - du_qos_config cfg{}; - // RLC - cfg.rlc.mode = rlc_mode::am; - cfg.rlc.am.tx.sn_field_length = rlc_am_sn_size::size12bits; - cfg.rlc.am.tx.t_poll_retx = 80; - cfg.rlc.am.tx.poll_pdu = 64; - cfg.rlc.am.tx.poll_byte = 125; - cfg.rlc.am.tx.max_retx_thresh = 4; - cfg.rlc.am.tx.max_window = 0; - cfg.rlc.am.tx.queue_size = 4096; - cfg.rlc.am.rx.sn_field_length = rlc_am_sn_size::size12bits; - cfg.rlc.am.rx.t_reassembly = 80; - cfg.rlc.am.rx.t_status_prohibit = 10; - cfg.rlc.am.rx.max_sn_per_status = {}; - cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); - // F1-U - cfg.f1u.t_notify = 10; - // MAC - cfg.mac = make_default_drb_mac_lc_config(); - - qos_list[uint_to_five_qi(5)] = cfg; - } - { - // 5QI=7 - du_qos_config cfg{}; - // RLC - cfg.rlc.mode = rlc_mode::um_bidir; - cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; - cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; - cfg.rlc.um.rx.t_reassembly = 100; - cfg.rlc.um.tx.queue_size = 4096; - cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); - // F1-U - cfg.f1u.t_notify = 10; - cfg.f1u.warn_on_drop = warn_on_drop; - // MAC - cfg.mac = make_default_drb_mac_lc_config(); - cfg.mac.priority = 4; - cfg.mac.lcg_id = uint_to_lcg_id(1); - - qos_list[uint_to_five_qi(7)] = cfg; - } - { - // 5QI=9 - du_qos_config cfg{}; - // RLC - cfg.rlc.mode = rlc_mode::am; - cfg.rlc.am.tx.sn_field_length = rlc_am_sn_size::size18bits; - cfg.rlc.am.tx.t_poll_retx = 20; - cfg.rlc.am.tx.poll_pdu = 16; - cfg.rlc.am.tx.poll_byte = -1; - cfg.rlc.am.tx.max_retx_thresh = 32; - cfg.rlc.am.tx.max_window = 0; - cfg.rlc.am.tx.queue_size = 4096; - cfg.rlc.am.rx.sn_field_length = rlc_am_sn_size::size18bits; - cfg.rlc.am.rx.t_reassembly = 20; - cfg.rlc.am.rx.t_status_prohibit = 10; - cfg.rlc.am.rx.max_sn_per_status = {}; - cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); - // F1-U - cfg.f1u.t_notify = 10; - cfg.f1u.warn_on_drop = warn_on_drop; - // MAC - cfg.mac = make_default_drb_mac_lc_config(); - - qos_list[uint_to_five_qi(9)] = cfg; - } - return qos_list; -} - } // namespace config_helpers } // namespace srsran diff --git a/include/srsran/du/du_qos_config_helpers.h b/include/srsran/du/du_qos_config_helpers.h new file mode 100644 index 0000000000..e982e712b0 --- /dev/null +++ b/include/srsran/du/du_qos_config_helpers.h @@ -0,0 +1,164 @@ +/* + * + * 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 "du_cell_config.h" +#include "srsran/du/du_qos_config.h" +#include "srsran/mac/config/mac_config_helpers.h" +#include "srsran/ran/pdcch/pdcch_type0_css_coreset_config.h" +#include "srsran/ran/qos/five_qi.h" +#include "srsran/scheduler/config/scheduler_expert_config.h" +#include "srsran/scheduler/config/serving_cell_config_factory.h" +#include + +namespace srsran { +namespace config_helpers { + +/// Generates default QoS configuration used by gNB DU. The default configuration should be valid. +/// Dependencies between RLC timers should be considered: +/// * t-Reassembly: How long it takes for the RLC to detect a lost PDU. If larger than the MAC SR, we may drop a +/// PDU prematurely in the case UM, or we may send NACKs prematurely for the case of AM. +/// +/// * t-StatusProhibit: This value dictates how often the RLC is allowed to send status reports. If this value is +/// shorter than the MAC's SR, it may take longer than t-StatusProhibit to send a control PDU. +/// +/// * t-PollRetransmission: This value should be slightly larger than t-StatusProhibit and also account for RTT. +/// Moreover this value should be slightly larger than the SR of the MAC +/// to avoid spurious RETX'es from late status reports. See t-StatusProhibit for details. +/// +/// Note: These three timers will have implications in picking the PDCP's t-Reordering. See the generation of +/// t-Reordering default configuration for details. +/// +/// Dependencies between F1-U timers should be considered: +/// * t-Notify: This value determines the maximum backoff time to aggregate notifications (towards CU_UP) of which +/// PDCP SDUs have been transmitted (RLC UM/AM) or delivered (RLC AM). Small values increase the number of +/// F1-U messages. Large values may trigger unnecessary discard notifications due to expiration of the +/// PDCP discard timer. +inline std::map make_default_du_qos_config_list(bool warn_on_drop, int rlc_metrics_report) +{ + std::map qos_list = {}; + { + // 5QI=1 + du_qos_config cfg{}; + // RLC + cfg.rlc.mode = rlc_mode::um_bidir; + cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; + cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; + cfg.rlc.um.rx.t_reassembly = 50; + cfg.rlc.um.tx.queue_size = 16384; + cfg.rlc.um.tx.queue_size_bytes = 6172672; + cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); + // F1-U + cfg.f1u.t_notify = 10; + // MAC + cfg.mac = make_default_drb_mac_lc_config(); + cfg.mac.priority = 4; + cfg.mac.lcg_id = uint_to_lcg_id(1); + + qos_list[uint_to_five_qi(1)] = cfg; + } + { + // 5QI=2 + du_qos_config cfg{}; + // RLC + cfg.rlc.mode = rlc_mode::um_bidir; + cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; + cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; + cfg.rlc.um.rx.t_reassembly = 50; + cfg.rlc.um.tx.queue_size = 16384; + cfg.rlc.um.tx.queue_size_bytes = 6172672; + cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); + // F1-U + cfg.f1u.t_notify = 10; + // MAC + cfg.mac = make_default_drb_mac_lc_config(); + cfg.mac.priority = 4; + cfg.mac.lcg_id = uint_to_lcg_id(1); + + qos_list[uint_to_five_qi(2)] = cfg; + } + { + // 5QI=5 + du_qos_config cfg{}; + // RLC + cfg.rlc.mode = rlc_mode::am; + cfg.rlc.am.tx.sn_field_length = rlc_am_sn_size::size12bits; + cfg.rlc.am.tx.t_poll_retx = 80; + cfg.rlc.am.tx.poll_pdu = 64; + cfg.rlc.am.tx.poll_byte = 125; + cfg.rlc.am.tx.max_retx_thresh = 4; + cfg.rlc.am.tx.max_window = 0; + cfg.rlc.am.tx.queue_size = 16384; + cfg.rlc.am.tx.queue_size_bytes = 6172672; + cfg.rlc.am.rx.sn_field_length = rlc_am_sn_size::size12bits; + cfg.rlc.am.rx.t_reassembly = 80; + cfg.rlc.am.rx.t_status_prohibit = 10; + cfg.rlc.am.rx.max_sn_per_status = {}; + cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); + // F1-U + cfg.f1u.t_notify = 10; + // MAC + cfg.mac = make_default_drb_mac_lc_config(); + + qos_list[uint_to_five_qi(5)] = cfg; + } + { + // 5QI=7 + du_qos_config cfg{}; + // RLC + cfg.rlc.mode = rlc_mode::um_bidir; + cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; + cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; + cfg.rlc.um.rx.t_reassembly = 100; + cfg.rlc.um.tx.queue_size = 16384; + cfg.rlc.um.tx.queue_size_bytes = 6172672; + cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); + // F1-U + cfg.f1u.t_notify = 10; + cfg.f1u.warn_on_drop = warn_on_drop; + // MAC + cfg.mac = make_default_drb_mac_lc_config(); + cfg.mac.priority = 4; + cfg.mac.lcg_id = uint_to_lcg_id(1); + + qos_list[uint_to_five_qi(7)] = cfg; + } + { + // 5QI=9 + du_qos_config cfg{}; + // RLC + cfg.rlc.mode = rlc_mode::am; + cfg.rlc.am.tx.sn_field_length = rlc_am_sn_size::size18bits; + cfg.rlc.am.tx.t_poll_retx = 20; + cfg.rlc.am.tx.poll_pdu = 16; + cfg.rlc.am.tx.poll_byte = -1; + cfg.rlc.am.tx.max_retx_thresh = 32; + cfg.rlc.am.tx.max_window = 0; + cfg.rlc.am.tx.queue_size = 16384; + cfg.rlc.am.tx.queue_size_bytes = 6172672; + cfg.rlc.am.rx.sn_field_length = rlc_am_sn_size::size18bits; + cfg.rlc.am.rx.t_reassembly = 20; + cfg.rlc.am.rx.t_status_prohibit = 10; + cfg.rlc.am.rx.max_sn_per_status = {}; + cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); + // F1-U + cfg.f1u.t_notify = 10; + cfg.f1u.warn_on_drop = warn_on_drop; + // MAC + cfg.mac = make_default_drb_mac_lc_config(); + + qos_list[uint_to_five_qi(9)] = cfg; + } + return qos_list; +} + +} // namespace config_helpers +} // namespace srsran diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 25bd4852c7..bf23144db0 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -37,6 +37,7 @@ #include "srsran/asn1/f1ap/common.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" #include "srsran/du/du_cell_config_helpers.h" +#include "srsran/du/du_qos_config_helpers.h" #include "srsran/du_high/du_high_configuration.h" #include "srsran/f1u/du/f1u_gateway.h" #include "srsran/support/benchmark_utils.h" diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 6611559cda..48ab9f8d80 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -17,6 +17,7 @@ #include "srsran/asn1/f1ap/common.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" #include "srsran/du/du_cell_config_helpers.h" +#include "srsran/du/du_qos_config_helpers.h" #include "srsran/du_high/du_high_factory.h" #include "srsran/support/error_handling.h" #include "srsran/support/test_utils.h" diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index a7c9375ed4..a2508d255d 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -10,6 +10,7 @@ #include "du_manager_test_helpers.h" #include "srsran/du/du_cell_config_helpers.h" +#include "srsran/du/du_qos_config_helpers.h" #include "srsran/mac/config/mac_cell_group_config_factory.h" #include "srsran/mac/config/mac_config_helpers.h" #include "srsran/rlc/rlc_srb_config_factory.h" diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index dbe42bde8e..96514214ad 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -10,6 +10,7 @@ #include "lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h" #include "srsran/du/du_cell_config_helpers.h" +#include "srsran/du/du_qos_config_helpers.h" #include "srsran/support/math/lcm.h" #include "srsran/support/test_utils.h" #include From 8216ffcfaad4b74cfc86a99ac2630c1c5513c268 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 8 Aug 2024 17:22:54 +0100 Subject: [PATCH 180/407] config: added queue-bytes parameter qos.yml and srb.yml --- configs/qos.yml | 15 ++++++++++----- configs/srb.yml | 1 + include/srsran/du/du_qos_config_helpers.h | 4 ---- include/srsran/rlc/rlc_srb_config_factory.h | 1 + 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/configs/qos.yml b/configs/qos.yml index 7d839b1405..00ea236aa6 100644 --- a/configs/qos.yml +++ b/configs/qos.yml @@ -12,7 +12,8 @@ qos: um-bidir: tx: sn: 12 - queue-size: 4096 + queue-size: 16384 + queue-bytes: 6172672 rx: sn: 12 t-reassembly: 50 @@ -42,7 +43,8 @@ qos: um-bidir: tx: sn: 12 - queue-size: 4096 + queue-size: 16384 + queue-bytes: 6172672 rx: sn: 12 t-reassembly: 50 @@ -76,7 +78,8 @@ qos: max-retx-threshold: 4 poll-pdu: 64 poll-byte: 125 - queue-size: 4096 + queue-size: 16384 + queue-bytes: 6172672 rx: sn: 12 t-reassembly: 80 @@ -107,7 +110,8 @@ qos: um-bidir: tx: sn: 12 - queue-size: 4096 + queue-size: 16384 + queue-bytes: 6172672 rx: sn: 12 t-reassembly: 50 @@ -141,7 +145,8 @@ qos: max-retx-threshold: 4 poll-pdu: 64 poll-byte: 125 - queue-size: 4096 + queue-size: 16384 + queue-bytes: 6172672 rx: sn: 12 t-reassembly: 80 diff --git a/configs/srb.yml b/configs/srb.yml index 0568c5e806..c9116a6c3f 100644 --- a/configs/srb.yml +++ b/configs/srb.yml @@ -14,6 +14,7 @@ srbs: poll-pdu: -1 poll-byte: -1 queue-size: 256 + queue-bytes: 64000 rx: sn: 12 t-reassembly: 35 diff --git a/include/srsran/du/du_qos_config_helpers.h b/include/srsran/du/du_qos_config_helpers.h index e982e712b0..622ceb220d 100644 --- a/include/srsran/du/du_qos_config_helpers.h +++ b/include/srsran/du/du_qos_config_helpers.h @@ -10,13 +10,9 @@ #pragma once -#include "du_cell_config.h" #include "srsran/du/du_qos_config.h" #include "srsran/mac/config/mac_config_helpers.h" -#include "srsran/ran/pdcch/pdcch_type0_css_coreset_config.h" #include "srsran/ran/qos/five_qi.h" -#include "srsran/scheduler/config/scheduler_expert_config.h" -#include "srsran/scheduler/config/serving_cell_config_factory.h" #include namespace srsran { diff --git a/include/srsran/rlc/rlc_srb_config_factory.h b/include/srsran/rlc/rlc_srb_config_factory.h index 12a49530fc..bac1185cbb 100644 --- a/include/srsran/rlc/rlc_srb_config_factory.h +++ b/include/srsran/rlc/rlc_srb_config_factory.h @@ -36,6 +36,7 @@ inline rlc_config make_default_srb_rlc_config() cfg.am.tx.poll_byte = -1; cfg.am.tx.max_retx_thresh = 8; cfg.am.tx.queue_size = 32; + cfg.am.tx.queue_size_bytes = 64000; cfg.am.rx.sn_field_length = rlc_am_sn_size::size12bits; cfg.am.rx.t_reassembly = 35; cfg.am.rx.t_status_prohibit = 0; From 29f2314ee9784dca0900b5f0c361e26695271b26 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 8 Aug 2024 22:35:55 +0100 Subject: [PATCH 181/407] rlc: fix unit tests after introducing byte queue --- tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp | 17 +++++++++-------- tests/unittests/rlc/rlc_tx_am_test.cpp | 17 +++++++++-------- tests/unittests/rlc/rlc_um_test.cpp | 8 ++++---- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp index 067c989a46..00751c5d7d 100644 --- a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp +++ b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp @@ -124,14 +124,15 @@ std::vector generate_pdus(bench_params params, rx_order order) { // Set Tx config rlc_tx_am_config config; - config.sn_field_length = rlc_am_sn_size::size18bits; - config.pdcp_sn_len = pdcp_sn_size::size18bits; - config.t_poll_retx = 45; - config.max_retx_thresh = 4; - config.poll_pdu = 4; - config.poll_byte = 25; - config.queue_size = 4096; - config.max_window = 0; + config.sn_field_length = rlc_am_sn_size::size18bits; + config.pdcp_sn_len = pdcp_sn_size::size18bits; + config.t_poll_retx = 45; + config.max_retx_thresh = 4; + config.poll_pdu = 4; + config.poll_byte = 25; + config.queue_size = 4096; + config.queue_size_bytes = 4096 * 1507; + config.max_window = 0; // Create test frame auto tester = std::make_unique(config.sn_field_length); diff --git a/tests/unittests/rlc/rlc_tx_am_test.cpp b/tests/unittests/rlc/rlc_tx_am_test.cpp index eb95e12e73..49da70731c 100644 --- a/tests/unittests/rlc/rlc_tx_am_test.cpp +++ b/tests/unittests/rlc/rlc_tx_am_test.cpp @@ -104,14 +104,15 @@ class rlc_tx_am_test : public ::testing::Test, public ::testing::WithParamInterf logger.info("Creating RLC Tx AM entity ({} bit)", to_number(sn_size)); // Set Tx config - config.sn_field_length = sn_size; - config.pdcp_sn_len = static_cast(sn_size); // use the same SN size for PDCP - config.t_poll_retx = 45; - config.max_retx_thresh = 4; - config.poll_pdu = 4; - config.poll_byte = 25; - config.max_window = 0; - config.queue_size = 4096; + config.sn_field_length = sn_size; + config.pdcp_sn_len = static_cast(sn_size); // use the same SN size for PDCP + config.t_poll_retx = 45; + config.max_retx_thresh = 4; + config.poll_pdu = 4; + config.poll_byte = 25; + config.max_window = 0; + config.queue_size = 4096; + config.queue_size_bytes = 4096 * 1500; // Create test frame tester = std::make_unique(config.sn_field_length); diff --git a/tests/unittests/rlc/rlc_um_test.cpp b/tests/unittests/rlc/rlc_um_test.cpp index 25b1e52956..8508a2a44a 100644 --- a/tests/unittests/rlc/rlc_um_test.cpp +++ b/tests/unittests/rlc/rlc_um_test.cpp @@ -44,7 +44,6 @@ class rlc_test_frame : public rlc_rx_upper_layer_data_notifier, { // store in list transmitted_pdcp_sn_list.push_back(max_tx_pdcp_sn); - transmitted_pdcp_sn_list.push_back(queue_free_bytes); } void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override {} void on_retransmitted_sdu(uint32_t max_retx_pdcp_sn) override {} @@ -84,9 +83,10 @@ class rlc_um_test : public ::testing::Test, public ::testing::WithParamInterface config.rx.t_reassembly = 5; // Set Tx config - config.tx.sn_field_length = sn_size; - config.tx.pdcp_sn_len = pdcp_sn_size::size12bits; - config.tx.queue_size = 4096; + config.tx.sn_field_length = sn_size; + config.tx.pdcp_sn_len = pdcp_sn_size::size12bits; + config.tx.queue_size = 4096; + config.tx.queue_size_bytes = 4096 * 1500; // Create RLC entities rlc1 = std::make_unique(gnb_du_id_t::min, From d7b7325026c3b9eb3a3877b2936060bd7d15311a Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 9 Aug 2024 16:39:59 +0100 Subject: [PATCH 182/407] f1u: make initial report match the configured RLC queue size --- .../flexible_du/du_high/du_high_config.h | 6 +++--- .../du_high/du_high_config_cli11_schema.cpp | 2 +- .../du_high/du_high_config_translators.cpp | 6 ++++-- include/srsran/du/du_qos_config_helpers.h | 19 ++++++++++++------- include/srsran/f1u/du/f1u_config.h | 11 +++++------ lib/f1u/du/f1u_bearer_impl.cpp | 5 ++++- lib/f1u/du/f1u_bearer_impl.h | 6 ++---- 7 files changed, 31 insertions(+), 24 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 f764bde9ee..0bed86ceac 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -689,9 +689,9 @@ struct du_high_unit_rlc_tx_am_config { uint32_t max_retx_thresh; ///< Max retx threshold int32_t poll_pdu; ///< Insert poll bit after this many PDUs int32_t poll_byte; ///< Insert poll bit after this much data (bytes) - uint32_t max_window = 0; ///< Custom parameter to limit the maximum window size for memory reasons. 0 means no limit. - uint32_t queue_size = 4096; ///< RLC SDU queue size - uint32_t queue_bytes = 4096 * 1507; ///< RLC SDU queue size in bytes + uint32_t max_window = 0; ///< Custom parameter to limit the maximum window size for memory reasons. 0 means no limit. + uint32_t queue_size = 4096; ///< RLC SDU queue size + uint32_t queue_size_bytes = 4096 * 1507; ///< RLC SDU queue size in bytes }; /// RLC UM RX configuration 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 22ed24380f..7f4cff2862 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 @@ -1336,7 +1336,7 @@ static void configure_cli11_rlc_am_args(CLI::App& app, du_high_unit_rlc_am_confi "large windows. 0 means no limits other than the SN size (i.e. 2^[sn_size-1])."); add_option(*rlc_tx_am_subcmd, "--queue-size", rlc_am_params.tx.queue_size, "RLC AM TX SDU queue size in PDUs") ->capture_default_str(); - add_option(*rlc_tx_am_subcmd, "--queue-bytes", rlc_am_params.tx.queue_bytes, "RLC AM TX SDU queue size in bytes") + add_option(*rlc_tx_am_subcmd, "--queue-bytes", rlc_am_params.tx.queue_size_bytes, "RLC AM TX SDU queue size in bytes") ->capture_default_str(); CLI::App* rlc_rx_am_subcmd = add_subcommand(app, "rx", "AM RX parameters"); add_option(*rlc_rx_am_subcmd, "--sn", rlc_am_params.rx.sn_field_length, "RLC AM RX SN")->capture_default_str(); 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 661a5703d4..6d1ce9367a 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 @@ -646,7 +646,7 @@ static rlc_am_config generate_du_rlc_am_config(const du_high_unit_rlc_am_config& out_rlc.tx.poll_byte = in_cfg.tx.poll_byte; out_rlc.tx.max_window = in_cfg.tx.max_window; out_rlc.tx.queue_size = in_cfg.tx.queue_size; - out_rlc.tx.queue_size_bytes = in_cfg.tx.queue_bytes; + out_rlc.tx.queue_size_bytes = in_cfg.tx.queue_size_bytes; //< RX SN if (!from_number(out_rlc.rx.sn_field_length, in_cfg.rx.sn_field_length)) { report_error("Invalid RLC AM RX SN: SN={}\n", in_cfg.rx.sn_field_length); @@ -732,7 +732,9 @@ std::map srsran::generate_du_qos_config(const du_high_ // Convert F1-U config auto& out_f1u = out_cfg[qos.five_qi].f1u; //< t-Notify - out_f1u.t_notify = qos.f1u_du.t_notify; + out_f1u.t_notify = qos.f1u_du.t_notify; + out_f1u.rlc_queue_bytes_limit = + qos.rlc.mode == "am" ? qos.rlc.am.tx.queue_size_bytes : qos.rlc.um.tx.queue_size_bytes; out_f1u.warn_on_drop = config.warn_on_drop; // Convert MAC config diff --git a/include/srsran/du/du_qos_config_helpers.h b/include/srsran/du/du_qos_config_helpers.h index 622ceb220d..4753f6313a 100644 --- a/include/srsran/du/du_qos_config_helpers.h +++ b/include/srsran/du/du_qos_config_helpers.h @@ -53,7 +53,8 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = 6172672; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.t_notify = 10; + cfg.f1u.t_notify = 10; + cfg.f1u.rlc_queue_bytes_limit = 6172672; // MAC cfg.mac = make_default_drb_mac_lc_config(); cfg.mac.priority = 4; @@ -73,7 +74,8 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = 6172672; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.t_notify = 10; + cfg.f1u.t_notify = 10; + cfg.f1u.rlc_queue_bytes_limit = 6172672; // MAC cfg.mac = make_default_drb_mac_lc_config(); cfg.mac.priority = 4; @@ -100,7 +102,8 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.rx.max_sn_per_status = {}; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.t_notify = 10; + cfg.f1u.t_notify = 10; + cfg.f1u.rlc_queue_bytes_limit = 6172672; // MAC cfg.mac = make_default_drb_mac_lc_config(); @@ -118,8 +121,9 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = 6172672; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.t_notify = 10; - cfg.f1u.warn_on_drop = warn_on_drop; + cfg.f1u.t_notify = 10; + cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.warn_on_drop = warn_on_drop; // MAC cfg.mac = make_default_drb_mac_lc_config(); cfg.mac.priority = 4; @@ -146,8 +150,9 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.rx.max_sn_per_status = {}; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.t_notify = 10; - cfg.f1u.warn_on_drop = warn_on_drop; + cfg.f1u.t_notify = 10; + cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.warn_on_drop = warn_on_drop; // MAC cfg.mac = make_default_drb_mac_lc_config(); diff --git a/include/srsran/f1u/du/f1u_config.h b/include/srsran/f1u/du/f1u_config.h index c59d919af3..b5b3b2a7bc 100644 --- a/include/srsran/f1u/du/f1u_config.h +++ b/include/srsran/f1u/du/f1u_config.h @@ -14,17 +14,16 @@ #include "fmt/format.h" #include -namespace srsran { -namespace srs_du { +namespace srsran::srs_du { /// \brief Configurable parameters of the F1-U bearer in the DU struct f1u_config { - uint32_t t_notify; ///< Timer used for periodic transmission of uplink notifications - bool warn_on_drop = true; ///< Log a warning instead of an info message whenever a PDU is dropped + uint32_t t_notify; ///< Timer used for periodic transmission of uplink notifications + uint32_t rlc_queue_bytes_limit; ///< RLC queue limit in bytes. Used for initial report of buffer space to the CU-UP. + bool warn_on_drop = true; ///< Log a warning instead of an info message whenever a PDU is dropped }; -} // namespace srs_du -} // namespace srsran +} // namespace srsran::srs_du namespace fmt { diff --git a/lib/f1u/du/f1u_bearer_impl.cpp b/lib/f1u/du/f1u_bearer_impl.cpp index 2958673357..8e3641002b 100644 --- a/lib/f1u/du/f1u_bearer_impl.cpp +++ b/lib/f1u/du/f1u_bearer_impl.cpp @@ -28,7 +28,10 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, rx_sdu_notifier(rx_sdu_notifier_), tx_pdu_notifier(tx_pdu_notifier_), ue_executor(ue_executor_), - ul_notif_timer(timers.create_timer()) + ul_notif_timer(timers.create_timer()), + desired_buffer_size_for_data_radio_bearer(cfg.rlc_queue_bytes_limit), + notif_desired_buffer_size_for_data_radio_bearer( + 0) // make sure that we send an initial buffer report, even if there is no data { ul_notif_timer.set(std::chrono::milliseconds(cfg.t_notify), [this](timer_id_t tid) { on_expired_ul_notif_timer(); }); ul_notif_timer.run(); diff --git a/lib/f1u/du/f1u_bearer_impl.h b/lib/f1u/du/f1u_bearer_impl.h index ea3fd3593e..780e545163 100644 --- a/lib/f1u/du/f1u_bearer_impl.h +++ b/lib/f1u/du/f1u_bearer_impl.h @@ -22,8 +22,6 @@ namespace srsran { namespace srs_du { -const uint32_t queue_bytes_limit = 6172672; - class f1u_bearer_impl final : public f1u_bearer, public f1u_tx_sdu_handler, public f1u_tx_delivery_handler, @@ -76,7 +74,7 @@ class f1u_bearer_impl final : public f1u_bearer, unique_timer ul_notif_timer; /// Holds the most recent information of the available space in the RLC SDU queue - std::atomic desired_buffer_size_for_data_radio_bearer{queue_bytes_limit}; + std::atomic desired_buffer_size_for_data_radio_bearer; /// Holds the most recent highest transmitted PDCP SN that is frequently updated by lower layers (i.e. by RLC AM/UM) std::atomic highest_transmitted_pdcp_sn{unset_pdcp_sn}; /// Holds the most recent highest delivered PDCP SN that is frequently updated by lower layers (i.e. by RLC AM) @@ -89,7 +87,7 @@ class f1u_bearer_impl final : public f1u_bearer, /// Holds the latest information of the available space in the RLC SDU queue that was reported to the upper layers /// (i.e. torward CU-UP) - uint32_t notif_desired_buffer_size_for_data_radio_bearer = queue_bytes_limit; + uint32_t notif_desired_buffer_size_for_data_radio_bearer; /// Holds the last highest transmitted PDCP SN that was reported to upper layers (i.e. towards CU-UP) uint32_t notif_highest_transmitted_pdcp_sn = unset_pdcp_sn; /// Holds the last highest delivered PDCP SN that was reported to upper layers (i.e. towards CU-UP) From d291ea3b5b08f9b3547b19cab1a5975b2f5df0b1 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 9 Aug 2024 16:57:02 +0100 Subject: [PATCH 183/407] rlc: change make byte limit configurable in TM entities too --- include/srsran/rlc/rlc_config.h | 3 ++- include/srsran/rlc/rlc_srb_config_factory.h | 9 +++++---- lib/rlc/rlc_tx_tm_entity.cpp | 4 +--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/srsran/rlc/rlc_config.h b/include/srsran/rlc/rlc_config.h index fc61d6db3b..e3cc985bcd 100644 --- a/include/srsran/rlc/rlc_config.h +++ b/include/srsran/rlc/rlc_config.h @@ -717,7 +717,8 @@ struct rlc_rx_tm_config { /// This includes only implementation-specific parameters that are not specified by 3GPP struct rlc_tx_tm_config { // Implementation-specific parameters that are not specified by 3GPP - uint32_t queue_size; ///< SDU queue size + uint32_t queue_size; ///< SDU queue size + uint32_t queue_size_bytes; ///< SDU queue size limit in bytes }; /// \brief Configurable parameters for RLC TM diff --git a/include/srsran/rlc/rlc_srb_config_factory.h b/include/srsran/rlc/rlc_srb_config_factory.h index bac1185cbb..cac50ad5d5 100644 --- a/include/srsran/rlc/rlc_srb_config_factory.h +++ b/include/srsran/rlc/rlc_srb_config_factory.h @@ -17,10 +17,11 @@ namespace srsran { /// \brief SRB0 default configuration (only implementation-specific parameters) inline rlc_config make_default_srb0_rlc_config() { - rlc_config cfg = {}; - cfg.mode = rlc_mode::tm; - cfg.tm.tx.queue_size = 8; - cfg.metrics_period = std::chrono::milliseconds(0); // disable metrics reporting for SRBs + rlc_config cfg = {}; + cfg.mode = rlc_mode::tm; + cfg.tm.tx.queue_size = 8; + cfg.tm.tx.queue_size_bytes = 8 * 2000; + cfg.metrics_period = std::chrono::milliseconds(0); // disable metrics reporting for SRBs return cfg; } diff --git a/lib/rlc/rlc_tx_tm_entity.cpp b/lib/rlc/rlc_tx_tm_entity.cpp index f37f71e54b..390c99f6f7 100644 --- a/lib/rlc/rlc_tx_tm_entity.cpp +++ b/lib/rlc/rlc_tx_tm_entity.cpp @@ -12,8 +12,6 @@ using namespace srsran; -const uint32_t queue_bytes_limit = 6172672; - rlc_tx_tm_entity::rlc_tx_tm_entity(gnb_du_id_t du_id, du_ue_index_t ue_index, rb_id_t rb_id_, @@ -40,7 +38,7 @@ rlc_tx_tm_entity::rlc_tx_tm_entity(gnb_du_id_t du_id, ue_executor_, timers), cfg(config), - sdu_queue(cfg.queue_size, queue_bytes_limit, logger), + sdu_queue(cfg.queue_size, cfg.queue_size_bytes, logger), pcap_context(ue_index, rb_id_, /* is_uplink */ false) { metrics_low.metrics_set_mode(rlc_mode::tm); From ceb3035b7723a3930b395bcf2c08ee0d0d9dda28 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 9 Aug 2024 17:10:22 +0100 Subject: [PATCH 184/407] rlc: remove magical number from default config generator and rlc queue test --- include/srsran/du/du_qos_config_helpers.h | 36 +++++++++++-------- .../rlc/rlc_sdu_queue_lockfree_test.cpp | 21 ++++++----- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/include/srsran/du/du_qos_config_helpers.h b/include/srsran/du/du_qos_config_helpers.h index 4753f6313a..8ec28ee87b 100644 --- a/include/srsran/du/du_qos_config_helpers.h +++ b/include/srsran/du/du_qos_config_helpers.h @@ -38,6 +38,12 @@ namespace config_helpers { /// PDCP SDUs have been transmitted (RLC UM/AM) or delivered (RLC AM). Small values increase the number of /// F1-U messages. Large values may trigger unnecessary discard notifications due to expiration of the /// PDCP discard timer. + +/// Default value for RLC SDU queue limit in bytes are chosen such that it allows for 4096 PDCP pdus of 1500 of payload +/// and 7 bytes of PDCP overhead. The SDU limit should be much larger then this, so that the limit is the number of +/// bytes in the queue, not the number of SDUs, even in the case of small PDUs +const uint32_t default_rlc_queue_size_sdus = 16384; +const uint32_t default_rlc_queue_size_bytes = 4096 * (1500 + 7); inline std::map make_default_du_qos_config_list(bool warn_on_drop, int rlc_metrics_report) { std::map qos_list = {}; @@ -49,12 +55,12 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; cfg.rlc.um.rx.t_reassembly = 50; - cfg.rlc.um.tx.queue_size = 16384; - cfg.rlc.um.tx.queue_size_bytes = 6172672; + cfg.rlc.um.tx.queue_size = default_rlc_queue_size_sdus; + cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U cfg.f1u.t_notify = 10; - cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC cfg.mac = make_default_drb_mac_lc_config(); cfg.mac.priority = 4; @@ -70,12 +76,12 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; cfg.rlc.um.rx.t_reassembly = 50; - cfg.rlc.um.tx.queue_size = 16384; - cfg.rlc.um.tx.queue_size_bytes = 6172672; + cfg.rlc.um.tx.queue_size = default_rlc_queue_size_sdus; + cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U cfg.f1u.t_notify = 10; - cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC cfg.mac = make_default_drb_mac_lc_config(); cfg.mac.priority = 4; @@ -94,8 +100,8 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.tx.poll_byte = 125; cfg.rlc.am.tx.max_retx_thresh = 4; cfg.rlc.am.tx.max_window = 0; - cfg.rlc.am.tx.queue_size = 16384; - cfg.rlc.am.tx.queue_size_bytes = 6172672; + cfg.rlc.am.tx.queue_size = default_rlc_queue_size_sdus; + cfg.rlc.am.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.am.rx.sn_field_length = rlc_am_sn_size::size12bits; cfg.rlc.am.rx.t_reassembly = 80; cfg.rlc.am.rx.t_status_prohibit = 10; @@ -103,7 +109,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U cfg.f1u.t_notify = 10; - cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC cfg.mac = make_default_drb_mac_lc_config(); @@ -117,12 +123,12 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.sn_field_length = rlc_um_sn_size::size12bits; cfg.rlc.um.rx.sn_field_length = rlc_um_sn_size::size12bits; cfg.rlc.um.rx.t_reassembly = 100; - cfg.rlc.um.tx.queue_size = 16384; - cfg.rlc.um.tx.queue_size_bytes = 6172672; + cfg.rlc.um.tx.queue_size = default_rlc_queue_size_sdus; + cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U cfg.f1u.t_notify = 10; - cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; cfg.f1u.warn_on_drop = warn_on_drop; // MAC cfg.mac = make_default_drb_mac_lc_config(); @@ -142,8 +148,8 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.tx.poll_byte = -1; cfg.rlc.am.tx.max_retx_thresh = 32; cfg.rlc.am.tx.max_window = 0; - cfg.rlc.am.tx.queue_size = 16384; - cfg.rlc.am.tx.queue_size_bytes = 6172672; + cfg.rlc.am.tx.queue_size = default_rlc_queue_size_sdus; + cfg.rlc.am.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.am.rx.sn_field_length = rlc_am_sn_size::size18bits; cfg.rlc.am.rx.t_reassembly = 20; cfg.rlc.am.rx.t_status_prohibit = 10; @@ -151,7 +157,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U cfg.f1u.t_notify = 10; - cfg.f1u.rlc_queue_bytes_limit = 6172672; + cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; cfg.f1u.warn_on_drop = warn_on_drop; // MAC cfg.mac = make_default_drb_mac_lc_config(); diff --git a/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp b/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp index c7ac606cee..92ab540919 100644 --- a/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp +++ b/tests/unittests/rlc/rlc_sdu_queue_lockfree_test.cpp @@ -17,13 +17,18 @@ namespace srsran { +/// Default value for RLC SDU queue limit in bytes are chosen such that it allows for 4096 PDCP pdus of 1500 of payload +/// and 7 bytes of PDCP overhead. The SDU limit should be much larger then this, so that the limit is the number of +/// bytes in the queue, not the number of SDUs, even in the case of small PDUs +const uint32_t default_rlc_queue_size_sdus = 16384; +const uint32_t default_rlc_queue_size_bytes = 4096 * (1500 + 7); + void queue_unqueue_test() { rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU queue unqueue test"}; - const uint32_t queue_bytes_limit = 6172672; - rlc_sdu_queue_lockfree tx_queue(4096, queue_bytes_limit, logger); + rlc_sdu_queue_lockfree tx_queue(default_rlc_queue_size_sdus, default_rlc_queue_size_bytes, logger); // Write 1 SDU byte_buffer buf = byte_buffer::create({0x00, 0x01}).value(); @@ -56,9 +61,8 @@ void full_capacity_test() rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU capacity test"}; - unsigned capacity = 5; - const uint32_t queue_bytes_limit = 6172672; - rlc_sdu_queue_lockfree tx_queue(capacity, queue_bytes_limit, logger); + unsigned capacity = 5; + rlc_sdu_queue_lockfree tx_queue(capacity, default_rlc_queue_size_bytes, logger); // Write Capacity + 1 SDUs for (uint32_t pdcp_sn = 0; pdcp_sn < capacity + 1; pdcp_sn++) { @@ -143,10 +147,9 @@ void discard_all_test() { rlc_bearer_logger logger("RLC", {gnb_du_id_t::min, du_ue_index_t::MIN_DU_UE_INDEX, rb_id_t(drb_id_t::drb1), "DL"}); test_delimit_logger delimiter{"RLC SDU discard all test"}; - unsigned capacity = 10; - unsigned n_sdus = capacity / 2; - const uint32_t queue_bytes_limit = 6172672; - rlc_sdu_queue_lockfree tx_queue(capacity, queue_bytes_limit, logger); + unsigned capacity = 10; + unsigned n_sdus = capacity / 2; + rlc_sdu_queue_lockfree tx_queue(capacity, default_rlc_queue_size_bytes, logger); // Fill SDU queue with SDUs for (uint32_t pdcp_sn = 0; pdcp_sn < n_sdus; pdcp_sn++) { From 6d2768a268f98d565b7523505b5f2be209342821 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 9 Aug 2024 15:58:45 +0200 Subject: [PATCH 185/407] du_high_app: fix setting of MAC LC configuration for SRBs --- .../units/flexible_du/du_high/du_high_config_cli11_schema.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7f4cff2862..ea77cd6f29 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 @@ -1355,10 +1355,10 @@ static void configure_cli11_mac_args(CLI::App& app, du_high_unit_mac_lc_config& mac_params.priority, "Logical Channel priority. An increasing priority value indicates a lower priority level") ->capture_default_str() - ->check(CLI::Range(4, 16)); + ->check(CLI::Range(1, 16)); add_option(app, "--lc_group_id", mac_params.lc_group_id, "Logical Channel Group id") ->capture_default_str() - ->check(CLI::Range(1, 7)); + ->check(CLI::Range(0, 7)); add_option( app, "--bucket_size_duration_ms", mac_params.bucket_size_duration_ms, "Bucket size duration in milliseconds") ->capture_default_str() From fa35c3e42bbadceb5b2c3ec0ce1e581d6fc684b7 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 9 Aug 2024 15:59:20 +0200 Subject: [PATCH 186/407] du_high_app: add validation for MAC LC configuration defined as part of SRBs and QoS configurations --- .../du_high/du_high_config_validator.cpp | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 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 145ef24a14..8dbfeb40be 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 @@ -9,12 +9,14 @@ */ #include "du_high_config_validator.h" + #include "srsran/ran/duplex_mode.h" #include "srsran/ran/nr_cell_identity.h" #include "srsran/ran/pdcch/pdcch_type0_css_coreset_config.h" #include "srsran/ran/prach/prach_helper.h" #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/rlc/rlc_config.h" +#include using namespace srsran; @@ -1048,13 +1050,47 @@ static bool validate_rlc_unit_config(five_qi_t five_qi, const du_high_unit_rlc_c return true; } +static bool validate_mac_lc_unit_config(five_qi_t five_qi, + const du_high_unit_mac_lc_config& config, + unsigned max_srb_lc_priority, + span srb_lcg_ids) +{ + // [Implementation-defined] Ensure that SRBs have higher LC priority than DRBs. + if (config.priority <= max_srb_lc_priority) { + fmt::print("MAC LC priority configured for {} cannot be less than the maximum LC priority of SRBs={}.\n", + five_qi, + max_srb_lc_priority); + return false; + } + + // [Implementation-defined] Ensure that DRBs are not configured with same LCG IDs as SRBs. + if (srb_lcg_ids.end() != std::find(srb_lcg_ids.begin(), srb_lcg_ids.end(), config.lc_group_id)) { + fmt::print( + "MAC LCG ID={} configured for {} cannot be same as the one assigned to a SRB.\n", config.lc_group_id, five_qi); + return false; + } + + return true; +} + /// Validates the given QoS configuration. Returns true on success, otherwise false. -static bool validate_qos_config(span config) +static bool validate_qos_config(span config, + const std::map& srb_cfg) { + uint8_t max_srb_lc_priority = 0; + std::vector srb_lcg_ids; + for (const auto& it : srb_cfg) { + max_srb_lc_priority = std::max(it.second.mac.priority, max_srb_lc_priority); + srb_lcg_ids.push_back(it.second.mac.lc_group_id); + } + for (const auto& qos : config) { if (!validate_rlc_unit_config(qos.five_qi, qos.rlc)) { return false; } + if (!validate_mac_lc_unit_config(qos.five_qi, qos.mac, max_srb_lc_priority, srb_lcg_ids)) { + return false; + } } return true; } @@ -1077,7 +1113,7 @@ bool srsran::validate_du_high_config(const du_high_unit_config& config, const os return false; } - if (!validate_qos_config(config.qos_cfg)) { + if (!validate_qos_config(config.qos_cfg, config.srb_cfg)) { return false; } From 9f0e9861680f58c104368c5a43232ae121f29ef2 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 9 Aug 2024 16:05:52 +0200 Subject: [PATCH 187/407] du_high_app: populate MAC LC configuration configured in configuration for SRBs --- .../du_high/du_high_config_translators.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) 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 6d1ce9367a..47cec9917e 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 @@ -751,34 +751,40 @@ std::map srsran::generate_du_srb_config(const du_high_u srb_cfg.insert(std::make_pair(srb_id_t::srb1, du_srb_config{})); if (config.srb_cfg.find(srb_id_t::srb1) != config.srb_cfg.end()) { auto& out_rlc = srb_cfg[srb_id_t::srb1].rlc; + auto& out_mac = srb_cfg[srb_id_t::srb1].mac; out_rlc.mode = rlc_mode::am; out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb1).rlc); + out_mac = generate_mac_lc_config(config.srb_cfg.at(srb_id_t::srb1).mac); } else { srb_cfg.at(srb_id_t::srb1).rlc = make_default_srb_rlc_config(); + srb_cfg.at(srb_id_t::srb1).mac = make_default_srb_mac_lc_config(LCID_SRB1); } - srb_cfg.at(srb_id_t::srb1).mac = make_default_srb_mac_lc_config(LCID_SRB1); // SRB2 srb_cfg.insert(std::make_pair(srb_id_t::srb2, du_srb_config{})); if (config.srb_cfg.find(srb_id_t::srb2) != config.srb_cfg.end()) { auto& out_rlc = srb_cfg[srb_id_t::srb2].rlc; + auto& out_mac = srb_cfg[srb_id_t::srb2].mac; out_rlc.mode = rlc_mode::am; out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb2).rlc); + out_mac = generate_mac_lc_config(config.srb_cfg.at(srb_id_t::srb2).mac); } else { srb_cfg.at(srb_id_t::srb2).rlc = make_default_srb_rlc_config(); + srb_cfg.at(srb_id_t::srb2).mac = make_default_srb_mac_lc_config(LCID_SRB2); } - srb_cfg.at(srb_id_t::srb2).mac = make_default_srb_mac_lc_config(LCID_SRB2); // SRB3 srb_cfg.insert(std::make_pair(srb_id_t::srb3, du_srb_config{})); if (config.srb_cfg.find(srb_id_t::srb3) != config.srb_cfg.end()) { auto& out_rlc = srb_cfg[srb_id_t::srb3].rlc; + auto& out_mac = srb_cfg[srb_id_t::srb3].mac; out_rlc.mode = rlc_mode::am; out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb3).rlc); + out_mac = generate_mac_lc_config(config.srb_cfg.at(srb_id_t::srb3).mac); } else { srb_cfg.at(srb_id_t::srb3).rlc = make_default_srb_rlc_config(); + srb_cfg.at(srb_id_t::srb3).mac = make_default_srb_mac_lc_config(LCID_SRB3); } - srb_cfg.at(srb_id_t::srb3).mac = make_default_srb_mac_lc_config(LCID_SRB3); if (config.ntn_cfg.has_value()) { ntn_augment_rlc_parameters(config.ntn_cfg.value(), srb_cfg); From f6c5bab1cd9606f61162d0efe08f33adf6b8a792 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 9 Aug 2024 16:07:18 +0200 Subject: [PATCH 188/407] configs: add MAC LC configuration SRB1 --- configs/srb.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configs/srb.yml b/configs/srb.yml index c9116a6c3f..935c6265c8 100644 --- a/configs/srb.yml +++ b/configs/srb.yml @@ -19,3 +19,8 @@ srbs: sn: 12 t-reassembly: 35 t-status-prohibit: 0 + mac: + lc_priority: 1 + lc_group_id: 0 + bucket_size_duration_ms: 5 + prioritized_bit_rate_kBps: 65537 From 6a817cb0c0a9760ded489cb1f1a94ca817c2e8b5 Mon Sep 17 00:00:00 2001 From: ninjab3s Date: Mon, 12 Aug 2024 10:27:31 +0200 Subject: [PATCH 189/407] Debugging CI: Reduce log level to info for ZMQ tests --- .gitlab/ci/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 1a90be93b4..de7c91aa20 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -237,7 +237,7 @@ smoke zmq: MARKERS: "smoke" PYTEST_ARGS: "-x" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - E2E_LOG_LEVEL: "debug" + E2E_LOG_LEVEL: "info" needs: - job: "smoke relwithdeb cached" artifacts: true From f485b4640f3a18eb3dd23a5d0a2b2e328ec6aacb Mon Sep 17 00:00:00 2001 From: sauka Date: Wed, 7 Aug 2024 15:13:56 +0300 Subject: [PATCH 190/407] ofh,eth_receiver: fix buffer pool depletion when socket is set to non-blocking mode --- lib/ofh/ethernet/ethernet_rx_buffer_impl.cpp | 9 ++++++++- lib/ofh/ethernet/ethernet_rx_buffer_impl.h | 7 +++++-- lib/ofh/ethernet/ethernet_rx_buffer_pool.h | 5 ++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/ofh/ethernet/ethernet_rx_buffer_impl.cpp b/lib/ofh/ethernet/ethernet_rx_buffer_impl.cpp index 28f1b354a6..4a4dcae53e 100644 --- a/lib/ofh/ethernet/ethernet_rx_buffer_impl.cpp +++ b/lib/ofh/ethernet/ethernet_rx_buffer_impl.cpp @@ -19,12 +19,19 @@ ethernet_rx_buffer_impl::ethernet_rx_buffer_impl(ethernet_rx_buffer_pool& pool_, size = pool.get_data(id).size(); } -ethernet_rx_buffer_impl::ethernet_rx_buffer_impl(ethernet_rx_buffer_impl&& other) noexcept : pool(other.pool) +ethernet_rx_buffer_impl::ethernet_rx_buffer_impl(ethernet_rx_buffer_impl&& other) noexcept : + pool(other.pool), id(std::exchange(other.id, -1)), size(std::exchange(other.size, 0)) +{ +} + +ethernet_rx_buffer_impl& ethernet_rx_buffer_impl::operator=(ethernet_rx_buffer_impl&& other) noexcept { id = other.id; size = other.size; other.id = -1; other.size = 0; + + return *this; } span ethernet_rx_buffer_impl::data() const diff --git a/lib/ofh/ethernet/ethernet_rx_buffer_impl.h b/lib/ofh/ethernet/ethernet_rx_buffer_impl.h index b97566d24f..4d81b273b8 100644 --- a/lib/ofh/ethernet/ethernet_rx_buffer_impl.h +++ b/lib/ofh/ethernet/ethernet_rx_buffer_impl.h @@ -31,8 +31,11 @@ class ethernet_rx_buffer_impl : public rx_buffer /// Copy constructor is deleted. ethernet_rx_buffer_impl(ethernet_rx_buffer_impl& /**/) = delete; - /// Move assigment operator. - ethernet_rx_buffer_impl& operator=(ethernet_rx_buffer_impl&& other) = delete; + /// Copy assignment operator is deleted. + ethernet_rx_buffer_impl& operator=(const ethernet_rx_buffer_impl& other) = delete; + + /// Move assignment operator. + ethernet_rx_buffer_impl& operator=(ethernet_rx_buffer_impl&& other) noexcept; /// Move constructor. ethernet_rx_buffer_impl(ethernet_rx_buffer_impl&& other) noexcept; diff --git a/lib/ofh/ethernet/ethernet_rx_buffer_pool.h b/lib/ofh/ethernet/ethernet_rx_buffer_pool.h index c4271dca9a..5738a15684 100644 --- a/lib/ofh/ethernet/ethernet_rx_buffer_pool.h +++ b/lib/ofh/ethernet/ethernet_rx_buffer_pool.h @@ -12,8 +12,8 @@ #include "ethernet_rx_buffer_impl.h" #include "srsran/adt/expected.h" +#include "srsran/adt/mpmc_queue.h" #include "srsran/adt/span.h" -#include "srsran/adt/spsc_queue.h" #include "srsran/support/math_utils.h" #include "srsran/support/srsran_assert.h" #include "srsran/support/units.h" @@ -29,7 +29,7 @@ class ethernet_rx_buffer_pool static inline constexpr units::bytes ETH_BUFFER_POOL_SIZE{4096000}; using rx_buffer_id_list = - concurrent_queue; + concurrent_queue; unsigned number_of_buffers; @@ -58,7 +58,6 @@ class ethernet_rx_buffer_pool if (!buffer_id.has_value()) { return make_unexpected(default_error_t{}); } - return {{*this, buffer_id.value()}}; } From 5e71d3ece3808a1da0eb49ed7484eef8d889df9b Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 8 Aug 2024 13:37:42 +0200 Subject: [PATCH 191/407] du: set unique nof of PUCCH res per resource set Signed-off-by: Carlo Galiotto --- apps/units/flexible_du/du_high/du_high_config.h | 8 ++++---- .../du_high/du_high_config_cli11_schema.cpp | 12 +++--------- .../du_high/du_high_config_translators.cpp | 4 ++-- .../flexible_du/du_high/du_high_config_validator.cpp | 4 ++-- .../du_high/du_high_config_yaml_writer.cpp | 3 +-- 5 files changed, 12 insertions(+), 19 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 0bed86ceac..d4c4e8dd17 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -213,10 +213,10 @@ struct du_high_unit_pucch_config { unsigned pucch_resource_common = 11; /// \c PUCCH-Config parameters. - /// Number of PUCCH Format 0/1 resources per UE for HARQ-ACK reporting. Values {1,...,8}. - unsigned nof_ue_pucch_f0_or_f1_res_harq = 8; - /// Number of PUCCH Format 2 resources per UE for HARQ-ACK reporting. Values {1,...,8}. - unsigned nof_ue_pucch_f2_res_harq = 6; + /// Number of PUCCH resources per UE for HARQ-ACK reporting. Values {1,...,8}. + /// \remark We assume the number of PUCCH F0/F1 resources for HARQ-ACK is equal to the equivalent number of Format 2 + /// resources. + unsigned nof_ue_pucch_res_harq_per_set = 8; /// Force Format 0 for the PUCCH resources belonging to PUCCH resource set 0. bool use_format_0 = false; /// \brief Number of separate PUCCH resource sets for HARQ-ACK reporting that are available in a cell. 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 ea77cd6f29..d8f9940c7d 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 @@ -782,9 +782,9 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option(app, "--use_format_0", pucch_params.use_format_0, "Use Format 0 for PUCCH resources from resource set 0") ->capture_default_str(); add_option(app, - "--f1_nof_ue_res_harq", - pucch_params.nof_ue_pucch_f0_or_f1_res_harq, - "Number of PUCCH F0/F1 resources available per UE for HARQ") + "--nof_ue_res_harq_per_set", + pucch_params.nof_ue_pucch_res_harq_per_set, + "Number of PUCCH resources available per UE for HARQ for each PUCCH resource set") ->capture_default_str() ->check(CLI::Range(1, 8)); add_option(app, @@ -817,12 +817,6 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& "higher the number of sets, the lower the chances UEs have to share the same PUCCH resources.") ->capture_default_str() ->check(CLI::Range(1, 10)); - add_option(app, - "--f2_nof_ue_res_harq", - pucch_params.nof_ue_pucch_f2_res_harq, - "Number of PUCCH F2 resources available per UE for HARQ") - ->capture_default_str() - ->check(CLI::Range(1, 8)); add_option(app, "--f2_nof_cell_res_csi", pucch_params.nof_cell_csi_resources, 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 47cec9917e..6478f25c4b 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 @@ -508,8 +508,8 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c // Parameters for PUCCH-Config builder (these parameters will be used later on to generate the PUCCH resources). pucch_builder_params& du_pucch_cfg = out_cell.pucch_cfg; const du_high_unit_pucch_config& user_pucch_cfg = base_cell.pucch_cfg; - du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq; - du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_f2_res_harq; + du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; + du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; du_pucch_cfg.nof_cell_harq_pucch_res_sets = user_pucch_cfg.nof_cell_harq_pucch_sets; du_pucch_cfg.nof_sr_resources = user_pucch_cfg.nof_cell_sr_resources; du_pucch_cfg.nof_csi_resources = user_pucch_cfg.nof_cell_csi_resources; 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 8dbfeb40be..62c7d17a89 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 @@ -412,8 +412,8 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& return false; } - if ((pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq + pucch_cfg.nof_ue_pucch_f2_res_harq) * - pucch_cfg.nof_cell_harq_pucch_sets + + // We need to count pucch_cfg.nof_ue_pucch_res_harq_per_set twice, as we have 2 sets of PUCCH resources for HARQ-ACK. + if (pucch_cfg.nof_ue_pucch_res_harq_per_set * 2U * pucch_cfg.nof_cell_harq_pucch_sets + pucch_cfg.nof_cell_sr_resources + pucch_cfg.nof_cell_csi_resources > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { fmt::print("With the given PUCCH parameters, the number of PUCCH resources per cell exceeds the limit={}.\n", diff --git a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp index f73b512f68..dd0330ee14 100644 --- a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp @@ -410,14 +410,13 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c node["pucch_resource_common"] = config.pucch_resource_common; node["use_format_0"] = config.use_format_0; node["sr_period_ms"] = config.sr_period_msec; - node["f0_or_f1_nof_ue_res_harq"] = config.nof_ue_pucch_f0_or_f1_res_harq; + node["f0_or_f1_nof_ue_res_harq"] = config.nof_ue_pucch_res_harq_per_set; node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; node["f0_intraslot_freq_hop"] = config.f0_intraslot_freq_hopping; node["f1_enable_occ"] = config.f1_enable_occ; node["f1_nof_cyclic_shifts"] = config.nof_cyclic_shift; node["f1_intraslot_freq_hop"] = config.f1_intraslot_freq_hopping; node["nof_cell_harq_pucch_res_sets"] = config.nof_cell_harq_pucch_sets; - node["f2_nof_ue_res_harq"] = config.nof_ue_pucch_f2_res_harq; node["f2_nof_cell_res_csi"] = config.nof_cell_csi_resources; node["f2_max_nof_rbs"] = config.f2_max_nof_rbs; node["f2_max_code_rate"] = to_string(config.max_code_rate); From 54e36f33fa18ec92f7df25da2149da568fd575c7 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 8 Aug 2024 15:46:42 +0200 Subject: [PATCH 192/407] sched: add validator check on PUCCH res sets sizes Signed-off-by: Carlo Galiotto --- .../du_high/du_high_config_yaml_writer.cpp | 34 +++++++++---------- .../config/serving_cell_config_validator.cpp | 8 +++-- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp index dd0330ee14..9fccac2cb3 100644 --- a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp @@ -406,23 +406,23 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c { YAML::Node node; - node["p0_nominal"] = config.p0_nominal; - node["pucch_resource_common"] = config.pucch_resource_common; - node["use_format_0"] = config.use_format_0; - node["sr_period_ms"] = config.sr_period_msec; - node["f0_or_f1_nof_ue_res_harq"] = config.nof_ue_pucch_res_harq_per_set; - node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; - node["f0_intraslot_freq_hop"] = config.f0_intraslot_freq_hopping; - node["f1_enable_occ"] = config.f1_enable_occ; - node["f1_nof_cyclic_shifts"] = config.nof_cyclic_shift; - node["f1_intraslot_freq_hop"] = config.f1_intraslot_freq_hopping; - node["nof_cell_harq_pucch_res_sets"] = config.nof_cell_harq_pucch_sets; - node["f2_nof_cell_res_csi"] = config.nof_cell_csi_resources; - node["f2_max_nof_rbs"] = config.f2_max_nof_rbs; - node["f2_max_code_rate"] = to_string(config.max_code_rate); - node["f2_intraslot_freq_hop"] = config.f2_intraslot_freq_hopping; - node["min_k1"] = config.min_k1; - node["max_consecutive_kos"] = config.max_consecutive_kos; + node["p0_nominal"] = config.p0_nominal; + node["pucch_resource_common"] = config.pucch_resource_common; + node["use_format_0"] = config.use_format_0; + node["sr_period_ms"] = config.sr_period_msec; + node["nof_ue_pucch_res_harq_per_set"] = config.nof_ue_pucch_res_harq_per_set; + node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; + node["f0_intraslot_freq_hop"] = config.f0_intraslot_freq_hopping; + node["f1_enable_occ"] = config.f1_enable_occ; + node["f1_nof_cyclic_shifts"] = config.nof_cyclic_shift; + node["f1_intraslot_freq_hop"] = config.f1_intraslot_freq_hopping; + node["nof_cell_harq_pucch_res_sets"] = config.nof_cell_harq_pucch_sets; + node["f2_nof_cell_res_csi"] = config.nof_cell_csi_resources; + node["f2_max_nof_rbs"] = config.f2_max_nof_rbs; + node["f2_max_code_rate"] = to_string(config.max_code_rate); + node["f2_intraslot_freq_hop"] = config.f2_intraslot_freq_hopping; + node["min_k1"] = config.min_k1; + node["max_consecutive_kos"] = config.max_consecutive_kos; if (config.max_payload_bits.has_value()) { node["f2_max_payload"] = config.max_payload_bits.value(); } diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index c666760660..850e69bb1e 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -157,10 +157,10 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(pucch_cfg.pucch_res_set.size() >= 2, "At least 2 PUCCH resource sets need to be configured in PUCCH-Config"); VERIFY(pucch_cfg.pucch_res_set[0].pucch_res_set_id == pucch_res_set_idx::set_0 and pucch_cfg.pucch_res_set[1].pucch_res_set_id == pucch_res_set_idx::set_1, - "PUCCH resouce sets 0 and 1 are expected to have PUCCH-ResourceSetId 0 and 1, respectively"); + "PUCCH resource sets 0 and 1 are expected to have PUCCH-ResourceSetId 0 and 1, respectively"); VERIFY((not pucch_cfg.pucch_res_set[0].pucch_res_id_list.empty()) and (not pucch_cfg.pucch_res_set[1].pucch_res_id_list.empty()), - "PUCCH resouce sets 0 and 1 are expected to have a non-empty set of PUCCH resource id"); + "PUCCH resource sets 0 and 1 are expected to have a non-empty set of PUCCH resource id"); for (size_t pucch_res_set_idx = 0; pucch_res_set_idx != 2; ++pucch_res_set_idx) { for (auto res_idx : pucch_cfg.pucch_res_set[pucch_res_set_idx].pucch_res_id_list) { const auto* pucch_res_it = get_pucch_resource_with_id(res_idx.cell_res_id); @@ -171,6 +171,10 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel } } + // Verify that the size of PUCCH resource set 1 is not smaller than the size of PUCCH resource set 0. + VERIFY(pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() <= pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), + "PUCCH resource set 1's size should be greater or equal to PUCCH resource set 0's size"); + // Verify that each PUCCH resource has a valid cell resource ID. for (auto res_idx : pucch_cfg.pucch_res_list) { VERIFY(res_idx.res_id.cell_res_id < pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES, From 7d0f6fce524e32f5bdd1ce767e1a8c4d9e1698a7 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 9 Aug 2024 11:22:56 +0200 Subject: [PATCH 193/407] du: fix comment in config validator Signed-off-by: Carlo Galiotto --- apps/units/flexible_du/du_high/du_high_config_validator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 62c7d17a89..1eef910602 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 @@ -412,7 +412,8 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& return false; } - // We need to count pucch_cfg.nof_ue_pucch_res_harq_per_set twice, as we have 2 sets of PUCCH resources for HARQ-ACK. + // We need to count pucch_cfg.nof_ue_pucch_res_harq_per_set twice, as we have 2 sets of PUCCH resources for HARQ-ACK + // (PUCCH Resource Set Id 0 with Format 0/1 and PUCCH Resource Set Id 1 with Format 2). if (pucch_cfg.nof_ue_pucch_res_harq_per_set * 2U * pucch_cfg.nof_cell_harq_pucch_sets + pucch_cfg.nof_cell_sr_resources + pucch_cfg.nof_cell_csi_resources > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { From a7d45d7712cacfbd345e1a80f444f62b75855c9b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 11:47:27 +0200 Subject: [PATCH 194/407] du-high: ensure RRC container is transmitted before deleting UE during UE context release --- .../f1ap_du_ue_context_release_procedure.cpp | 54 +++++++++++-------- .../f1ap_du_ue_context_release_procedure.h | 4 ++ 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp index 58468080db..11034eaf00 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp @@ -9,8 +9,10 @@ */ #include "f1ap_du_ue_context_release_procedure.h" +#include "proc_logger.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/f1ap/common/f1ap_message.h" +#include "srsran/support/async/async_no_op_task.h" #include "srsran/support/async/async_timer.h" using namespace srsran; @@ -34,7 +36,7 @@ void f1ap_du_ue_context_release_procedure::operator()(coro_contextrrc_container_present) { - // If the UE CONTEXT RELEASE COMMAND message contains the RRC-Container IE, the gNB-DU shall send the RRC - // container to the UE via the SRB indicated by the SRB ID IE. - f1c_bearer* srb = nullptr; - if (msg->srb_id_present) { - srb_id_t srb_id = int_to_srb_id(msg->srb_id); - srb = ue.bearers.find_srb(srb_id); - } - - if (srb != nullptr) { - byte_buffer pdu{msg->rrc_container}; - - // Forward F1AP PDU to lower layers to be transmitted over-the-air. - srb->handle_pdu(std::move(pdu)); - } else { - logger.warning("SRB-ID not defined"); - // Handle Error. - } + CORO_AWAIT(handle_rrc_container()); } // Wait for pending RRC messages to be flushed. - logger.debug("ue={}, proc=\"UE Context Release\": Waiting for {} milliseconds to flush pending RRC messages.", - ue.context.ue_index, + logger.debug("{}: Waiting for {} milliseconds to flush pending RRC messages.", + f1ap_log_prefix{ue.context, name()}, ue_release_timeout.count()); CORO_AWAIT(async_wait_for(release_wait_timer, ue_release_timeout)); // Remove UE from DU manager. - logger.debug("ue={}, proc=\"UE Context Release\": Initiate UE release in lower layers.", ue.context.ue_index); + logger.debug("{}: Initiate UE release in lower layers.", f1ap_log_prefix{ue.context, name()}); CORO_AWAIT(ue.du_handler.request_ue_removal(f1ap_ue_delete_request{ue.context.ue_index})); // Note: UE F1AP context deleted at this point. @@ -80,6 +68,28 @@ void f1ap_du_ue_context_release_procedure::operator()(coro_context f1ap_du_ue_context_release_procedure::handle_rrc_container() +{ + f1c_bearer* srb = nullptr; + if (msg->srb_id_present) { + srb_id_t srb_id = int_to_srb_id(msg->srb_id); + srb = ue.bearers.find_srb(srb_id); + if (srb == nullptr) { + logger.error("{}: Discarding RRC container. Cause: {} not found", f1ap_log_prefix{ue.context, name()}, srb_id); + // Handle Error. + return launch_no_op_task(); + } + + } else { + logger.error("{}: Discarding RRC container. Cause: SRB-ID not defined", f1ap_log_prefix{ue.context, name()}); + // Handle Error. + return launch_no_op_task(); + } + + // Forward F1AP PDU to lower layers, and await for PDU to be transmitted over-the-air. + return srb->handle_pdu_and_await_transmission(msg->rrc_container.copy()); +} + void f1ap_du_ue_context_release_procedure::send_ue_context_release_complete() { using namespace asn1::f1ap; @@ -93,6 +103,6 @@ void f1ap_du_ue_context_release_procedure::send_ue_context_release_complete() resp->gnb_du_ue_f1ap_id = msg->gnb_du_ue_f1ap_id; resp->gnb_cu_ue_f1ap_id = msg->gnb_cu_ue_f1ap_id; - logger.debug("ue={}, proc=\"UE Context Release\": Finished successfully.", ue.context.ue_index); + logger.debug("{}: Finished successfully.", f1ap_log_prefix{ue.context, name()}); cu_msg_notifier.on_new_message(f1ap_msg); } diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h index 745af80576..78421d52cb 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h @@ -25,8 +25,12 @@ class f1ap_du_ue_context_release_procedure void operator()(coro_context>& ctx); private: + const char* name() const { return "UE Context Release"; } + void send_ue_context_release_complete(); + async_task handle_rrc_container(); + const asn1::f1ap::ue_context_release_cmd_s msg; f1ap_du_ue& ue; srslog::basic_logger& logger = srslog::fetch_basic_logger("DU-F1"); From 65e500f800dcc756ff4c2649b385b27cd3c84267 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 12:28:24 +0200 Subject: [PATCH 195/407] f1ap-du: refactor event pools to wait for f1ap pdu tx/delivery notification --- .../unsync_fixed_size_memory_block_pool.h | 36 +++++++++++ lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 60 ++++++++----------- lib/f1ap/du/ue_context/f1c_du_bearer_impl.h | 8 ++- 3 files changed, 67 insertions(+), 37 deletions(-) diff --git a/include/srsran/support/memory_pool/unsync_fixed_size_memory_block_pool.h b/include/srsran/support/memory_pool/unsync_fixed_size_memory_block_pool.h index fa65cecda4..7d6491f6a3 100644 --- a/include/srsran/support/memory_pool/unsync_fixed_size_memory_block_pool.h +++ b/include/srsran/support/memory_pool/unsync_fixed_size_memory_block_pool.h @@ -80,4 +80,40 @@ class unsync_fixed_size_memory_block_pool free_memory_block_list block_free_list; }; +template +class unsync_fixed_size_object_pool +{ + static_assert(sizeof(T) >= free_memory_block_list::min_memory_block_align(), "sizeof(T) is too small"); + + struct pool_deleter { + pool_deleter() = default; + pool_deleter(unsync_fixed_size_memory_block_pool& parent_) : parent(&parent_) {} + void operator()(T* ptr) + { + if (ptr != nullptr) { + parent->deallocate_node(ptr); + } + } + unsync_fixed_size_memory_block_pool* parent; + }; + +public: + using ptr = std::unique_ptr; + + unsync_fixed_size_object_pool(unsigned nof_objs) : mem_pool(nof_objs, sizeof(T)) {} + + template + ptr create(Args&&... args) + { + void* node = mem_pool.allocate_node(sizeof(T)); + if (node == nullptr) { + return nullptr; + } + return ptr{new (node) T{std::forward(args)...}, pool_deleter{mem_pool}}; + } + +private: + unsync_fixed_size_memory_block_pool mem_pool; +}; + } // namespace srsran diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp index 0f24cffca1..a255248ae1 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -109,6 +109,9 @@ async_task f1c_srb0_du_bearer::handle_pdu_and_await_transmission(byte_buff return launch_no_op_task(); } +// Max number of concurrent PDCP SN deliveries/transmissions being awaited on. +static constexpr size_t MAX_CONCURRENT_PDU_EVENTS = 8; + f1c_other_srb_du_bearer::f1c_other_srb_du_bearer(f1ap_ue_context& ue_ctxt_, srb_id_t srb_id_, f1ap_message_notifier& f1ap_notifier_, @@ -123,15 +126,9 @@ f1c_other_srb_du_bearer::f1c_other_srb_du_bearer(f1ap_ue_context& ue_ctxt_ du_configurator(du_configurator_), ctrl_exec(ctrl_exec_), ue_exec(ue_exec_), - logger(srslog::fetch_basic_logger("DU-F1")) + logger(srslog::fetch_basic_logger("DU-F1")), + event_pool(MAX_CONCURRENT_PDU_EVENTS) { - // Mark all event entries as free. - for (auto& event : pending_delivery_event_pool) { - event.first = -1; - } - for (auto& event : pending_transmission_event_pool) { - event.first = -1; - } } void f1c_other_srb_du_bearer::handle_sdu(byte_buffer_chain sdu) @@ -260,22 +257,24 @@ async_task f1c_other_srb_du_bearer::handle_pdu_and_await(byte_buffer pdu, void f1c_other_srb_du_bearer::handle_notification(uint32_t highest_pdcp_sn, bool tx_or_delivery) { - std::optional& last_sn = tx_or_delivery ? last_pdcp_sn_transmitted : last_pdcp_sn_delivered; - auto& event_pool = tx_or_delivery ? pending_transmission_event_pool : pending_delivery_event_pool; + std::optional& last_sn = tx_or_delivery ? last_pdcp_sn_transmitted : last_pdcp_sn_delivered; + auto& pending_events = tx_or_delivery ? pending_transmissions : pending_deliveries; // Register the highest PDCP SN. last_sn = highest_pdcp_sn; // Trigger awaiters of delivery notifications. - for (auto& awaiter : event_pool) { - if (awaiter.first >= 0 and static_cast(awaiter.first) <= highest_pdcp_sn) { - // Free up the event entry. - awaiter.first = -1; - - // Trigger awaiter. - awaiter.second.set(); - } - } + pending_events.erase(std::remove_if(pending_events.begin(), + pending_events.end(), + [highest_pdcp_sn](const auto& event_pair) { + if (event_pair.first <= highest_pdcp_sn) { + // Trigger awaiter and remove it from the list of pending events. + event_pair.second->set(); + return true; + } + return false; + }), + pending_events.end()); } /// Create an always ready event. @@ -291,8 +290,8 @@ manual_event_flag& always_ready_flag() manual_event_flag& f1c_other_srb_du_bearer::wait_for_notification(uint32_t pdcp_sn, bool tx_or_delivery) { - std::optional& last_sn = tx_or_delivery ? last_pdcp_sn_transmitted : last_pdcp_sn_delivered; - auto& event_pool = tx_or_delivery ? pending_transmission_event_pool : pending_delivery_event_pool; + std::optional& last_sn = tx_or_delivery ? last_pdcp_sn_transmitted : last_pdcp_sn_delivered; + auto& pending_events = tx_or_delivery ? pending_transmissions : pending_deliveries; // Check if the PDU has been already delivered. if (last_sn.has_value() and last_sn.value() >= pdcp_sn) { @@ -301,23 +300,16 @@ manual_event_flag& f1c_other_srb_du_bearer::wait_for_notification(uint32_t pdcp_ } // Allocate a notification event awaitable. - size_t idx = 0; - for (; idx != event_pool.size(); ++idx) { - if (event_pool[idx].first < 0) { - // This event entry is free. - break; - } - } - if (idx == event_pool.size()) { - logger.warning("Rx PDU {}: Ignoring SRB{} Rx PDU {} notification. Cause: Failed to allocate notification handler.", + auto event_slot = event_pool.create(); + if (event_slot == nullptr) { + logger.warning("Rx PDU {}: Ignoring {} Rx PDU {} notification. Cause: Failed to allocate notification handler.", ue_ctxt, - srb_id_to_uint(srb_id), + srb_id, tx_or_delivery ? "Tx" : "delivery"); return always_ready_flag(); } // Allocation successful. Return awaitable event. - event_pool[idx].first = pdcp_sn; - event_pool[idx].second.reset(); - return event_pool[idx].second; + pending_events.emplace_back(pdcp_sn, std::move(event_slot)); + return *pending_events.back().second; } diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h index 014d4f856b..211fcb8e66 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h @@ -16,6 +16,7 @@ #include "srsran/f1ap/du/f1c_bearer.h" #include "srsran/ran/rnti.h" #include "srsran/support/async/manual_event.h" +#include "srsran/support/memory_pool/unsync_fixed_size_memory_block_pool.h" namespace srsran { namespace srs_du { @@ -81,7 +82,7 @@ class f1c_other_srb_du_bearer final : public f1c_bearer async_task handle_pdu_and_await_transmission(byte_buffer pdu) override; private: - static constexpr size_t MAX_CONCURRENT_PDU_EVENTS = 4; + using event_ptr = unsync_fixed_size_object_pool::ptr; async_task handle_pdu_and_await(byte_buffer pdu, bool tx_or_delivery); manual_event_flag& wait_for_notification(uint32_t pdcp_sn, bool tx_or_delivery); @@ -100,8 +101,9 @@ class f1c_other_srb_du_bearer final : public f1c_bearer std::optional last_pdcp_sn_delivered; // Pool of events for PDU transmission and delivery. Each entry is represented by the PDCP SN (negative if // the pool element is negative) and the event flag to wait for. - std::array, MAX_CONCURRENT_PDU_EVENTS> pending_delivery_event_pool; - std::array, MAX_CONCURRENT_PDU_EVENTS> pending_transmission_event_pool; + unsync_fixed_size_object_pool event_pool; + std::vector> pending_deliveries; + std::vector> pending_transmissions; }; } // namespace srs_du From 3a7914284cf68ba76109a15c832cdf0aafb6c38c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 15:21:23 +0200 Subject: [PATCH 196/407] f1ap-du: add timeouts for rrc container delivery in ue context setup and release --- include/srsran/f1ap/du/f1c_bearer.h | 5 +- lib/du_manager/du_ue/du_ue_adapters.cpp | 16 ++-- .../f1ap_du_ue_context_release_procedure.cpp | 37 +++++---- .../f1ap_du_ue_context_release_procedure.h | 4 +- .../f1ap_du_ue_context_setup_procedure.cpp | 25 +++++-- .../f1ap_du_ue_context_setup_procedure.h | 2 +- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 75 ++++++++++--------- lib/f1ap/du/ue_context/f1c_du_bearer_impl.h | 43 +++++++---- .../du_manager/du_manager_test_helpers.h | 8 +- 9 files changed, 128 insertions(+), 87 deletions(-) diff --git a/include/srsran/f1ap/du/f1c_bearer.h b/include/srsran/f1ap/du/f1c_bearer.h index d5ed84baff..7189cd5064 100644 --- a/include/srsran/f1ap/du/f1c_bearer.h +++ b/include/srsran/f1ap/du/f1c_bearer.h @@ -58,10 +58,11 @@ class f1c_rx_pdu_handler virtual void handle_pdu(byte_buffer pdu) = 0; /// Handle Rx PDU that is pushed to the F1AP from the F1-C and await its delivery (ACK) in the lower layers. - virtual async_task handle_pdu_and_await_delivery(byte_buffer pdu) = 0; + virtual async_task handle_pdu_and_await_delivery(byte_buffer pdu, std::chrono::milliseconds time_to_wait) = 0; /// Handle Rx PDU that is pushed to the F1AP from the F1-C and await its transmission by the lower layers. - virtual async_task handle_pdu_and_await_transmission(byte_buffer pdu) = 0; + virtual async_task handle_pdu_and_await_transmission(byte_buffer pdu, + std::chrono::milliseconds time_to_wait) = 0; }; class f1c_bearer : public f1c_tx_sdu_handler, public f1c_tx_delivery_handler, public f1c_rx_pdu_handler diff --git a/lib/du_manager/du_ue/du_ue_adapters.cpp b/lib/du_manager/du_ue/du_ue_adapters.cpp index ff918e6aab..dfcc7ec98d 100644 --- a/lib/du_manager/du_ue/du_ue_adapters.cpp +++ b/lib/du_manager/du_ue/du_ue_adapters.cpp @@ -21,11 +21,17 @@ class null_sink_f1c_bearer : public f1c_bearer { public: void handle_pdu(byte_buffer pdu) override {} - async_task handle_pdu_and_await_delivery(byte_buffer pdu) override { return launch_no_op_task(); } - async_task handle_pdu_and_await_transmission(byte_buffer pdu) override { return launch_no_op_task(); } - void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_bytes_free) override {} - void handle_delivery_notification(uint32_t highest_pdcp_sn) override {} - void handle_sdu(byte_buffer_chain sdu) override {} + async_task handle_pdu_and_await_delivery(byte_buffer pdu, std::chrono::milliseconds timeout) override + { + return launch_no_op_task(true); + } + async_task handle_pdu_and_await_transmission(byte_buffer pdu, std::chrono::milliseconds timeout) override + { + return launch_no_op_task(true); + } + void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_bytes_free) override {} + void handle_delivery_notification(uint32_t highest_pdcp_sn) override {} + void handle_sdu(byte_buffer_chain sdu) override {} } null_f1c_bearer; /// \brief F1-U Bearer Sink. Used to discard events while in the process of destroying a UE bearer. diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp index 11034eaf00..bbc8af7557 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp @@ -18,22 +18,19 @@ using namespace srsran; using namespace srs_du; +// Wait period for RRC container in UE CONTEXT RELEASE REQUEST to be delivered in the lower layers, before deleting +// the UE context. +const std::chrono::milliseconds rrc_container_delivery_timeout{120}; + f1ap_du_ue_context_release_procedure::f1ap_du_ue_context_release_procedure( const asn1::f1ap::ue_context_release_cmd_s& msg_, f1ap_du_ue_manager& ues) : - msg(msg_), - ue(*ues.find(int_to_gnb_du_ue_f1ap_id(msg->gnb_du_ue_f1ap_id))), - cu_msg_notifier(ue.f1ap_msg_notifier), - release_wait_timer(ue.du_handler.get_timer_factory().create_timer()) + msg(msg_), ue(*ues.find(int_to_gnb_du_ue_f1ap_id(msg->gnb_du_ue_f1ap_id))), cu_msg_notifier(ue.f1ap_msg_notifier) { } void f1ap_du_ue_context_release_procedure::operator()(coro_context>& ctx) { - // Wait period before the UE context is deleted from the DU. This value should be large enough to ensure any - // pending RRC message (e.g. RRC Release) is sent to the UE. - static const std::chrono::milliseconds ue_release_timeout{120}; - CORO_BEGIN(ctx); logger.debug("{}: Started.", f1ap_log_prefix{ue.context, name()}); @@ -47,15 +44,17 @@ void f1ap_du_ue_context_release_procedure::operator()(coro_contextrrc_container_present) { - CORO_AWAIT(handle_rrc_container()); + CORO_AWAIT_VALUE(bool ret, handle_rrc_container()); + if (ret) { + logger.debug("{}: RRC container delivered successfully.", f1ap_log_prefix{ue.context, name()}); + } else { + logger.info( + "{}: RRC container not delivered within a time window of {}msec. Proceeding with the UE context release.", + f1ap_log_prefix{ue.context, name()}, + rrc_container_delivery_timeout.count()); + } } - // Wait for pending RRC messages to be flushed. - logger.debug("{}: Waiting for {} milliseconds to flush pending RRC messages.", - f1ap_log_prefix{ue.context, name()}, - ue_release_timeout.count()); - CORO_AWAIT(async_wait_for(release_wait_timer, ue_release_timeout)); - // Remove UE from DU manager. logger.debug("{}: Initiate UE release in lower layers.", f1ap_log_prefix{ue.context, name()}); CORO_AWAIT(ue.du_handler.request_ue_removal(f1ap_ue_delete_request{ue.context.ue_index})); @@ -68,7 +67,7 @@ void f1ap_du_ue_context_release_procedure::operator()(coro_context f1ap_du_ue_context_release_procedure::handle_rrc_container() +async_task f1ap_du_ue_context_release_procedure::handle_rrc_container() { f1c_bearer* srb = nullptr; if (msg->srb_id_present) { @@ -77,17 +76,17 @@ async_task f1ap_du_ue_context_release_procedure::handle_rrc_container() if (srb == nullptr) { logger.error("{}: Discarding RRC container. Cause: {} not found", f1ap_log_prefix{ue.context, name()}, srb_id); // Handle Error. - return launch_no_op_task(); + return launch_no_op_task(false); } } else { logger.error("{}: Discarding RRC container. Cause: SRB-ID not defined", f1ap_log_prefix{ue.context, name()}); // Handle Error. - return launch_no_op_task(); + return launch_no_op_task(false); } // Forward F1AP PDU to lower layers, and await for PDU to be transmitted over-the-air. - return srb->handle_pdu_and_await_transmission(msg->rrc_container.copy()); + return srb->handle_pdu_and_await_transmission(msg->rrc_container.copy(), rrc_container_delivery_timeout); } void f1ap_du_ue_context_release_procedure::send_ue_context_release_complete() diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h index 78421d52cb..4c56b1d72f 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.h @@ -29,14 +29,12 @@ class f1ap_du_ue_context_release_procedure void send_ue_context_release_complete(); - async_task handle_rrc_container(); + async_task handle_rrc_container(); const asn1::f1ap::ue_context_release_cmd_s msg; f1ap_du_ue& ue; srslog::basic_logger& logger = srslog::fetch_basic_logger("DU-F1"); f1ap_message_notifier& cu_msg_notifier; // used after the UE context as been released. - - unique_timer release_wait_timer; }; } // namespace srs_du diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index 4a36e4a0d8..3505fd266e 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -20,6 +20,9 @@ using namespace srsran; using namespace srs_du; using namespace asn1::f1ap; +// Time waiting for RRC container delivery. +constexpr std::chrono::milliseconds rrc_container_delivery_timeout{120}; + f1ap_du_ue_context_setup_procedure::f1ap_du_ue_context_setup_procedure( const asn1::f1ap::ue_context_setup_request_s& msg_, f1ap_du_ue_manager& ue_mng_, @@ -92,7 +95,16 @@ void f1ap_du_ue_context_setup_procedure::operator()(coro_context If the UE CONTEXT SETUP REQUEST message contains the RRC-Container IE, the gNB-DU shall send the corresponding // RRC message to the UE via SRB1. if (msg->rrc_container_present and not msg->rrc_container.empty()) { - CORO_AWAIT(handle_rrc_container()); + CORO_AWAIT_VALUE(bool ret, handle_rrc_container()); + if (ret) { + logger.debug("{}: RRC container sent successfully.", f1ap_log_prefix{ue->context, name()}); + } else { + logger.error("{}: Failed to send RRC container after timeout of {}msec", + f1ap_log_prefix{ue->context, name()}, + rrc_container_delivery_timeout.count()); + send_ue_context_setup_failure(); + CORO_EARLY_RETURN(); + } } // Respond back to CU-CP with success. @@ -101,14 +113,15 @@ void f1ap_du_ue_context_setup_procedure::operator()(coro_context f1ap_du_ue_context_setup_procedure::handle_rrc_container() +async_task f1ap_du_ue_context_setup_procedure::handle_rrc_container() { f1c_bearer* srb1 = ue->bearers.find_srb(srb_id_t::srb1); - if (srb1 != nullptr) { - return srb1->handle_pdu_and_await_transmission(msg->rrc_container.copy()); + if (srb1 == nullptr) { + logger.error("{}: Failed to find SRB1 bearer to send RRC container.", f1ap_log_prefix{ue->context, name()}); + return launch_no_op_task(false); } - logger.error("{}: Failed to find SRB1 bearer to send RRC container.", f1ap_log_prefix{ue->context, name()}); - return launch_no_op_task(); + + return srb1->handle_pdu_and_await_transmission(msg->rrc_container.copy(), rrc_container_delivery_timeout); } async_task f1ap_du_ue_context_setup_procedure::request_du_ue_config() diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h index 911df08465..2d639c491a 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h @@ -39,7 +39,7 @@ class f1ap_du_ue_context_setup_procedure // Send UE Context Setup Failure to CU. void send_ue_context_setup_failure(); - async_task handle_rrc_container(); + async_task handle_rrc_container(); const char* name() const { return "UE Context Setup"; } diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp index a255248ae1..881515f63a 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -91,22 +91,24 @@ void f1c_srb0_du_bearer::handle_pdu(byte_buffer pdu) } } -async_task f1c_srb0_du_bearer::handle_pdu_and_await_delivery(byte_buffer sdu) +async_task f1c_srb0_du_bearer::handle_pdu_and_await_delivery(byte_buffer sdu, + std::chrono::milliseconds time_to_wait) { // Forward task to lower layers. handle_pdu(std::move(sdu)); // For SRB0, there is no delivery notification. - return launch_no_op_task(); + return launch_no_op_task(true); } -async_task f1c_srb0_du_bearer::handle_pdu_and_await_transmission(byte_buffer pdu) +async_task f1c_srb0_du_bearer::handle_pdu_and_await_transmission(byte_buffer pdu, + std::chrono::milliseconds time_to_wait) { // Forward task to lower layers. handle_pdu(std::move(pdu)); // For SRB0, there is no transmission notification. - return launch_no_op_task(); + return launch_no_op_task(true); } // Max number of concurrent PDCP SN deliveries/transmissions being awaited on. @@ -129,6 +131,10 @@ f1c_other_srb_du_bearer::f1c_other_srb_du_bearer(f1ap_ue_context& ue_ctxt_ logger(srslog::fetch_basic_logger("DU-F1")), event_pool(MAX_CONCURRENT_PDU_EVENTS) { + // set up the always set event + event_source_type source{du_configurator.get_timer_factory()}; + always_set_event.subscribe_to(source, std::chrono::milliseconds{0}); + source.set(true); } void f1c_other_srb_du_bearer::handle_sdu(byte_buffer_chain sdu) @@ -192,14 +198,16 @@ void f1c_other_srb_du_bearer::handle_pdu(srsran::byte_buffer pdu) } } -async_task f1c_other_srb_du_bearer::handle_pdu_and_await_transmission(byte_buffer pdu) +async_task f1c_other_srb_du_bearer::handle_pdu_and_await_transmission(byte_buffer pdu, + std::chrono::milliseconds time_to_wait) { - return handle_pdu_and_await(std::move(pdu), true); + return handle_pdu_and_await(std::move(pdu), true, time_to_wait); } -async_task f1c_other_srb_du_bearer::handle_pdu_and_await_delivery(byte_buffer pdu) +async_task f1c_other_srb_du_bearer::handle_pdu_and_await_delivery(byte_buffer pdu, + std::chrono::milliseconds time_to_wait) { - return handle_pdu_and_await(std::move(pdu), false); + return handle_pdu_and_await(std::move(pdu), false, time_to_wait); } void f1c_other_srb_du_bearer::handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) @@ -218,7 +226,9 @@ void f1c_other_srb_du_bearer::handle_delivery_notification(uint32_t highest_pdcp } } -async_task f1c_other_srb_du_bearer::handle_pdu_and_await(byte_buffer pdu, bool tx_or_delivery) +async_task f1c_other_srb_du_bearer::handle_pdu_and_await(byte_buffer pdu, + bool tx_or_delivery, + std::chrono::milliseconds time_to_wait) { // Extract PDCP SN. std::optional pdcp_sn = get_pdcp_sn(pdu, pdcp_sn_size::size12bits, true, logger); @@ -233,11 +243,15 @@ async_task f1c_other_srb_du_bearer::handle_pdu_and_await(byte_buffer pdu, ue_ctxt, srb_id_to_uint(srb_id), tx_or_delivery ? "Tx" : "delivery"); - return launch_no_op_task(); + return launch_no_op_task(false); } - return launch_async([this, pdcp_sn = pdcp_sn.value(), tx_or_delivery, sdu = std::move(pdu)]( - coro_context>& ctx) mutable { + return launch_async([this, + pdcp_sn = pdcp_sn.value(), + tx_or_delivery, + time_to_wait, + result = event_result_type{}, + sdu = std::move(pdu)](coro_context>& ctx) mutable { CORO_BEGIN(ctx); CORO_AWAIT(execute_on_blocking(ue_exec)); @@ -246,12 +260,13 @@ async_task f1c_other_srb_du_bearer::handle_pdu_and_await(byte_buffer pdu, sdu_notifier.on_new_sdu(std::move(sdu)); // Await SDU delivery. - CORO_AWAIT(wait_for_notification(pdcp_sn, tx_or_delivery)); + CORO_AWAIT_VALUE(result, wait_for_notification(pdcp_sn, tx_or_delivery, time_to_wait)); // Return back to control executor. CORO_AWAIT(execute_on_blocking(ctrl_exec)); - CORO_RETURN(); + // True for success, false for timeout/cancel. + CORO_RETURN(result.index() == 0); }); } @@ -266,10 +281,10 @@ void f1c_other_srb_du_bearer::handle_notification(uint32_t highest_pdcp_sn, bool // Trigger awaiters of delivery notifications. pending_events.erase(std::remove_if(pending_events.begin(), pending_events.end(), - [highest_pdcp_sn](const auto& event_pair) { - if (event_pair.first <= highest_pdcp_sn) { + [highest_pdcp_sn](const auto& event) { + if (event->pdcp_sn <= highest_pdcp_sn) { // Trigger awaiter and remove it from the list of pending events. - event_pair.second->set(); + event->source.set(true); return true; } return false; @@ -277,18 +292,10 @@ void f1c_other_srb_du_bearer::handle_notification(uint32_t highest_pdcp_sn, bool pending_events.end()); } -/// Create an always ready event. -manual_event_flag& always_ready_flag() -{ - static manual_event_flag& flag = []() -> manual_event_flag& { - static manual_event_flag event_flag; - event_flag.set(); - return event_flag; - }(); - return flag; -} - -manual_event_flag& f1c_other_srb_du_bearer::wait_for_notification(uint32_t pdcp_sn, bool tx_or_delivery) +f1c_other_srb_du_bearer::event_observer_type& +f1c_other_srb_du_bearer::wait_for_notification(uint32_t pdcp_sn, + bool tx_or_delivery, + std::chrono::milliseconds time_to_wait) { std::optional& last_sn = tx_or_delivery ? last_pdcp_sn_transmitted : last_pdcp_sn_delivered; auto& pending_events = tx_or_delivery ? pending_transmissions : pending_deliveries; @@ -296,20 +303,20 @@ manual_event_flag& f1c_other_srb_du_bearer::wait_for_notification(uint32_t pdcp_ // Check if the PDU has been already delivered. if (last_sn.has_value() and last_sn.value() >= pdcp_sn) { // SN already notified. - return always_ready_flag(); + return always_set_event; } // Allocate a notification event awaitable. - auto event_slot = event_pool.create(); + auto event_slot = event_pool.create(pdcp_sn, du_configurator.get_timer_factory(), time_to_wait); if (event_slot == nullptr) { logger.warning("Rx PDU {}: Ignoring {} Rx PDU {} notification. Cause: Failed to allocate notification handler.", ue_ctxt, srb_id, tx_or_delivery ? "Tx" : "delivery"); - return always_ready_flag(); + return always_set_event; } // Allocation successful. Return awaitable event. - pending_events.emplace_back(pdcp_sn, std::move(event_slot)); - return *pending_events.back().second; + pending_events.emplace_back(std::move(event_slot)); + return pending_events.back()->observer; } diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h index 211fcb8e66..771bc88d4f 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h @@ -15,7 +15,7 @@ #include "srsran/f1ap/du/f1ap_du.h" #include "srsran/f1ap/du/f1c_bearer.h" #include "srsran/ran/rnti.h" -#include "srsran/support/async/manual_event.h" +#include "srsran/support/async/protocol_transaction_manager.h" #include "srsran/support/memory_pool/unsync_fixed_size_memory_block_pool.h" namespace srsran { @@ -44,8 +44,8 @@ class f1c_srb0_du_bearer final : public f1c_bearer void handle_delivery_notification(uint32_t highest_pdcp_sn) override; void handle_pdu(byte_buffer pdu) override; - async_task handle_pdu_and_await_delivery(byte_buffer sdu) override; - async_task handle_pdu_and_await_transmission(byte_buffer pdu) override; + async_task handle_pdu_and_await_delivery(byte_buffer sdu, std::chrono::milliseconds time_to_wait) override; + async_task handle_pdu_and_await_transmission(byte_buffer pdu, std::chrono::milliseconds time_to_wait) override; private: f1ap_ue_context& ue_ctxt; @@ -78,15 +78,31 @@ class f1c_other_srb_du_bearer final : public f1c_bearer void handle_delivery_notification(uint32_t highest_pdcp_sn) override; void handle_pdu(byte_buffer sdu) override; - async_task handle_pdu_and_await_delivery(byte_buffer sdu) override; - async_task handle_pdu_and_await_transmission(byte_buffer pdu) override; + async_task handle_pdu_and_await_delivery(byte_buffer pdu, std::chrono::milliseconds time_to_wait) override; + async_task handle_pdu_and_await_transmission(byte_buffer pdu, std::chrono::milliseconds time_to_wait) override; private: - using event_ptr = unsync_fixed_size_object_pool::ptr; - - async_task handle_pdu_and_await(byte_buffer pdu, bool tx_or_delivery); - manual_event_flag& wait_for_notification(uint32_t pdcp_sn, bool tx_or_delivery); - void handle_notification(uint32_t highest_pdcp_sn, bool tx_or_delivery); + using event_source_type = protocol_transaction_event_source; + using event_observer_type = protocol_transaction_outcome_observer; + using event_result_type = std::variant; + + struct event_context { + uint32_t pdcp_sn; + event_source_type source; + event_observer_type observer; + + event_context(uint32_t pdcp_sn_, timer_factory timers, std::chrono::milliseconds time_to_wait) : + pdcp_sn(pdcp_sn_), source(timers) + { + observer.subscribe_to(source, time_to_wait); + } + }; + using event_ptr = unsync_fixed_size_object_pool::ptr; + + async_task handle_pdu_and_await(byte_buffer pdu, bool tx_or_delivery, std::chrono::milliseconds time_to_wait); + event_observer_type& + wait_for_notification(uint32_t pdcp_sn, bool tx_or_delivery, std::chrono::milliseconds time_to_wait); + void handle_notification(uint32_t highest_pdcp_sn, bool tx_or_delivery); f1ap_ue_context& ue_ctxt; srb_id_t srb_id; @@ -96,14 +112,15 @@ class f1c_other_srb_du_bearer final : public f1c_bearer task_executor& ctrl_exec; task_executor& ue_exec; srslog::basic_logger& logger; + event_observer_type always_set_event; std::optional last_pdcp_sn_transmitted; std::optional last_pdcp_sn_delivered; // Pool of events for PDU transmission and delivery. Each entry is represented by the PDCP SN (negative if // the pool element is negative) and the event flag to wait for. - unsync_fixed_size_object_pool event_pool; - std::vector> pending_deliveries; - std::vector> pending_transmissions; + unsync_fixed_size_object_pool event_pool; + std::vector pending_deliveries; + std::vector pending_transmissions; }; } // namespace srs_du diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index 3d4350bd0a..b972893a8e 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -70,15 +70,15 @@ class dummy_f1c_bearer : public f1c_bearer byte_buffer_chain last_tx_sdu = byte_buffer_chain::create().value(); void handle_pdu(byte_buffer pdu) override { last_rx_pdu = std::move(pdu); } - async_task handle_pdu_and_await_delivery(byte_buffer pdu) override + async_task handle_pdu_and_await_delivery(byte_buffer pdu, std::chrono::milliseconds timeout) override { last_rx_pdu = std::move(pdu); - return launch_no_op_task(); + return launch_no_op_task(true); } - async_task handle_pdu_and_await_transmission(byte_buffer pdu) override + async_task handle_pdu_and_await_transmission(byte_buffer pdu, std::chrono::milliseconds timeout) override { last_rx_pdu = std::move(pdu); - return launch_no_op_task(); + return launch_no_op_task(true); } void handle_sdu(byte_buffer_chain sdu) override { last_tx_sdu = std::move(sdu); } void handle_transmit_notification(uint32_t highest_pdcp_sn, uint32_t queue_free_bytes) override {} From 1bf2eb8c4c27529cbff5836593b5cc7843b79b4e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 16:06:02 +0200 Subject: [PATCH 197/407] f1ap-du: wait for delivery rather than transmission of RRC container --- .../f1ap_du_ue_context_release_procedure.cpp | 9 +++++---- .../test_utils/du_high_env_simulator.cpp | 17 +++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp index bbc8af7557..e6c7ea8dba 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp @@ -18,8 +18,9 @@ using namespace srsran; using namespace srs_du; -// Wait period for RRC container in UE CONTEXT RELEASE REQUEST to be delivered in the lower layers, before deleting -// the UE context. +// Wait period for RRC container in UE CONTEXT RELEASE REQUEST to be delivered in the lower layers. +// Note: This timeout should account for the delay for the UE to receive the RRC container, which is non-deterministic, +// and the timeout of 60msec specified in TS 38.331, 5.3.8.3 for the UE to ACK the RRC container. const std::chrono::milliseconds rrc_container_delivery_timeout{120}; f1ap_du_ue_context_release_procedure::f1ap_du_ue_context_release_procedure( @@ -49,7 +50,7 @@ void f1ap_du_ue_context_release_procedure::operator()(coro_context f1ap_du_ue_context_release_procedure::handle_rrc_container() } // Forward F1AP PDU to lower layers, and await for PDU to be transmitted over-the-air. - return srb->handle_pdu_and_await_transmission(msg->rrc_container.copy(), rrc_container_delivery_timeout); + return srb->handle_pdu_and_await_delivery(msg->rrc_container.copy(), rrc_container_delivery_timeout); } void f1ap_du_ue_context_release_procedure::send_ue_context_release_complete() diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 48ab9f8d80..53f7a52fdb 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -156,14 +156,15 @@ du_high_env_simulator::du_high_env_simulator(du_high_env_sim_params params) : init_loggers(); du_high_configuration cfg{}; - cfg.exec_mapper = &workers.exec_mapper; - cfg.f1c_client = &cu_notifier; - cfg.f1u_gw = &cu_up_sim; - cfg.phy_adapter = &phy; - cfg.timers = &timers; - cfg.gnb_du_id = gnb_du_id_t::min; - cfg.gnb_du_name = "srsdu"; - cfg.du_bind_addr = transport_layer_address::create_from_string("127.0.0.1"); + cfg.exec_mapper = &workers.exec_mapper; + cfg.f1c_client = &cu_notifier; + cfg.f1u_gw = &cu_up_sim; + cfg.phy_adapter = &phy; + cfg.timers = &timers; + cfg.gnb_du_id = gnb_du_id_t::min; + cfg.gnb_du_name = "srsdu"; + cfg.du_bind_addr = transport_layer_address::create_from_string("127.0.0.1"); + cfg.sched_cfg.log_broadcast_messages = false; cfg.cells.reserve(params.nof_cells); cell_config_builder_params builder_params; From 856e7225afcd9447da4caec4969cfc045a6347e9 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 16:31:12 +0200 Subject: [PATCH 198/407] sched: remove requirement to wait for SRB1 scheduling during UE removal in the scheduler --- .../ue_scheduling/dl_logical_channel_manager.cpp | 8 ++++++++ .../ue_scheduling/dl_logical_channel_manager.h | 3 +++ lib/scheduler/ue_scheduling/ue.cpp | 11 +++++------ lib/scheduler/ue_scheduling/ue_cell.cpp | 9 ++++++--- lib/scheduler/ue_scheduling/ue_repository.cpp | 5 ++--- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/scheduler/ue_scheduling/dl_logical_channel_manager.cpp b/lib/scheduler/ue_scheduling/dl_logical_channel_manager.cpp index c01089c667..b41ab132ee 100644 --- a/lib/scheduler/ue_scheduling/dl_logical_channel_manager.cpp +++ b/lib/scheduler/ue_scheduling/dl_logical_channel_manager.cpp @@ -27,6 +27,14 @@ dl_logical_channel_manager::dl_logical_channel_manager() set_status(LCID_SRB0, true); } +void dl_logical_channel_manager::deactivate() +{ + for (unsigned lcid = LCID_SRB0; lcid <= LCID_MAX_DRB; lcid++) { + set_status((lcid_t)lcid, false); + } + pending_ces.clear(); +} + void dl_logical_channel_manager::configure(span log_channels_configs) { for (unsigned i = 1; i != channels.size(); ++i) { diff --git a/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h b/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h index 66b47b5e87..30c262a3cd 100644 --- a/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h @@ -31,6 +31,9 @@ class dl_logical_channel_manager dl_logical_channel_manager(); + /// \brief Deactivate all bearers. + void deactivate(); + /// \brief Activate/Deactivate Bearer. void set_status(lcid_t lcid, bool active) { diff --git a/lib/scheduler/ue_scheduling/ue.cpp b/lib/scheduler/ue_scheduling/ue.cpp index 8a1089e1bc..f3c38ed967 100644 --- a/lib/scheduler/ue_scheduling/ue.cpp +++ b/lib/scheduler/ue_scheduling/ue.cpp @@ -62,16 +62,15 @@ void ue::slot_indication(slot_point sl_tx) void ue::deactivate() { - // Disable DL DRBs. - for (unsigned lcid = LCID_MIN_DRB; lcid <= LCID_MAX_DRB; lcid++) { - dl_lc_ch_mgr.set_status((lcid_t)lcid, false); - } + // Disable DL SRBs and DRBs. + // Note: We assume that when this function is called any pending RRC container (e.g. containing RRC Release) has + // already been Tx+ACKed or an upper layer timeout has triggered. + dl_lc_ch_mgr.deactivate(); // Disable UL SRBs and DRBs. ul_lc_ch_mgr.deactivate(); - // Stop UL HARQ retransmissions. - // Note: We do no stop DL retransmissions because we are still relying on DL to send a potential RRC Release. + // Cancel HARQ retransmissions in all UE cells. for (unsigned i = 0; i != ue_du_cells.size(); ++i) { if (ue_du_cells[i] != nullptr) { ue_du_cells[i]->deactivate(); diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index cd25936df9..ced808bb50 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -45,12 +45,15 @@ ue_cell::ue_cell(du_ue_index_t ue_index_, void ue_cell::deactivate() { - // Stop UL HARQ retransmissions. - // Note: We do no stop DL retransmissions because we are still relying on DL to send a potential RRC Release. + // Stop HARQ retransmissions. + // Note: We assume that when this function is called, any RRC container (e.g. containing RRC Release) was already + // transmitted+ACKed (ensured by F1AP). + for (unsigned hid = 0; hid != harqs.nof_dl_harqs(); ++hid) { + harqs.dl_harq(hid).cancel_harq_retxs(0); + } for (unsigned hid = 0; hid != harqs.nof_ul_harqs(); ++hid) { harqs.ul_harq(hid).cancel_harq_retxs(); } - active = false; } diff --git a/lib/scheduler/ue_scheduling/ue_repository.cpp b/lib/scheduler/ue_scheduling/ue_repository.cpp index ae5526e62e..715079d9ac 100644 --- a/lib/scheduler/ue_scheduling/ue_repository.cpp +++ b/lib/scheduler/ue_scheduling/ue_repository.cpp @@ -19,9 +19,8 @@ ue_repository::ue_repository() : logger(srslog::fetch_basic_logger("SCHED")) rnti_to_ue_index_lookup.reserve(MAX_NOF_DU_UES); } -/// \brief This function checks whether it is safe to remove a UE. Currently we verify that: -/// - The UE has no pending DL SRB data. This ensures that messages like RRC Release are sent before the UE removal. -/// - The UE has no DL or UL HARQ awaiting an ACK. +/// \brief This function checks whether it is safe to remove a UE. Currently we verify that the UE has no DL or UL +/// HARQ awaiting an ACK. static bool is_ue_ready_for_removal(ue& u) { // Ensure that there no currently active HARQs. From be0197d27dd947a3c9219d70a962cc2efe69e89f Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 17:27:43 +0200 Subject: [PATCH 199/407] ngap: add support for handover cancel --- lib/ngap/ngap_impl.cpp | 3 +++ lib/ngap/procedures/ngap_transaction_manager.h | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index e8fb231fff..72f6690f69 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -837,6 +837,9 @@ void ngap_impl::handle_successful_outcome(const successful_outcome_s& outcome) case ngap_elem_procs_o::successful_outcome_c::types_opts::ho_cmd: { ev_mng.handover_preparation_outcome.set(outcome.value.ho_cmd()); } break; + case ngap_elem_procs_o::successful_outcome_c::types_opts::ho_cancel_ack: { + ev_mng.handover_cancel_outcome.set(outcome.value.ho_cancel_ack()); + } break; default: logger.error("Successful outcome of type {} is not supported", outcome.value.type().to_string()); } diff --git a/lib/ngap/procedures/ngap_transaction_manager.h b/lib/ngap/procedures/ngap_transaction_manager.h index 76ae96b1c2..ac47fe2bec 100644 --- a/lib/ngap/procedures/ngap_transaction_manager.h +++ b/lib/ngap/procedures/ngap_transaction_manager.h @@ -21,7 +21,10 @@ class ngap_transaction_manager { public: ngap_transaction_manager(timer_factory timers) : - ng_setup_outcome(timers), ng_reset_outcome(timers), handover_preparation_outcome(timers) + ng_setup_outcome(timers), + ng_reset_outcome(timers), + handover_preparation_outcome(timers), + handover_cancel_outcome(timers) { } @@ -33,6 +36,9 @@ class ngap_transaction_manager /// Handover Preparation Response/Failure Event Source. protocol_transaction_event_source handover_preparation_outcome; + + /// Handover Cancel Ack Event Source. + protocol_transaction_event_source handover_cancel_outcome; }; } // namespace srs_cu_cp From 82c89ec1456ffad978247bba5fe10566448624bc Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 17:28:40 +0200 Subject: [PATCH 200/407] cu_cp,ngap: add handling of handover cancel --- .../ngap_handover_preparation_procedure.cpp | 35 +++++++++++++++++-- .../ngap_handover_preparation_procedure.h | 3 ++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp index 16af4fb965..a921b8400e 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp @@ -17,6 +17,8 @@ using namespace srsran; using namespace srsran::srs_cu_cp; using namespace asn1::ngap; +constexpr std::chrono::milliseconds ng_cancel_ack_timeout{5000}; + ngap_handover_preparation_procedure::ngap_handover_preparation_procedure( const ngap_handover_preparation_request& request_, const ngap_context_t& context_, @@ -63,7 +65,20 @@ void ngap_handover_preparation_procedure::operator()(coro_contextamf_ue_ngap_id = amf_ue_id_to_uint(ue_ids.amf_ue_id); + ho_cancel->ran_ue_ngap_id = ran_ue_id_to_uint(ue_ids.ran_ue_id); + + ho_cancel->cause.set_radio_network(); + ho_cancel->cause.set_radio_network() = cause_radio_network_opts::ho_cancelled; + amf_notifier.on_new_message(msg); +} + void ngap_handover_preparation_procedure::fill_asn1_target_ran_node_id(target_id_c& target_id) { auto& target_node = target_id.set_target_ran_node_id(); @@ -187,7 +218,7 @@ byte_buffer ngap_handover_preparation_procedure::fill_asn1_source_to_target_tran byte_buffer ngap_handover_preparation_procedure::get_rrc_handover_command() { - auto& target_to_source_container_packed = transaction_sink.response()->target_to_source_transparent_container; + const auto& target_to_source_container_packed = transaction_sink.response()->target_to_source_transparent_container; asn1::ngap::target_ngran_node_to_source_ngran_node_transparent_container_s target_to_source_container; asn1::cbit_ref bref({target_to_source_container_packed.begin(), target_to_source_container_packed.end()}); diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.h b/lib/ngap/procedures/ngap_handover_preparation_procedure.h index d23e00a266..039c30493e 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.h +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.h @@ -13,6 +13,7 @@ #include "../ngap_context.h" #include "../ue_context/ngap_ue_context.h" #include "ngap_transaction_manager.h" +#include "srsran/asn1/ngap/ngap_pdu_contents.h" #include "srsran/ngap/ngap.h" #include "srsran/support/async/async_task.h" @@ -51,11 +52,13 @@ class ngap_handover_preparation_procedure ngap_ue_source_handover_context ho_ue_context; protocol_transaction_outcome_observer transaction_sink; + protocol_transaction_outcome_observer ho_cancel_transaction_sink; byte_buffer rrc_ho_cmd_pdu = byte_buffer{}; bool rrc_reconfig_success = false; void get_required_handover_context(); void send_handover_required(); + void send_handover_cancel(); byte_buffer get_rrc_handover_command(); // ASN.1 helpers From 16eb59afdc113a92fbb3c1c6cbc4ca9f99b00785 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 18:29:56 +0200 Subject: [PATCH 201/407] cu_cp: refactor handover tests --- .../ngap/ngap_test_message_validators.cpp | 14 +++ .../ngap/ngap_test_message_validators.h | 4 + tests/unittests/cu_cp/CMakeLists.txt | 2 +- ...t.cpp => cu_cp_inter_cu_handover_test.cpp} | 68 +++++++++++- tests/unittests/cu_cp/mobility/CMakeLists.txt | 3 +- .../inter_cu_handover_routine_test.cpp | 105 ------------------ .../cu_cp/mobility/mobility_test_helpers.h | 9 +- tests/unittests/ngap/ngap_test_messages.cpp | 17 ++- tests/unittests/ngap/ngap_test_messages.h | 3 + 9 files changed, 106 insertions(+), 119 deletions(-) rename tests/unittests/cu_cp/{cu_cp_handover_test.cpp => cu_cp_inter_cu_handover_test.cpp} (70%) delete mode 100644 tests/unittests/cu_cp/mobility/inter_cu_handover_routine_test.cpp diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.cpp b/tests/test_doubles/ngap/ngap_test_message_validators.cpp index 3b3be3bfed..36a2d0b82e 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.cpp +++ b/tests/test_doubles/ngap/ngap_test_message_validators.cpp @@ -105,6 +105,20 @@ bool srsran::test_helpers::is_valid_handover_notify(const srs_cu_cp::ngap_messag return true; } +bool srsran::test_helpers::is_valid_handover_required(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_NGAP_ID_HO_PREP); + return true; +} + +bool srsran::test_helpers::is_valid_handover_cancel(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_NGAP_ID_HO_CANCEL); + return true; +} + bool srsran::test_helpers::is_expected_pdu_session_resource_setup_response( const ngap_message& ngap_pdu, const std::vector& expected_pdu_sessions_to_setup, diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.h b/tests/test_doubles/ngap/ngap_test_message_validators.h index be5fa93829..671e6c2be8 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.h +++ b/tests/test_doubles/ngap/ngap_test_message_validators.h @@ -45,6 +45,10 @@ bool is_valid_handover_request_ack(const srs_cu_cp::ngap_message& msg); bool is_valid_handover_notify(const srs_cu_cp::ngap_message& msg); +bool is_valid_handover_required(const srs_cu_cp::ngap_message& msg); + +bool is_valid_handover_cancel(const srs_cu_cp::ngap_message& msg); + // Check if the NGAP PDU contains the expected PDU session setup response. bool is_expected_pdu_session_resource_setup_response( const srs_cu_cp::ngap_message& ngap_pdu, diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index 2d5fa72556..fcd115edbe 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -42,8 +42,8 @@ add_executable(cu_cp_test cu_cp_pdu_session_resource_modify_test.cpp cu_cp_paging_test.cpp cu_cp_inactivity_notification_test.cpp - cu_cp_handover_test.cpp cu_cp_inter_du_handover_test.cpp + cu_cp_inter_cu_handover_test.cpp ) set_target_properties(cu_cp_test PROPERTIES UNITY_BUILD ON) target_link_libraries(cu_cp_test diff --git a/tests/unittests/cu_cp/cu_cp_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp similarity index 70% rename from tests/unittests/cu_cp/cu_cp_handover_test.cpp rename to tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp index 49e93c82b5..dcb1f3dbc7 100644 --- a/tests/unittests/cu_cp/cu_cp_handover_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp @@ -27,10 +27,10 @@ using namespace srsran; using namespace srs_cu_cp; -class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Test +class cu_cp_inter_cu_handover_test : public cu_cp_test_environment, public ::testing::Test { public: - cu_cp_handover_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) + cu_cp_inter_cu_handover_test() : cu_cp_test_environment(cu_cp_test_env_params{8, 8, 8192, create_mock_amf()}) { // Run NG setup to completion. run_ng_setup(); @@ -48,6 +48,17 @@ class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Tes EXPECT_TRUE(this->run_e1_setup(cu_up_idx)); } + [[nodiscard]] bool attach_ue() + { + if (!cu_cp_test_environment::attach_ue( + du_idx, cu_up_idx, du_ue_id, crnti, amf_ue_id, cu_up_e1ap_id, psi, drb_id_t::drb1, qfi)) { + return false; + } + ue_ctx = this->find_ue_context(du_idx, du_ue_id); + + return ue_ctx != nullptr; + } + [[nodiscard]] bool send_handover_request_and_await_bearer_context_setup_request() { report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), @@ -112,6 +123,37 @@ class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Tes return true; } + [[nodiscard]] bool send_rrc_measurement_report_and_await_handover_required() + { + // Inject UL RRC Message (containing RRC Measurement Report) and wait for Handover Required + get_du(du_idx).push_ul_pdu( + generate_ul_rrc_message_transfer(ue_ctx->cu_ue_id.value(), + ue_ctx->du_ue_id.value(), + srb_id_t::srb1, + make_byte_buffer("000800410004015f741fe0804bf183fcaa6e9699").value())); + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Handover Required"); + report_fatal_error_if_not(test_helpers::is_valid_handover_required(ngap_pdu), "Invalid Handover Required"); + return true; + } + + [[nodiscard]] bool timeout_handover_command_and_await_handover_cancel() + { + // Fail Handover Preparation (AMF doesn't respond) and await Handover Cancel + if (tick_until(std::chrono::milliseconds(1000), [&]() { return false; })) { + return false; + } + report_fatal_error_if_not(this->wait_for_ngap_tx_pdu(ngap_pdu), "Failed to receive Handover Cancel"); + report_fatal_error_if_not(test_helpers::is_valid_handover_cancel(ngap_pdu), "Invalid Handover Cancel"); + return true; + } + + [[nodiscard]] bool send_handover_cancel_ack() + { + // Inject Handover Cancel Ack + get_amf().push_tx_pdu(generate_handover_cancel_ack(ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value())); + return true; + } + unsigned du_idx = 0; unsigned cu_up_idx = 0; @@ -123,12 +165,17 @@ class cu_cp_handover_test : public cu_cp_test_environment, public ::testing::Tes gnb_cu_up_ue_e1ap_id_t cu_up_e1ap_id = gnb_cu_up_ue_e1ap_id_t::min; gnb_cu_cp_ue_e1ap_id_t cu_cp_e1ap_id; + const ue_context* ue_ctx = nullptr; + + pdu_session_id_t psi = uint_to_pdu_session_id(1); + qos_flow_id_t qfi = uint_to_qos_flow_id(1); + ngap_message ngap_pdu; f1ap_message f1ap_pdu; e1ap_message e1ap_pdu; }; -TEST_F(cu_cp_handover_test, when_handover_request_received_then_handover_notify_is_sent) +TEST_F(cu_cp_inter_cu_handover_test, when_handover_request_received_then_handover_notify_is_sent) { // Inject Handover Request and await Bearer Context Setup Request ASSERT_TRUE(send_handover_request_and_await_bearer_context_setup_request()); @@ -145,3 +192,18 @@ TEST_F(cu_cp_handover_test, when_handover_request_received_then_handover_notify_ // Inject RRC Reconfiguration Complete and await Handover Notify ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_handover_notify()); } + +TEST_F(cu_cp_inter_cu_handover_test, when_handover_command_times_out_then_handover_cancel_is_sent) +{ + // Attach UE + ASSERT_TRUE(attach_ue()); + + // Inject RRC Measurement Report and await Handover Required + ASSERT_TRUE(send_rrc_measurement_report_and_await_handover_required()); + + // timeout Handover Command and await Handover Cancel + ASSERT_TRUE(timeout_handover_command_and_await_handover_cancel()); + + // Inject Handover Cancel Ack + ASSERT_TRUE(send_handover_cancel_ack()); +} diff --git a/tests/unittests/cu_cp/mobility/CMakeLists.txt b/tests/unittests/cu_cp/mobility/CMakeLists.txt index 515d5da2d6..85f71c41ab 100644 --- a/tests/unittests/cu_cp/mobility/CMakeLists.txt +++ b/tests/unittests/cu_cp/mobility/CMakeLists.txt @@ -10,8 +10,7 @@ add_library(mobility_test_helpers mobility_test_helpers.cpp ../du_processor_test target_include_directories(mobility_test_helpers PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(mobility_test_helpers srsran_cu_cp e1ap_test_helpers f1ap_test_helpers rrc_ue_test_helpers ngap_test_helpers srsran_support f1ap_asn1 srslog) -set(SOURCES inter_cu_handover_routine_test.cpp - handover_reconfiguration_routine_test.cpp) +set(SOURCES handover_reconfiguration_routine_test.cpp) add_executable(cu_cp_mobility_test ${SOURCES}) target_include_directories(cu_cp_mobility_test PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/tests/unittests/cu_cp/mobility/inter_cu_handover_routine_test.cpp b/tests/unittests/cu_cp/mobility/inter_cu_handover_routine_test.cpp deleted file mode 100644 index 3e93bb6121..0000000000 --- a/tests/unittests/cu_cp/mobility/inter_cu_handover_routine_test.cpp +++ /dev/null @@ -1,105 +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 "mobility_test_helpers.h" -#include "srsran/support/test_utils.h" -#include - -using namespace srsran; -using namespace srs_cu_cp; - -class inter_cu_handover_routine_test : public mobility_test -{ -protected: - inter_cu_handover_routine_test() {} - - /// \brief Create two DUs and attach a single UE to the first DU. - void create_dus_and_attach_ue() - { - // Test preamble to create CU-CP, attach to 5GC, attach CU-UP, create and attach DU and attach UE. - du_index_t du_index = source_du_index; - gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(0); - gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(0); - rnti_t crnti = to_rnti(0x4601); - pci_t pci = 1; - amf_ue_id_t amf_ue_id = uint_to_amf_ue_id( - test_rgen::uniform_int(amf_ue_id_to_uint(amf_ue_id_t::min), amf_ue_id_to_uint(amf_ue_id_t::max))); - ran_ue_id_t ran_ue_id = uint_to_ran_ue_id(0); - std::vector psis = {uint_to_pdu_session_id(1)}; - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id = int_to_gnb_cu_cp_ue_e1ap_id(0); - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id = int_to_gnb_cu_up_ue_e1ap_id(0); - - // Connect AMF, DU, CU-UP. - test_preamble_all_connected(du_index, pci); - - // Attach UE. - test_preamble_ue_full_attach( - du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id, psis, cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - - // Assert single UE attached to source DU. - ASSERT_EQ(get_nof_ues_in_source_du(), 1); - } - - /// \brief Inject an RRC measurement report to trigger handover. - void inject_rrc_meas_report() - { - // Inject UL RRC message containing RRC measurement report to trigger HO - f1ap_message ul_rrc_msg = - generate_ul_rrc_message_transfer(int_to_gnb_cu_ue_f1ap_id(0), - int_to_gnb_du_ue_f1ap_id(0), - srb_id_t::srb1, - make_byte_buffer("000800410004015f741fe0804bf183fcaa6e9699").value()); - test_logger.info("Injecting UL RRC message (RRC Measurement Report)"); - f1c_gw.get_du(source_du_index).on_new_message(ul_rrc_msg); - } - - du_index_t get_source_du_index() { return source_du_index; } - - ue_index_t get_source_ue() { return source_ue_index; } - - unsigned get_target_pci() const { return target_pci; } - - size_t get_nof_ues_in_source_du() const { return nof_du_ues(source_du_index); } - - void check_handover_required_was_sent_to_amf() const - { - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, - asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ho_required); - } - -private: - size_t nof_du_ues(du_index_t idx) const - { - const metrics_report report = cu_cp_obj->get_metrics_handler().request_metrics_report(); - gnb_du_id_t du_id = report.dus.at((size_t)idx).id; - return std::count_if(report.ues.begin(), report.ues.end(), [du_id](const auto& u) { return u.du_id == du_id; }); - } - - // source DU parameters. - du_index_t source_du_index = uint_to_du_index(0); - - // target DU parameters. - unsigned target_pci = 3; - - ue_index_t source_ue_index = uint_to_ue_index(0); -}; - -TEST_F(inter_cu_handover_routine_test, when_measurement_report_is_received_then_handover_required_is_send_to_amf) -{ - // Test Preamble. - create_dus_and_attach_ue(); - - // Start handover by injecting measurement report. - inject_rrc_meas_report(); - - // Check that handover required was sent to AMF. - check_handover_required_was_sent_to_amf(); -} diff --git a/tests/unittests/cu_cp/mobility/mobility_test_helpers.h b/tests/unittests/cu_cp/mobility/mobility_test_helpers.h index 4af3a2844a..1aa19fba03 100644 --- a/tests/unittests/cu_cp/mobility/mobility_test_helpers.h +++ b/tests/unittests/cu_cp/mobility/mobility_test_helpers.h @@ -10,20 +10,15 @@ #pragma once -#include "../cu_cp_test_helpers.h" -#include "lib/cu_cp/du_processor/du_processor_config.h" #include "tests/unittests/cu_cp/test_helpers.h" -#include "tests/unittests/f1ap/common/test_helpers.h" -#include "tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.h" -#include "tests/unittests/rrc/test_helpers.h" -#include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/support/executors/manual_task_worker.h" #include namespace srsran { namespace srs_cu_cp { /// Fixture class for CU-CP mobility tests -class mobility_test : public cu_cp_test +class mobility_test : public ::testing::Test { protected: mobility_test(); diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index bf734cb8fb..d497ff8690 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -1002,4 +1002,19 @@ ngap_handover_preparation_request srsran::srs_cu_cp::generate_handover_preparati } return request; -} \ No newline at end of file +} + +ngap_message srsran::srs_cu_cp::generate_handover_cancel_ack(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id) +{ + ngap_message ngap_msg; + + ngap_msg.pdu.set_successful_outcome(); + ngap_msg.pdu.successful_outcome().load_info_obj(ASN1_NGAP_ID_HO_CANCEL); + + auto& ho_cancel_ack = ngap_msg.pdu.successful_outcome().value.ho_cancel_ack(); + + ho_cancel_ack->amf_ue_ngap_id = amf_ue_id_to_uint(amf_ue_id); + ho_cancel_ack->ran_ue_ngap_id = ran_ue_id_to_uint(ran_ue_id); + + return ngap_msg; +} diff --git a/tests/unittests/ngap/ngap_test_messages.h b/tests/unittests/ngap/ngap_test_messages.h index 59a077a37b..99fb461c63 100644 --- a/tests/unittests/ngap/ngap_test_messages.h +++ b/tests/unittests/ngap/ngap_test_messages.h @@ -221,5 +221,8 @@ generate_handover_preparation_request(ue_index_t nr_cell_identity nci = nr_cell_identity::create({1, 22}, 1).value(), uint32_t gnb_id_bit_length = 22); +/// \brief Generate a valid dummy Handover Cancel Acknowledgement message. +ngap_message generate_handover_cancel_ack(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); + } // namespace srs_cu_cp } // namespace srsran From c6fad65288e0f16dfc3560bb00a43e677dbeb74d Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 23 Jul 2024 18:30:28 +0200 Subject: [PATCH 202/407] cu_cp: remove unused code --- tests/unittests/cu_cp/CMakeLists.txt | 1 - tests/unittests/cu_cp/cu_cp_test_helpers.cpp | 444 ------------------- tests/unittests/cu_cp/cu_cp_test_helpers.h | 96 ---- 3 files changed, 541 deletions(-) delete mode 100644 tests/unittests/cu_cp/cu_cp_test_helpers.cpp delete mode 100644 tests/unittests/cu_cp/cu_cp_test_helpers.h diff --git a/tests/unittests/cu_cp/CMakeLists.txt b/tests/unittests/cu_cp/CMakeLists.txt index fcd115edbe..07fad9b779 100644 --- a/tests/unittests/cu_cp/CMakeLists.txt +++ b/tests/unittests/cu_cp/CMakeLists.txt @@ -23,7 +23,6 @@ add_library(cu_cp_test_helpers test_doubles/mock_amf.cpp test_doubles/mock_du.cpp cu_cp_test_environment.cpp - cu_cp_test_helpers.cpp cu_cp_test_messages.cpp du_processor_test_messages.cpp test_helpers.cpp) diff --git a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp deleted file mode 100644 index 4e26ca47d3..0000000000 --- a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp +++ /dev/null @@ -1,444 +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_cp_test_helpers.h" -#include "srsran/asn1/f1ap/f1ap_pdu_contents.h" -#include "srsran/cu_cp/cu_cp_configuration_helpers.h" -#include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/ran/cu_types.h" -#include "srsran/support/executors/task_worker.h" -#include -#include - -using namespace srsran; -using namespace srs_cu_cp; - -namespace { - -struct amf_test_stub final : public ngap_message_handler { - amf_test_stub(ngap_message_handler& cu_cp_) : cu_cp(cu_cp_) {} - - void handle_message(const ngap_message& msg) override - { - if (is_pdu_type(msg, asn1::ngap::ngap_elem_procs_o::init_msg_c::types::ng_setup_request)) { - // Generate fake NG Setup Response. - cu_cp.handle_message(generate_ng_setup_response()); - } - } - -private: - ngap_message_handler& cu_cp; -}; - -} // namespace - -cu_cp_test::cu_cp_test() -{ - test_logger.set_level(srslog::basic_levels::debug); - cu_cp_logger.set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("NGAP").set_hex_dump_max_size(32); - srslog::fetch_basic_logger("RRC").set_hex_dump_max_size(32); - srslog::fetch_basic_logger("SEC").set_hex_dump_max_size(32); - srslog::fetch_basic_logger("PDCP").set_hex_dump_max_size(32); - srslog::init(); - - // create CU-CP config - cu_cp_configuration cfg = config_helpers::make_default_cu_cp_config(); - cfg.services.cu_cp_executor = &ctrl_worker; - cfg.services.n2_gw = &n2_gw; - cfg.services.timers = &timers; - // mobility config - cfg.mobility.mobility_manager_config.trigger_handover_from_measurements = true; - // Generate NCIs. - gnb_id_t gnb_id1 = cfg.node.gnb_id; - nr_cell_identity nci1 = nr_cell_identity::create(gnb_id1, 0).value(); - nr_cell_identity nci2 = nr_cell_identity::create(gnb_id1, 1).value(); - gnb_id_t gnb_id2 = {cfg.node.gnb_id.id + 1, cfg.node.gnb_id.bit_length}; - nr_cell_identity nci3 = nr_cell_identity::create(gnb_id2, 0).value(); - - cell_meas_config cell_cfg_1; - cell_cfg_1.periodic_report_cfg_id = uint_to_report_cfg_id(1); - cell_cfg_1.serving_cell_cfg.gnb_id_bit_length = gnb_id1.bit_length; - cell_cfg_1.serving_cell_cfg.nci = nci1; - cell_cfg_1.ncells.push_back({nci2, {uint_to_report_cfg_id(2)}}); - // Add external cell (for inter CU handover tests) - cell_cfg_1.ncells.push_back({nci3, {uint_to_report_cfg_id(2)}}); - cfg.mobility.meas_manager_config.cells.emplace(nci1, cell_cfg_1); - - cell_meas_config cell_cfg_2; - cell_cfg_2.periodic_report_cfg_id = uint_to_report_cfg_id(1); - cell_cfg_2.serving_cell_cfg.gnb_id_bit_length = gnb_id1.bit_length; - cell_cfg_2.serving_cell_cfg.nci = nci2; - cell_cfg_2.ncells.push_back({nci1, {uint_to_report_cfg_id(2)}}); - cfg.mobility.meas_manager_config.cells.emplace(nci2, cell_cfg_2); - - // Add an external cell - cell_meas_config cell_cfg_3; - cell_cfg_3.periodic_report_cfg_id = uint_to_report_cfg_id(1); - cell_cfg_3.serving_cell_cfg.gnb_id_bit_length = gnb_id2.bit_length; - cell_cfg_3.serving_cell_cfg.nci = nci3; - cell_cfg_3.serving_cell_cfg.pci = 3; - cell_cfg_3.serving_cell_cfg.ssb_arfcn = 632628; - cell_cfg_3.serving_cell_cfg.band = nr_band::n78; - cell_cfg_3.serving_cell_cfg.ssb_scs = subcarrier_spacing::kHz15; - cell_cfg_3.serving_cell_cfg.ssb_mtc = rrc_ssb_mtc{{rrc_periodicity_and_offset::periodicity_t::sf20, 0}, 5}; - - cell_cfg_3.ncells.push_back({nci1, {uint_to_report_cfg_id(2)}}); - cfg.mobility.meas_manager_config.cells.emplace(nci3, cell_cfg_3); - - // Add periodic event - rrc_report_cfg_nr periodic_report_cfg; - auto& periodical_cfg = periodic_report_cfg.periodical.emplace(); - - periodical_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; - periodical_cfg.report_interv = 1024; - periodical_cfg.report_amount = -1; - periodical_cfg.report_quant_cell.rsrp = true; - periodical_cfg.report_quant_cell.rsrq = true; - periodical_cfg.report_quant_cell.sinr = true; - periodical_cfg.max_report_cells = 4; - - periodic_report_cfg.periodical = periodical_cfg; - cfg.mobility.meas_manager_config.report_config_ids.emplace(uint_to_report_cfg_id(1), periodic_report_cfg); - - rrc_report_cfg_nr a3_report_cfg; - auto& event_trigger_cfg = a3_report_cfg.event_triggered.emplace(); - auto& event_a3 = a3_report_cfg.event_triggered.value().event_id.event_a3.emplace(); - - event_a3.a3_offset.rsrp.emplace() = 6; - event_a3.hysteresis = 0; - event_a3.time_to_trigger = 100; - - event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; - event_trigger_cfg.report_interv = 1024; - event_trigger_cfg.report_amount = -1; - event_trigger_cfg.report_quant_cell.rsrp = true; - event_trigger_cfg.report_quant_cell.rsrq = true; - event_trigger_cfg.report_quant_cell.sinr = true; - event_trigger_cfg.max_report_cells = 4; - - rrc_meas_report_quant report_quant_rs_idxes; - report_quant_rs_idxes.rsrp = true; - report_quant_rs_idxes.rsrq = true; - report_quant_rs_idxes.sinr = true; - event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - - a3_report_cfg.event_triggered = event_trigger_cfg; - cfg.mobility.meas_manager_config.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); - - // create CU-CP. - cu_cp_obj = std::make_unique(std::move(cfg)); - - // Connect CU-CP to AMF stub. - dummy_amf = std::make_unique(cu_cp_obj->get_ngap_message_handler()); - n2_gw.attach_handler(dummy_amf.get()); - - // Start CU-CP. - cu_cp_obj->start(); - - // Attach F1-C gateway to CU-CP - f1c_gw.attach_cu_cp_du_repo(cu_cp_obj->get_f1c_handler()); - - // Attach E1AP gateway to CU-CP - e1ap_gw.attach_cu_cp_cu_up_repo(cu_cp_obj->get_e1_handler()); -} - -cu_cp_test::~cu_cp_test() -{ - std::promise p; - std::future f = p.get_future(); - - // cu_cp->stop() should not be called from same execution context as of the CU-CP executor. - task_worker stop_worker{"stop_worker", 128}; - bool res = stop_worker.push_task([this, &p]() { - cu_cp_obj->stop(); - p.set_value(); - }); - report_fatal_error_if_not(res, "Task was not dispatched"); - - start_auto_tick(f); - - // flush logger after each test - srslog::flush(); -} - -void cu_cp_test::attach_ue(gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - rnti_t crnti, - du_index_t du_index) -{ - // Inject Initial UL RRC message - f1ap_message init_ul_rrc_msg = generate_init_ul_rrc_message_transfer(du_ue_id, crnti); - test_logger.info("Injecting Initial UL RRC message"); - f1c_gw.get_du(du_index).on_new_message(init_ul_rrc_msg); - - // Inject UL RRC message containing RRC Setup Complete - f1ap_message ul_rrc_msg = - generate_ul_rrc_message_transfer(cu_ue_id, du_ue_id, srb_id_t::srb1, generate_rrc_setup_complete()); - test_logger.info("Injecting UL RRC message (RRC Setup Complete)"); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg); -} - -void cu_cp_test::authenticate_ue(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id) -{ - // Inject NGAP DL message (authentication request) - ngap_message dl_nas_transport = generate_downlink_nas_transport_message(amf_ue_id, ran_ue_id); - cu_cp_obj->get_ngap_message_handler().handle_message(dl_nas_transport); - - // Inject UL RRC msg transfer (authentication response) - f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, - du_ue_id, - srb_id_t::srb1, - make_byte_buffer("00013a0abf002b96882dac46355c4f34464ddaf7b43fde37ae8000000000").value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); - - // Inject DL NAS Transport message (ue security mode command) - dl_nas_transport = generate_downlink_nas_transport_message(amf_ue_id, ran_ue_id); - cu_cp_obj->get_ngap_message_handler().handle_message(dl_nas_transport); - - // Inject UL RRC msg transfer (ue security mode complete) - ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, - du_ue_id, - srb_id_t::srb1, - make_byte_buffer("00023a1cbf0243241cb5003f002f3b80048290a1b283800000f8b880103f0020bc800680807888787f800008192a3b4" - "c080080170170700c0080a980808000000000") - .value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); -} - -void cu_cp_test::setup_security(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id) -{ - // Inject Initial Context Setup Request - ngap_message init_ctxt_setup_req = generate_valid_initial_context_setup_request_message(amf_ue_id, ran_ue_id); - cu_cp_obj->get_ngap_message_handler().handle_message(init_ctxt_setup_req); - - // Inject UE Context Setup Response - f1ap_message ue_ctxt_setup_response = generate_ue_context_setup_response(cu_ue_id, du_ue_id); - f1c_gw.get_du(du_index).on_new_message(ue_ctxt_setup_response); - - // Inject Security Mode Complete - f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, du_ue_id, srb_id_t::srb1, make_byte_buffer("00032a00fd5ec7ff").value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); - - // Inject UE capability info - ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, - du_ue_id, - srb_id_t::srb1, - make_byte_buffer("00044c821930680ce811d1968097e360e1480005824c5c00060fc2c00637fe002e00131401a0000000880058d006007" - "a071e439f0000240400e0300000000100186c0000700809df000000000000030368000800004b2ca000a07143c001c0" - "03c000000100200409028098a8660c") - .value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); -} - -void cu_cp_test::test_amf_connection() -{ - // Connect AMF by injecting a ng_setup_response - ngap_message ngap_msg = generate_ng_setup_response(); - cu_cp_obj->get_ngap_message_handler().handle_message(ngap_msg); - - ASSERT_TRUE(cu_cp_obj->amf_is_connected()); -} - -void cu_cp_test::test_e1ap_attach() -{ - // Create a new CU-UP connection to the CU-CP, creating a new CU-UP processor in the CU-CP in the process. - e1ap_gw.request_new_cu_up_connection(); - ASSERT_EQ(e1ap_gw.nof_connections(), 1U); - - // Pass E1SetupRequest to the CU-CP - e1ap_message e1setup_msg = generate_valid_cu_up_e1_setup_request(); - e1ap_gw.get_cu_up(0).on_new_message(e1setup_msg); -} - -void cu_cp_test::test_du_attach(du_index_t du_index, gnb_du_id_t gnb_du_id, nr_cell_identity nrcell_id, pci_t pci) -{ - // Store current number of DUs. - size_t nof_dus = f1c_gw.nof_connections(); - - // Create a new DU connection to the CU-CP, creating a new DU processor in the CU-CP in the process. - f1c_gw.request_new_du_connection(); - - size_t expected_nof_dus = nof_dus + 1; - ASSERT_EQ(f1c_gw.nof_connections(), expected_nof_dus); - - // Pass F1SetupRequest to the CU-CP - f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(gnb_du_id, nrcell_id, pci); - f1c_gw.get_du(du_index).on_new_message(f1setup_msg); -} - -void cu_cp_test::add_pdu_sessions(std::vector psis, - du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id) -{ - bool initial_pdu_session = true; - - for (const auto psi : psis) { - // Inject PDU Session Resource Setup Request - ngap_message pdu_session_resource_setup_request = generate_valid_pdu_session_resource_setup_request_message( - amf_ue_id, ran_ue_id, {{psi, {{uint_to_qos_flow_id(1), 9}}}}); - cu_cp_obj->get_ngap_message_handler().handle_message(pdu_session_resource_setup_request); - - if (initial_pdu_session) { - initial_pdu_session = false; - - // check that the Bearer Context Setup was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_setup_request); - - // Inject Bearer Context Setup Response - e1ap_message bearer_context_setup_resp = - generate_bearer_context_setup_response(cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - e1ap_gw.get_cu_up(0).on_new_message(bearer_context_setup_resp); - } else { - // check that the Bearer Context Modification was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_mod_request); - // Inject Bearer Context Modification Response - e1ap_message bearer_context_mod_resp = - generate_bearer_context_modification_response(cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - e1ap_gw.get_cu_up(0).on_new_message(bearer_context_mod_resp); - } - - // check that the UE Context Modification Request was sent to the DU - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ue_context_mod_request); - - // Inject UE Context Modification Response - f1ap_message ue_context_mod_resp = generate_ue_context_modification_response(cu_ue_id, du_ue_id); - f1c_gw.get_du(du_index).on_new_message(ue_context_mod_resp); - - // check that the Bearer Context Modification was sent to the CU-UP - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.type(), asn1::e1ap::e1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(e1ap_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::e1ap::e1ap_elem_procs_o::init_msg_c::types_opts::bearer_context_mod_request); - - // check that the UE Context Modification Request contains the UE capabilities - ASSERT_TRUE(f1c_gw.last_tx_pdus(0).back().pdu.init_msg().value.ue_context_mod_request()->cu_to_du_rrc_info_present); - ASSERT_NE(f1c_gw.last_tx_pdus(0) - .back() - .pdu.init_msg() - .value.ue_context_mod_request() - ->cu_to_du_rrc_info.ue_cap_rat_container_list.size(), - 0U); - - // Inject Bearer Context Modification Response - e1ap_message bearer_context_mod_resp = - generate_bearer_context_modification_response(cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); - e1ap_gw.get_cu_up(0).on_new_message(bearer_context_mod_resp); - - // check that the RRC Reconfiguration was sent to the DU - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.type(), asn1::f1ap::f1ap_pdu_c::types_opts::options::init_msg); - ASSERT_EQ(f1c_gw.last_tx_pdus(0).back().pdu.init_msg().value.type().value, - asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::dl_rrc_msg_transfer); - - // Inject RRC Reconfiguration Complete - f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, du_ue_id, srb_id_t::srb1, make_byte_buffer("00070e00cc6fcda5").value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); - - // check that the PDU Session Resource Setup Response was sent to the AMF - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type(), asn1::ngap::ngap_pdu_c::types_opts::options::successful_outcome); - ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.successful_outcome().value.type().value, - asn1::ngap::ngap_elem_procs_o::successful_outcome_c::types_opts::pdu_session_res_setup_resp); - } -} - -void cu_cp_test::test_preamble_all_connected(du_index_t du_index, pci_t pci) -{ - test_amf_connection(); - - test_e1ap_attach(); - - test_du_attach(du_index, int_to_gnb_du_id(0x11), nr_cell_identity::create(gnb_id_t{411, 22}, 0).value(), pci); -} - -void cu_cp_test::test_preamble_ue_creation(du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - rnti_t crnti, - amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id) -{ - // Attach UE - attach_ue(du_ue_id, cu_ue_id, crnti, du_index); - ASSERT_EQ(cu_cp_obj->get_metrics_handler().request_metrics_report().ues.size(), 1); - - authenticate_ue(amf_ue_id, ran_ue_id, du_index, du_ue_id, cu_ue_id); - - setup_security(amf_ue_id, ran_ue_id, du_index, du_ue_id, cu_ue_id); -} - -void cu_cp_test::test_preamble_ue_full_attach(du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - rnti_t crnti, - amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - std::vector psis_to_setup, - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id) -{ - // Create UE - test_preamble_ue_creation(du_index, du_ue_id, cu_ue_id, crnti, amf_ue_id, ran_ue_id); - - // Inject Registration Complete - f1ap_message ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, du_ue_id, srb_id_t::srb1, make_byte_buffer("00053a053f015362c51680bf00218086b09a5b").value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); - - // Inject PDU Session Establishment Request - ul_rrc_msg_transfer = generate_ul_rrc_message_transfer( - cu_ue_id, - du_ue_id, - srb_id_t::srb1, - make_byte_buffer("00063a253f011ffa9203013f0033808018970080e0ffffc9d8bd8013404010880080000840830000000041830000000" - "00000800001800005000006000006800008800900c092838339b939b0b83700e03a21bb") - .value()); - f1c_gw.get_du(du_index).on_new_message(ul_rrc_msg_transfer); - - // Inject Configuration Update Command - ngap_message dl_nas_transport_msg = generate_downlink_nas_transport_message( - amf_ue_id, - ran_ue_id, - make_byte_buffer("7e0205545bfc027e0054430f90004f00700065006e00350047005346004732800131235200490100").value()); - cu_cp_obj->get_ngap_message_handler().handle_message(dl_nas_transport_msg); - - add_pdu_sessions( - std::move(psis_to_setup), du_index, du_ue_id, cu_ue_id, amf_ue_id, ran_ue_id, cu_cp_ue_e1ap_id, cu_up_ue_e1ap_id); -} - -void cu_cp_test::start_auto_tick(const std::future& stop_signal) -{ - do { - timers.tick(); - ctrl_worker.run_pending_tasks(); - } while (stop_signal.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready); -} diff --git a/tests/unittests/cu_cp/cu_cp_test_helpers.h b/tests/unittests/cu_cp/cu_cp_test_helpers.h deleted file mode 100644 index cc16cbe34b..0000000000 --- a/tests/unittests/cu_cp/cu_cp_test_helpers.h +++ /dev/null @@ -1,96 +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 "lib/cu_cp/cu_cp_impl.h" -#include "test_helpers.h" -#include "tests/unittests/e1ap/common/test_helpers.h" -#include "tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h" -#include "tests/unittests/f1ap/common/test_helpers.h" -#include "tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.h" -#include "tests/unittests/ngap/test_helpers.h" -#include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/support/executors/manual_task_worker.h" -#include - -namespace srsran { -namespace srs_cu_cp { - -/// Fixture class for CU-CP test -class cu_cp_test : public ::testing::Test -{ -protected: - cu_cp_test(); - ~cu_cp_test() override; - - void test_amf_connection(); - - void test_e1ap_attach(); - void test_du_attach(du_index_t du_index, gnb_du_id_t gnb_du_id, nr_cell_identity nrcell_id, pci_t pci); - - void add_pdu_sessions(std::vector psis, - du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id); - - void attach_ue(gnb_du_ue_f1ap_id_t du_ue_id, gnb_cu_ue_f1ap_id_t cu_ue_id, rnti_t crnti, du_index_t du_index); - void authenticate_ue(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id); - void setup_security(amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id); - void test_preamble_all_connected(du_index_t du_index, pci_t pci); - void test_preamble_ue_creation(du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - rnti_t crnti, - amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id); - void test_preamble_ue_full_attach(du_index_t du_index, - gnb_du_ue_f1ap_id_t du_ue_id, - gnb_cu_ue_f1ap_id_t cu_ue_id, - rnti_t crnti, - amf_ue_id_t amf_ue_id, - ran_ue_id_t ran_ue_id, - std::vector psis_to_setup, - gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, - gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id); - bool check_minimal_paging_result(); - bool check_paging_result(); - - void start_auto_tick(const std::future& stop_signal); - - srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); - srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP"); - - timer_manager timers{256}; - manual_task_worker ctrl_worker{128}; - - std::unique_ptr dummy_amf; - - std::unique_ptr cu_cp_obj; - - dummy_n2_gateway n2_gw; - dummy_cu_cp_f1c_gateway f1c_gw; - dummy_cu_cp_e1ap_gateway e1ap_gw; -}; - -} // namespace srs_cu_cp -} // namespace srsran From 456bef0c49ed6a2fc9b4bb7c466bb62bd5f3dcd9 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 12 Aug 2024 16:01:46 +0200 Subject: [PATCH 203/407] cu_cp,ngap: add handling of handover preparation failure --- lib/ngap/procedures/ngap_handover_preparation_procedure.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp index a921b8400e..f8ba07236d 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp @@ -81,6 +81,11 @@ void ngap_handover_preparation_procedure::operator()(coro_context Date: Mon, 12 Aug 2024 16:02:11 +0200 Subject: [PATCH 204/407] cu_cp,ngap: add unit test for handover preparation failure --- .../cu_cp/cu_cp_inter_cu_handover_test.cpp | 23 +++++++++++++++++++ tests/unittests/ngap/ngap_test_messages.cpp | 18 +++++++++++++++ tests/unittests/ngap/ngap_test_messages.h | 3 +++ 3 files changed, 44 insertions(+) diff --git a/tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp index dcb1f3dbc7..1b38137936 100644 --- a/tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_inter_cu_handover_test.cpp @@ -136,6 +136,13 @@ class cu_cp_inter_cu_handover_test : public cu_cp_test_environment, public ::tes return true; } + [[nodiscard]] bool send_handover_preparation_failure() + { + // Inject Handover Preparation Failure + get_amf().push_tx_pdu(generate_handover_preparation_failure(ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value())); + return true; + } + [[nodiscard]] bool timeout_handover_command_and_await_handover_cancel() { // Fail Handover Preparation (AMF doesn't respond) and await Handover Cancel @@ -193,6 +200,22 @@ TEST_F(cu_cp_inter_cu_handover_test, when_handover_request_received_then_handove ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_handover_notify()); } +TEST_F(cu_cp_inter_cu_handover_test, when_handover_preparation_failure_is_received_then_handover_fails) +{ + // Attach UE + ASSERT_TRUE(attach_ue()); + + // Inject RRC Measurement Report and await Handover Required + ASSERT_TRUE(send_rrc_measurement_report_and_await_handover_required()); + + // Inject Handover Preparation Failure + ASSERT_TRUE(send_handover_preparation_failure()); + + // STATUS: Handover Preparation failed and no further messages are sent to the AMF + report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), + "there are still NGAP messages to pop from AMF"); +} + TEST_F(cu_cp_inter_cu_handover_test, when_handover_command_times_out_then_handover_cancel_is_sent) { // Attach UE diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index d497ff8690..aa5671fd61 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -935,6 +935,24 @@ ngap_message srsran::srs_cu_cp::generate_valid_handover_request(amf_ue_id_t amf_ return ngap_msg; } +ngap_message srsran::srs_cu_cp::generate_handover_preparation_failure(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id) +{ + ngap_message ngap_msg; + + ngap_msg.pdu.set_unsuccessful_outcome(); + ngap_msg.pdu.unsuccessful_outcome().load_info_obj(ASN1_NGAP_ID_HO_PREP); + + auto& ho_prep_fail = ngap_msg.pdu.unsuccessful_outcome().value.ho_prep_fail(); + + ho_prep_fail->amf_ue_ngap_id = amf_ue_id_to_uint(amf_ue_id); + ho_prep_fail->ran_ue_ngap_id = ran_ue_id_to_uint(ran_ue_id); + + // cause + ho_prep_fail->cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::options::unspecified; + + return ngap_msg; +} + ngap_message srsran::srs_cu_cp::generate_valid_handover_command(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id) { ngap_message ngap_msg; diff --git a/tests/unittests/ngap/ngap_test_messages.h b/tests/unittests/ngap/ngap_test_messages.h index 99fb461c63..fea48188ef 100644 --- a/tests/unittests/ngap/ngap_test_messages.h +++ b/tests/unittests/ngap/ngap_test_messages.h @@ -211,6 +211,9 @@ ngap_message generate_error_indication_message(amf_ue_id_t amf_ue_id, ran_ue_id_ /// \brief Generate a valid dummy Handover Request message. ngap_message generate_valid_handover_request(amf_ue_id_t amf_ue_id); +/// \brief Generate a valid dummy Handover Preparation Failure message. +ngap_message generate_handover_preparation_failure(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); + /// \brief Generate a valid dummy Handover Command message. ngap_message generate_valid_handover_command(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); From 03deec41d51557ece9616ac236218ef01aa3e632 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 9 Aug 2024 11:22:56 +0200 Subject: [PATCH 205/407] du: fix comment in config validator Signed-off-by: Carlo Galiotto --- include/srsran/du/du_cell_config.h | 2 +- tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index 8432d79dc2..b833d95023 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -73,7 +73,7 @@ struct pucch_builder_params { /// UE specific parameters. Use to set the number of resources per UE for HARQ-ACK reporting (not including SR/CSI /// dedicated resources). NOTE: by default, each UE is assigned 1 SR and 1 CSI resource. /// \remark Format 0 and Format 1 resources are mutually exclusive. - bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 3; + bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 7; bounded_integer nof_ue_pucch_f2_res_harq = 6; /// \brief Number of separate PUCCH resource sets for HARQ-ACK reporting that are available in a cell. /// \remark UEs will be distributed possibly over different HARQ-ACK PUCCH sets; the more sets, the fewer UEs will diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 178fe76e3d..7c2c590d08 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -193,6 +193,7 @@ test_bench::test_bench(const test_bench_params& params, if (use_format_0) { pucch_builder_params pucch_params{}; + pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 3; pucch_params.f0_or_f1_params.emplace(); pucch_builder.setup( cell_cfg.ul_cfg_common.init_ul_bwp, params.is_tdd ? cell_cfg.tdd_cfg_common : std::nullopt, pucch_params); From cddb607c2203ab309fdc6fc4e1825bbc88c40756 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 12 Jul 2024 19:47:55 +0200 Subject: [PATCH 206/407] du: change builder for pucch_cfg for UEs with F0 Signed-off-by: Carlo Galiotto --- .../du_pucch_resource_manager.cpp | 60 +++- .../du_pucch_resource_manager.h | 6 + .../pucch_resource_generator.cpp | 96 ++++-- .../config/serving_cell_config_validator.cpp | 10 +- .../pucch_scheduling/pucch_allocator_impl.cpp | 207 +++++++------ .../pucch_scheduling/pucch_allocator_impl.h | 6 +- .../pucch_resource_manager.cpp | 53 +++- .../du_ran_resource_manager_test.cpp | 142 +++++++++ .../pucch_resource_generator_test.cpp | 72 +++-- .../pucch_alloc_harq_sr_csi_test.cpp | 283 ++++++++---------- .../uci_and_pucch/uci_test_utils.cpp | 3 +- 11 files changed, 625 insertions(+), 313 deletions(-) diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index 6e98b88fa0..df2bbc87bd 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -135,6 +135,7 @@ std::vector>::const_iterator du_pucch_resource_manager::find_optimal_csi_report_slot_offset( const std::vector>& available_csi_slot_offsets, unsigned candidate_sr_offset, + const pucch_resource& sr_res_cfg, const csi_meas_config& csi_meas_cfg) { // [Implementation-defined] Given that it takes some time for a UE to process a CSI-RS and integrate its estimate @@ -151,21 +152,40 @@ du_pucch_resource_manager::find_optimal_csi_report_slot_offset( const unsigned csi_rs_period = csi_resource_periodicity_to_uint(*csi_res.csi_res_period); const unsigned csi_rs_offset = *csi_res.csi_res_offset; - const auto weight_function = [&](unsigned offset_candidate) -> unsigned { + const auto weight_function = [&](std::pair csi_res_offset_candidate) -> unsigned { // This weight formula prioritizes offsets equal or after the \c csi_rs_slot_offset + // MINIMUM_CSI_RS_REPORT_DISTANCE. unsigned weight = - (csi_rs_period + offset_candidate - csi_rs_offset - MINIMUM_CSI_RS_REPORT_DISTANCE) % csi_rs_period; + (csi_rs_period + csi_res_offset_candidate.second - csi_rs_offset - MINIMUM_CSI_RS_REPORT_DISTANCE) % + csi_rs_period; + + if (sr_res_cfg.format == pucch_format::FORMAT_0) { + const pucch_resource& candidate_csi_res_cfg = + default_pucch_res_list[csi_du_res_idx_to_pucch_res_idx(csi_res_offset_candidate.first)]; + srsran_assert(std::holds_alternative(candidate_csi_res_cfg.format_params), + "PUCCH resource for CSI must be of format 2 or 3"); + const ofdm_symbol_range csi_symbols = { + std::get(candidate_csi_res_cfg.format_params).starting_sym_idx, + std::get(candidate_csi_res_cfg.format_params).starting_sym_idx + + std::get(candidate_csi_res_cfg.format_params).nof_symbols}; + const ofdm_symbol_range sr_symbols = {std::get(sr_res_cfg.format_params).starting_sym_idx, + std::get(sr_res_cfg.format_params).starting_sym_idx + + std::get(sr_res_cfg.format_params).nof_symbols}; + if (not csi_symbols.overlaps(sr_symbols)) { + weight += 2 * csi_rs_period; + return weight; + } + } // We increase the weight if the CSI report offset collides with an SR slot offset. - if (csi_offset_collides_with_sr(candidate_sr_offset, offset_candidate)) { + if (csi_offset_collides_with_sr(candidate_sr_offset, csi_res_offset_candidate.second)) { weight += csi_rs_period; } // If the CSI offset exceeds the maximum number of PUCCH grants, we increase by 2 * csi_rs_period, to ensure this // gets picked as the last resort (the highest possible weight for a CSI colliding with SR // is = 2 * csi_rs_period - 1). - if (csi_offset_exceeds_grant_cnt(offset_candidate, + if (csi_offset_exceeds_grant_cnt(csi_res_offset_candidate.second, max_pucch_grants_per_slot, lcm_csi_sr_period, csi_period_slots, @@ -180,7 +200,7 @@ du_pucch_resource_manager::find_optimal_csi_report_slot_offset( available_csi_slot_offsets.begin(), available_csi_slot_offsets.end(), [&weight_function](const std::pair& lhs, const std::pair& rhs) { - return weight_function(lhs.second) < weight_function(rhs.second); + return weight_function(lhs) < weight_function(rhs); }); return csi_offset_exceeds_grant_cnt(optimal_res_it->second, @@ -227,10 +247,13 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) free_sr_list.erase(sr_res_offset_it); break; } + + const pucch_resource sr_res = default_pucch_res_list[sr_du_res_idx_to_pucch_res_idx(sr_res_offset_it->first)]; + cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list = {*default_csi_report_cfg}; auto optimal_res_it = get_csi_resource_offset( - cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg.value(), sr_res_offset_it->second, free_csi_list); + cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg.value(), sr_res_offset_it->second, sr_res, free_csi_list); if (optimal_res_it != free_csi_list.end()) { // At this point the allocation has been successful. Remove SR and CSI resources assigned to this UE from the @@ -324,10 +347,12 @@ void du_pucch_resource_manager::dealloc_resources(cell_group_config& cell_grp_cf std::vector>::const_iterator du_pucch_resource_manager::get_csi_resource_offset(const csi_meas_config& csi_meas_cfg, unsigned candidate_sr_offset, + const pucch_resource& sr_res_cfg, const std::vector>& free_csi_list) { // Chosse the optimal CSI-RS slot offset. - auto optimal_res_it = find_optimal_csi_report_slot_offset(free_csi_list, candidate_sr_offset, csi_meas_cfg); + auto optimal_res_it = + find_optimal_csi_report_slot_offset(free_csi_list, candidate_sr_offset, sr_res_cfg, csi_meas_cfg); if (optimal_res_it != free_csi_list.end()) { // Set temporarily CSI report with a default PUCCH_res_id. @@ -385,6 +410,15 @@ bool du_pucch_resource_manager::csi_offset_collides_with_sr(unsigned sr_offset, return false; } +unsigned du_pucch_resource_manager::sr_du_res_idx_to_pucch_res_idx(unsigned sr_du_res_idx) const +{ + // The mapping from the UE's PUCCH-Config \ref res_id index to the DU index for PUCCH SR resource is the inverse of + // what is defined in \ref srs_du::ue_pucch_config_builder. + return user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * + user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + + sr_du_res_idx; +} + unsigned du_pucch_resource_manager::pucch_res_idx_to_sr_du_res_idx(unsigned pucch_res_idx) const { // The mapping from the UE's PUCCH-Config \ref res_id index to the DU index for PUCCH SR resource is the inverse of @@ -393,6 +427,18 @@ unsigned du_pucch_resource_manager::pucch_res_idx_to_sr_du_res_idx(unsigned pucc user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets; } +unsigned du_pucch_resource_manager::csi_du_res_idx_to_pucch_res_idx(unsigned csi_du_res_idx) const +{ + // The mapping from the UE's PUCCH-Config \ref res_id index to the DU index for PUCCH CSI resource is the inverse of + // what is defined in \ref srs_du::ue_pucch_config_builder. + return user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * + user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + + user_defined_pucch_cfg.nof_sr_resources + + user_defined_pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() * + user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + + csi_du_res_idx; +} + unsigned du_pucch_resource_manager::pucch_res_idx_to_csi_du_res_idx(unsigned pucch_res_idx) const { // The mapping from the UE's PUCCH-Config \ref res_id index to the DU index for PUCCH CSI resource is the inverse of diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h index 64b47ccc09..eb6fd38284 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h @@ -37,6 +37,8 @@ class du_pucch_resource_manager void dealloc_resources(cell_group_config& cell_grp_cfg); private: + unsigned sr_du_res_idx_to_pucch_res_idx(unsigned sr_du_res_idx) const; + /// \brief Computes the DU index for PUCCH SR resource from the UE's PUCCH-Config \ref res_id index. /// /// Each cell has nof_cell_pucch_f1_res_sr PUCCH Format 1 resources that can be used for SR. Within the DU, these @@ -45,6 +47,8 @@ class du_pucch_resource_manager /// index and the UE's PUCCH-Config for SR PUCCH resources is defined in \ref srs_du::ue_pucch_config_builder. unsigned pucch_res_idx_to_sr_du_res_idx(unsigned pucch_res_idx) const; + unsigned csi_du_res_idx_to_pucch_res_idx(unsigned csi_du_res_idx) const; + /// \brief Computes the DU index for PUCCH CSI resource from the UE's PUCCH-Config \ref res_id index. /// /// Each cell has nof_cell_pucch_f2_res_csi PUCCH Format 2 resources that can be used for CSI. Within the DU, these @@ -56,6 +60,7 @@ class du_pucch_resource_manager std::vector>::const_iterator find_optimal_csi_report_slot_offset(const std::vector>& available_csi_slot_offsets, unsigned candidate_sr_offset, + const pucch_resource& sr_res_cfg, const csi_meas_config& csi_meas_cfg); /// Computes the CSI resource ID and offset, under the following constraints: (i) the PUCCH grants counter doesn't @@ -64,6 +69,7 @@ class du_pucch_resource_manager std::vector>::const_iterator get_csi_resource_offset(const csi_meas_config& csi_meas_cfg, unsigned candidate_sr_offset, + const pucch_resource& sr_res_cfg, const std::vector>& free_csi_list); /// Computes the SR and CSI PUCCH offsets and their repetitions within a given period, which is the Least Common diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp index e60b5a7326..991284ebff 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -600,7 +600,7 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned } static unsigned cell_res_list_validator(const std::vector& res_list, - bounded_integer nof_ue_pucch_f1_res_harq, + bounded_integer nof_ue_pucch_f0_f1_res_harq, bounded_integer nof_ue_pucch_f2_res_harq, unsigned nof_harq_pucch_cfgs, unsigned nof_cell_pucch_f1_res_sr, @@ -618,6 +618,10 @@ static unsigned cell_res_list_validator(const std::vector& return cnt; }; + const auto contain_format_0 = std::find_if(res_list.begin(), res_list.end(), [](const pucch_resource& res) { + return res.format == pucch_format::FORMAT_0; + }) != res_list.end(); + const unsigned tot_nof_f0_res = count_resources(pucch_format::FORMAT_0); const unsigned tot_nof_f1_res = count_resources(pucch_format::FORMAT_1); const unsigned tot_nof_f2_res = count_resources(pucch_format::FORMAT_2); @@ -635,19 +639,26 @@ static unsigned cell_res_list_validator(const std::vector& return FAILURE_CASE; } - if (tot_nof_f0_f1_res < 2 or tot_nof_f2_res < 2) { - srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2 PUCCH resources."); - return FAILURE_CASE; + if (contain_format_0) { + if (tot_nof_f0_f1_res < 3 or tot_nof_f2_res < 2) { + srsran_assertion_failure("The cell PUCCH resource list must contain at least 3 F0/F1 and 2 F2 PUCCH resources."); + return FAILURE_CASE; + } + } else { + if (tot_nof_f0_f1_res < 2 or tot_nof_f2_res < 2) { + srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2 PUCCH resources."); + return FAILURE_CASE; + } } - if (nof_ue_pucch_f1_res_harq.to_uint() > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr or + if (nof_ue_pucch_f0_f1_res_harq.to_uint() > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr or nof_ue_pucch_f2_res_harq.to_uint() > tot_nof_f2_res - nof_cell_pucch_f2_res_csi) { srsran_assertion_failure( "The nof requested UE PUCCH resources is greater than the nof of resources available in the cell."); return FAILURE_CASE; } - if ((nof_ue_pucch_f1_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr) or + if ((nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr) or (nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f2_res - nof_cell_pucch_f2_res_csi)) { srsran_assertion_failure( "The cell PUCCH resource list doesn't contain enough resources to allocate all requested UEs."); @@ -704,9 +715,9 @@ bool srsran::srs_du::ue_pucch_config_builder( pucch_res_set_idx::set_1; // Add F1 for HARQ. - const unsigned f1_idx_offset = (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq.to_uint(); + const unsigned f0_f1_idx_offset = (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq.to_uint(); for (unsigned ue_f1_cnt = 0; ue_f1_cnt < nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f1_cnt) { - const auto& cell_res = res_list[ue_f1_cnt + f1_idx_offset]; + const auto& cell_res = res_list[ue_f1_cnt + f0_f1_idx_offset]; // Add PUCCH resource to pucch_res_list. pucch_cfg.pucch_res_list.emplace_back(pucch_resource{.res_id = {cell_res.res_id.cell_res_id, ue_pucch_res_id}, @@ -724,18 +735,34 @@ bool srsran::srs_du::ue_pucch_config_builder( } // Add SR resource. - const unsigned sr_res_idx = - nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_sets + (du_sr_res_idx % nof_cell_pucch_f0_f1_res_sr); - const auto& sr_cell_res = res_list[sr_res_idx]; - pucch_cfg.pucch_res_list.emplace_back(pucch_resource{.res_id = {sr_cell_res.res_id.cell_res_id, ue_pucch_res_id}, - .starting_prb = sr_cell_res.starting_prb, - .second_hop_prb = sr_cell_res.second_hop_prb, - .format = sr_cell_res.format, - .format_params = sr_cell_res.format_params}); - pucch_cfg.sr_res_list.front().pucch_res_id = pucch_res_id_t{sr_cell_res.res_id.cell_res_id, ue_pucch_res_id}; + const unsigned sr_res_idx = nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_sets + (du_sr_res_idx); + const auto& sr_cell_res = res_list[sr_res_idx]; + const unsigned ue_pucch_res_id_for_sr = ue_pucch_res_id; + pucch_cfg.pucch_res_list.emplace_back( + pucch_resource{.res_id = {sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}, + .starting_prb = sr_cell_res.starting_prb, + .second_hop_prb = sr_cell_res.second_hop_prb, + .format = sr_cell_res.format, + .format_params = sr_cell_res.format_params}); + pucch_cfg.sr_res_list.front().pucch_res_id = pucch_res_id_t{sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}; // Increment the PUCCH resource ID for ASN1 message. ++ue_pucch_res_id; + // For Format 0, copy maps the last resource of the set 0 to the SR resource. + const bool is_format_0 = res_list[f0_f1_idx_offset].format == pucch_format::FORMAT_0; + if (is_format_0) { + const unsigned last_harq_res_set_0_idx = nof_ue_pucch_f0_f1_res_harq.to_uint() - 1U; + auto& last_harq_res_set_0 = pucch_cfg.pucch_res_list[last_harq_res_set_0_idx]; + last_harq_res_set_0.res_id.cell_res_id = sr_cell_res.res_id.cell_res_id; + last_harq_res_set_0.res_id.ue_res_id = ue_pucch_res_id_for_sr; + last_harq_res_set_0.starting_prb = sr_cell_res.starting_prb; + last_harq_res_set_0.second_hop_prb = sr_cell_res.second_hop_prb; + last_harq_res_set_0.format = sr_cell_res.format; + last_harq_res_set_0.format_params = sr_cell_res.format_params; + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)] + .pucch_res_id_list[last_harq_res_set_0_idx] = {sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}; + } + // Add F2 for HARQ. const unsigned f2_idx_offset = tot_nof_cell_f0_f1_res + (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_res_harq.to_uint(); @@ -756,20 +783,37 @@ bool srsran::srs_du::ue_pucch_config_builder( if (serv_cell_cfg.csi_meas_cfg.has_value()) { // Add CSI resource. - const unsigned csi_res_idx = tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_sets + - (du_csi_res_idx % nof_cell_pucch_f2_res_csi); - const auto& csi_cell_res = res_list[csi_res_idx]; - pucch_cfg.pucch_res_list.emplace_back(pucch_resource{.res_id = {csi_cell_res.res_id.cell_res_id, ue_pucch_res_id}, - .starting_prb = csi_cell_res.starting_prb, - .second_hop_prb = csi_cell_res.second_hop_prb, - .format = csi_cell_res.format, - .format_params = csi_cell_res.format_params}); + const unsigned csi_res_idx = + tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_sets + (du_csi_res_idx); + const auto& csi_cell_res = res_list[csi_res_idx]; + const unsigned ue_pucch_res_id_for_csi = ue_pucch_res_id; + pucch_cfg.pucch_res_list.emplace_back( + pucch_resource{.res_id = {csi_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_csi}, + .starting_prb = csi_cell_res.starting_prb, + .second_hop_prb = csi_cell_res.second_hop_prb, + .format = csi_cell_res.format, + .format_params = csi_cell_res.format_params}); std::get( serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list[0].report_cfg_type) .pucch_csi_res_list.front() - .pucch_res_id = {csi_cell_res.res_id.cell_res_id, ue_pucch_res_id}; + .pucch_res_id = {csi_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_csi}; // Increment the PUCCH resource ID for ASN1 message. ++ue_pucch_res_id; + + if (is_format_0) { + const unsigned last_harq_res_set_1_idx = + nof_ue_pucch_f0_f1_res_harq.to_uint() + 1U + nof_ue_pucch_f2_res_harq.to_uint() - 1U; + auto& last_harq_res_set_1 = pucch_cfg.pucch_res_list[last_harq_res_set_1_idx]; + last_harq_res_set_1.res_id.cell_res_id = csi_cell_res.res_id.cell_res_id; + last_harq_res_set_1.res_id.ue_res_id = ue_pucch_res_id_for_csi; + last_harq_res_set_1.starting_prb = csi_cell_res.starting_prb; + last_harq_res_set_1.second_hop_prb = csi_cell_res.second_hop_prb; + last_harq_res_set_1.format = csi_cell_res.format; + last_harq_res_set_1.format_params = csi_cell_res.format_params; + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)] + .pucch_res_id_list[nof_ue_pucch_f2_res_harq.to_uint() - 1U] = {csi_cell_res.res_id.cell_res_id, + ue_pucch_res_id_for_csi}; + } } return true; diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index 850e69bb1e..047a63a579 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -148,10 +148,6 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel [res_id](const pucch_resource& res) { return res.res_id.cell_res_id == res_id; }); }; - // NOTE: No need to check this for Format 0, as this struct doesn't exist for F0. - VERIFY(pucch_cfg.format_1_common_param.has_value(), "Missing PUCCH-format1 parameters in PUCCH-Config"); - VERIFY(pucch_cfg.format_2_common_param.has_value(), "Missing PUCCH-format2 parameters in PUCCH-Config"); - // Verify that the PUCCH resources IDs of each PUCCH resource set point at a corresponding item in the PUCCH reource // list. VERIFY(pucch_cfg.pucch_res_set.size() >= 2, "At least 2 PUCCH resource sets need to be configured in PUCCH-Config"); @@ -205,6 +201,12 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(not(has_format_0 and has_format_1), "Only PUCCH Format 0 or Format 1 can be configured in a UE configuration, not both."); + // NOTE: No need to check this for Format 0, as this struct doesn't exist for F0. + if (has_format_1) { + VERIFY(pucch_cfg.format_1_common_param.has_value(), "Missing PUCCH-format1 parameters in PUCCH-Config"); + } + VERIFY(pucch_cfg.format_2_common_param.has_value(), "Missing PUCCH-format2 parameters in PUCCH-Config"); + // Check PUCCH Formats for each PUCCH Resource Set. for (auto res_idx : pucch_cfg.pucch_res_set[0].pucch_res_id_list) { const auto* pucch_res_it = get_pucch_resource_with_id(res_idx.cell_res_id); diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 213567bd63..60778a5e11 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -302,9 +302,9 @@ std::optional pucch_allocator_impl::alloc_ded_pucch_harq_ack_ue(cell_r std::optional pucch_res_ind = is_multiplexing_needed - ? multiplex_and_allocate_pucch(pucch_slot_alloc, new_bits, *existing_grant_it, ue_cell_cfg) + ? multiplex_and_allocate_pucch(pucch_slot_alloc, new_bits, *existing_grant_it, ue_cell_cfg, std::nullopt) : allocate_without_multiplexing(pucch_slot_alloc, new_bits, *existing_grant_it, ue_cell_cfg); - ; + if (not pucch_res_ind) { resource_manager.cancel_last_ue_res_reservations(sl_ack, crnti, ue_cell_cfg); } @@ -439,7 +439,8 @@ void pucch_allocator_impl::pucch_allocate_csi_opportunity(cell_slot_resource_all pucch_uci_bits bits_for_uci = existing_grant_it->pucch_grants.get_uci_bits(); srsran_assert(bits_for_uci.csi_part1_nof_bits == 0, "PUCCH grant for CSI has already been allocated"); bits_for_uci.csi_part1_nof_bits = csi_part1_nof_bits; - auto alloc_outcome = multiplex_and_allocate_pucch(pucch_slot_alloc, bits_for_uci, *existing_grant_it, ue_cell_cfg); + auto alloc_outcome = + multiplex_and_allocate_pucch(pucch_slot_alloc, bits_for_uci, *existing_grant_it, ue_cell_cfg, std::nullopt); if (not alloc_outcome.has_value()) { resource_manager.cancel_last_ue_res_reservations(sl_tx, crnti, ue_cell_cfg); } @@ -631,7 +632,7 @@ class existing_pucch_pdus_handler sr_nof_bits sr_bits, unsigned csi_part1_bits, const pucch_resource& pucch_res_cfg, - const float max_pucch_code_rate = 1.0F); + float max_pucch_code_rate = 1.0F); pucch_info* sr_pdu{nullptr}; pucch_info* harq_pdu{nullptr}; @@ -771,7 +772,7 @@ void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned har sr_nof_bits sr_bits, unsigned csi_part1_bits, const pucch_resource& pucch_res_cfg, - const float max_pucch_code_rate) + float max_pucch_code_rate) { if (harq_pdu->format == pucch_format::FORMAT_0) { harq_pdu->format_0.harq_ack_nof_bits = harq_ack_bits; @@ -1088,15 +1089,6 @@ pucch_allocator_impl::find_common_and_ded_harq_res_available(cell_slot_resource_ } resource_manager.set_new_resource_allocation(rnti, pucch_resource_usage::HARQ_SET_0); - // Add a current grant entry with the PUCCH resource indicator found above; this will force the function that - // multiplexes the resources to use the specific resource with the given PUCCH resource indicator (it could be - // either from resource set 1 or 0, depending on whether there is a CSI grant in the same slot). - pucch_grant& harq_grant = - existing_grants.pucch_grants.harq_resource.emplace(pucch_grant{.type = pucch_grant_type::harq_ack}); - harq_grant.set_res_config(*ded_resource); - harq_grant.bits.harq_ack_nof_bits = 1U; - harq_grant.harq_id.pucch_set_idx = pucch_res_set_idx::set_0; - harq_grant.harq_id.pucch_res_ind = d_pri; // In the bit to transmit, we have 1 HARQ-ACK bit, plus the SR and CSI bits if any existing grants. pucch_uci_bits bits_for_uci{.harq_ack_nof_bits = 1U}; bits_for_uci.sr_bits = existing_grants.pucch_grants.sr_resource.has_value() @@ -1106,11 +1098,11 @@ pucch_allocator_impl::find_common_and_ded_harq_res_available(cell_slot_resource_ ? existing_grants.pucch_grants.csi_resource.value().bits.csi_part1_nof_bits : 0U; - pucch_res_ind = multiplex_and_allocate_pucch(pucch_alloc, bits_for_uci, existing_grants, ue_cell_cfg, true); + // The PUCCH resource indicator must match the one used for the common resource. + pucch_res_ind = multiplex_and_allocate_pucch(pucch_alloc, bits_for_uci, existing_grants, ue_cell_cfg, d_pri); if (not pucch_res_ind.has_value()) { resource_manager.cancel_last_ue_res_reservations(pucch_alloc.slot, rnti, ue_cell_cfg); - existing_grants.pucch_grants.harq_resource.reset(); continue; } @@ -1408,7 +1400,7 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& pucch_uci_bits new_bits, ue_grants& current_grants, const ue_cell_configuration& ue_cell_cfg, - bool preserve_res_indicator) + std::optional preserve_res_indicator) { // NOTE: In this function, the \c candidate_grants report the data about the grants BEFORE the multiplexing is // applied. Each grant contains only one UCI type (HARQ grant contains HARQ bits, SR grant contains SR bits and so @@ -1435,6 +1427,33 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& return allocate_grants(pucch_slot_alloc, current_grants, current_grants.rnti, grants_to_tx, ue_cell_cfg); } +static unsigned get_pucch_resource_ind_f0_sr_csi(pucch_uci_bits bits, const pucch_config& pucch_cfg) +{ + // With Format 0, with HARQ-ACK bits <= 2, pick a resource from PUCCH resource set 0. + + if (bits.harq_ack_nof_bits <= 2U) { + // At position (PUCCH resource set 0 size - 1U) the resource coincides with the SR resource. + if (bits.sr_bits != sr_nof_bits::no_sr) { + return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)].pucch_res_id_list.size() - 1U; + } + // NOTE: Either CSI or SR bits are non-zero, but not both. + // At position (PUCCH resource set 0 size - 2U) the resource is of Format 0, but set on the same PRBs/symbols as the + // CSI resource. + return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)].pucch_res_id_list.size() - 2U; + } + + // This if for bits.harq_ack_nof_bits > 2U. + + // At position (PUCCH resource set 1 size - 2U) the resource is of Format 2, but set on the same PRBs/symbols as the + // SR resource. + if (bits.sr_bits != sr_nof_bits::no_sr) { + return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.size() - 2U; + } + // NOTE: Either CSI or SR bits are non-zero, but not both. + // At position (PUCCH resource set 1 size - 1U) the resource coincides with the CSI resource. + return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.size() - 1U; +} + std::optional pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point sl_tx, pucch_uci_bits new_bits, @@ -1445,67 +1464,6 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point const pucch_config& pucch_cfg = ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value(); - if (new_bits.harq_ack_nof_bits > 0) { - // Case HARQ ACK bits 1 or 2, resource to be chosen from PUCCH resource set 0; else, pick from PUCCH resource - // set 1. - const pucch_res_set_idx pucch_set_idx = - new_bits.harq_ack_nof_bits <= 2U ? pucch_res_set_idx::set_0 : pucch_res_set_idx::set_1; - - candidate_resources.harq_resource.emplace(pucch_grant{.type = pucch_grant_type::harq_ack}); - pucch_grant& harq_candidate_grant = candidate_resources.harq_resource.value(); - - // There is already a PUCCH resource for HARQ-ACK; if so, we use the info and configuration from this resource. - if (ue_current_grants.pucch_grants.harq_resource.has_value() and - ue_current_grants.pucch_grants.harq_resource.value().harq_id.pucch_set_idx == pucch_set_idx) { - const pucch_resource* pucch_res = - pucch_set_idx == pucch_res_set_idx::set_0 - ? resource_manager.reserve_set_0_res_by_res_indicator( - sl_tx, - ue_current_grants.rnti, - ue_current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, - pucch_cfg) - : resource_manager.reserve_set_1_res_by_res_indicator( - sl_tx, - ue_current_grants.rnti, - ue_current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, - pucch_cfg); - if (pucch_res == nullptr) { - srsran_assertion_failure("rnti={}: PUCCH HARQ-ACK resource previously reserved not available anymore", - ue_current_grants.rnti); - return std::nullopt; - } - harq_candidate_grant.harq_id.pucch_set_idx = pucch_set_idx; - harq_candidate_grant.harq_id.pucch_res_ind = - static_cast(ue_current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind); - harq_candidate_grant.set_res_config(*pucch_res); - } - // Get a new PUCCH resource for HARQ-ACK from the correct PUCCH resource set. - else { - // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits before multiplexing. - pucch_harq_resource_alloc_record harq_resource = - pucch_set_idx == pucch_res_set_idx::set_0 - ? resource_manager.reserve_next_set_0_harq_res_available(sl_tx, ue_current_grants.rnti, pucch_cfg) - : resource_manager.reserve_next_set_1_harq_res_available(sl_tx, ue_current_grants.rnti, pucch_cfg); - // Save the resources that have been generated; if at some point the allocation fails, we need to release them. - if (pucch_set_idx == pucch_res_set_idx::set_0) { - resource_manager.set_new_resource_allocation(ue_current_grants.rnti, pucch_resource_usage::HARQ_SET_0); - } else { - resource_manager.set_new_resource_allocation(ue_current_grants.rnti, pucch_resource_usage::HARQ_SET_1); - } - if (harq_resource.pucch_res == nullptr) { - return std::nullopt; - } - harq_candidate_grant.harq_id.pucch_set_idx = pucch_set_idx; - harq_candidate_grant.harq_id.pucch_res_ind = static_cast(harq_resource.pucch_res_indicator); - harq_candidate_grant.set_res_config(*harq_resource.pucch_res); - } - // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits assuming the resources - // still need to be multiplexed. - harq_candidate_grant.bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; - harq_candidate_grant.bits.sr_bits = sr_nof_bits::no_sr; - harq_candidate_grant.bits.csi_part1_nof_bits = 0U; - } - if (new_bits.sr_bits != sr_nof_bits::no_sr) { candidate_resources.sr_resource.emplace(pucch_grant{.type = pucch_grant_type::sr}); pucch_grant& sr_candidate_grant = candidate_resources.sr_resource.value(); @@ -1554,6 +1512,85 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point csi_candidate_grant.bits.csi_part1_nof_bits = new_bits.csi_part1_nof_bits; } + if (new_bits.harq_ack_nof_bits > 0) { + // Case HARQ ACK bits 1 or 2, resource to be chosen from PUCCH resource set 0; else, pick from PUCCH resource + // set 1. + const pucch_res_set_idx pucch_set_idx = + new_bits.harq_ack_nof_bits <= 2U ? pucch_res_set_idx::set_0 : pucch_res_set_idx::set_1; + // NOTE: Not all UEs are capable of transmitting more than 1 PUCCH; this would be the case in which the UE has + // Format 0 resources, and it needs to transmit HARQ-ACK bits + SR or CSI in the same slot, and the resource symbols + // for HARQ and SR/CSI do not overlap. In these slots, we force, the UE to use a PUCCH resource for HARQ-ACK that is + // guaranteed to overlap (in symbols) with the SR or CSI resource. + const bool has_format_0 = + std::find_if(pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), [](const auto& pucch_res) { + return pucch_res.format == pucch_format::FORMAT_0; + }) != pucch_cfg.pucch_res_list.end(); + const bool ue_with_f0_sr_csi_allocation = + has_format_0 and (new_bits.sr_bits != sr_nof_bits::no_sr or new_bits.csi_part1_nof_bits != 0U); + + candidate_resources.harq_resource.emplace(pucch_grant{.type = pucch_grant_type::harq_ack}); + pucch_grant& harq_candidate_grant = candidate_resources.harq_resource.value(); + + // Handle these 2 cases: (i) There is already a PUCCH resource for HARQ-ACK; if so, we use the info and + // configuration from this resource; (ii) the UE has Format 0 resources, and it needs to transmit HARQ-ACK bits + SR + // or CSI in the same slot. + if ((ue_current_grants.pucch_grants.harq_resource.has_value() and + ue_current_grants.pucch_grants.harq_resource.value().harq_id.pucch_set_idx == pucch_set_idx) or + ue_with_f0_sr_csi_allocation) { + // NOTE: If the UE has Format 0 resources, and it needs to transmit HARQ-ACK bits + SR or CSI in the same slot, + // use the HARQ-ACK resource that has highest PUCCH resource indicator; the UE's dedicated PUCCH config has been + // constructed in such a way that this resource overlaps with the SR or CSI resource. + const unsigned pucch_res_ind = ue_with_f0_sr_csi_allocation + ? get_pucch_resource_ind_f0_sr_csi(new_bits, pucch_cfg) + : ue_current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind; + + const pucch_resource* pucch_res = pucch_set_idx == pucch_res_set_idx::set_0 + ? resource_manager.reserve_set_0_res_by_res_indicator( + sl_tx, ue_current_grants.rnti, pucch_res_ind, pucch_cfg) + : resource_manager.reserve_set_1_res_by_res_indicator( + sl_tx, ue_current_grants.rnti, pucch_res_ind, pucch_cfg); + if (pucch_res == nullptr) { + if (ue_with_f0_sr_csi_allocation) { + srsran_assertion_failure("rnti={}: PUCCH HARQ-ACK that should be reserved for this UE is not available", + ue_current_grants.rnti); + } else { + srsran_assertion_failure("rnti={}: PUCCH HARQ-ACK resource previously reserved not available anymore", + ue_current_grants.rnti); + } + + return std::nullopt; + } + harq_candidate_grant.harq_id.pucch_set_idx = pucch_set_idx; + harq_candidate_grant.harq_id.pucch_res_ind = static_cast(pucch_res_ind); + harq_candidate_grant.set_res_config(*pucch_res); + } + // Get a new PUCCH resource for HARQ-ACK from the correct PUCCH resource set. + else { + // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits before multiplexing. + pucch_harq_resource_alloc_record harq_resource = + pucch_set_idx == pucch_res_set_idx::set_0 + ? resource_manager.reserve_next_set_0_harq_res_available(sl_tx, ue_current_grants.rnti, pucch_cfg) + : resource_manager.reserve_next_set_1_harq_res_available(sl_tx, ue_current_grants.rnti, pucch_cfg); + // Save the resources that have been generated; if at some point the allocation fails, we need to release them. + if (pucch_set_idx == pucch_res_set_idx::set_0) { + resource_manager.set_new_resource_allocation(ue_current_grants.rnti, pucch_resource_usage::HARQ_SET_0); + } else { + resource_manager.set_new_resource_allocation(ue_current_grants.rnti, pucch_resource_usage::HARQ_SET_1); + } + if (harq_resource.pucch_res == nullptr) { + return std::nullopt; + } + harq_candidate_grant.harq_id.pucch_set_idx = pucch_set_idx; + harq_candidate_grant.harq_id.pucch_res_ind = static_cast(harq_resource.pucch_res_indicator); + harq_candidate_grant.set_res_config(*harq_resource.pucch_res); + } + // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits assuming the resources + // still need to be multiplexed. + harq_candidate_grant.bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; + harq_candidate_grant.bits.sr_bits = sr_nof_bits::no_sr; + harq_candidate_grant.bits.csi_part1_nof_bits = 0U; + } + // TODO: handle the failure case, in which the resources that had been reserved are not used and need to be released. return candidate_resources; @@ -1683,7 +1720,7 @@ pucch_allocator_impl::multiplex_resources(slot_point sl_tx, rnti_t crnti, pucch_grant_list candidate_grants, const ue_cell_configuration& ue_cell_cfg, - bool preserve_res_indicator) + std::optional preserve_res_indicator) { // This function implements the multiplexing pseudo-code for PUCCH resources defined in Section 9.2.5, TS 38.213. // Refer to paragraph starting as "Set Q to the set of resources for transmission of corresponding PUCCHs in a single @@ -1792,7 +1829,7 @@ pucch_allocator_impl::merge_pucch_resources(span preserve_res_indicator) { // This function implements the merging rules for HARQ-ACK, SR and CSI defined in Section 9.2.5.1 and 9.2.5.2, // TS 38.213. @@ -1841,9 +1878,9 @@ pucch_allocator_impl::merge_pucch_resources(span preserve_res_indicator); // Computes which resources are expected to be sent, depending on the UCI bits to be sent, before any multiplexing. std::optional get_pucch_res_pre_multiplexing(slot_point sl_tx, @@ -190,14 +190,14 @@ class pucch_allocator_impl final : public pucch_allocator rnti_t crnti, pucch_grant_list candidate_grants, const ue_cell_configuration& ue_cell_cfg, - bool preserve_res_indicator = false); + std::optional preserve_res_indicator); // Applies the multiplexing rules depending on the PUCCH resource format, as per TS 38.213, Section 9.2.5.1/2. std::optional merge_pucch_resources(span resources_to_merge, slot_point slot_harq, rnti_t crnti, const pucch_config& pucch_cfg, - bool preserve_res_indicator = false); + std::optional preserve_res_indicator); // Allocate the PUCCH PDUs in the scheduler output, depending on the new PUCCH grants to be transmitted, and depending // on the PUCCH PDUs currently allocated. diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp index 5cb73134f4..d283f4c04d 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp @@ -365,9 +365,20 @@ pucch_harq_resource_alloc_record pucch_resource_manager::reserve_next_harq_res_a const auto& ue_res_id_set_for_harq = pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(res_set_idx)].pucch_res_id_list; unsigned ue_first_res_id = ue_res_id_set_for_harq.front().cell_res_id; + + const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; + srsran_assert(ue_first_res_id + ue_res_id_set_for_harq.size() <= slot_res_array.size(), "Indexing of PUCCH resource set exceeds the size of the cell resource array"); - span slot_ue_res_array(&slot_res_array[ue_first_res_id], ue_res_id_set_for_harq.size()); + // For PUCCH format 0, we don't use the last 2 resources of the PUCCH resource set; these are reserved the UE for CSI + // and SR slots and should only be picked for through the specific PUCCH resource indicator. + const unsigned nof_eligible_resource = + is_format0 ? ue_res_id_set_for_harq.size() - 2U : ue_res_id_set_for_harq.size(); + srsran_assert(nof_eligible_resource >= 1U, + "rnti={}: Not enough eligible resources from PUCCH resource set={}", + crnti, + pucch_res_set_idx_to_uint(res_set_idx)); + span slot_ue_res_array(&slot_res_array[ue_first_res_id], nof_eligible_resource); // Check first if there is any PUCCH resource already used by this UE. auto* available_resource = std::find_if(slot_ue_res_array.begin(), @@ -385,7 +396,7 @@ pucch_harq_resource_alloc_record pucch_resource_manager::reserve_next_harq_res_a // If there is an available resource, try to allocate it. if (available_resource != slot_ue_res_array.end() and - static_cast(available_resource - slot_ue_res_array.begin()) < ue_res_id_set_for_harq.size()) { + static_cast(available_resource - slot_ue_res_array.begin()) < nof_eligible_resource) { // Get the PUCCH resource indicator from the available resource position within the span. const auto pucch_res_indicator = static_cast(available_resource - slot_ue_res_array.begin()); // Get the PUCCH resource ID from the PUCCH resource indicator and the PUCCH resource set. @@ -429,14 +440,30 @@ const pucch_resource* pucch_resource_manager::reserve_harq_res_by_res_indicator( } // Get PUCCH resource ID from the PUCCH resource set. - const unsigned pucch_res_id = ue_res_id_set_for_harq[res_indicator].cell_res_id; + const auto pucch_res_id = ue_res_id_set_for_harq[res_indicator]; + + const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; + // For Format 0, the resources indexed by PUCCH res. indicators >= ue_res_id_set_for_harq.size() - 2 are reserved for + // CSI and SR slots. In the case, we don't need to reserve these in the PUCCH resource manager, we only need to return + // the resouces. + if (is_format0 and res_indicator >= ue_res_id_set_for_harq.size() - 2U) { + const auto* res_cfg = std::find_if( + pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), [pucch_res_id](const pucch_resource& res) { + return res.res_id.ue_res_id == pucch_res_id.ue_res_id; + }); + return res_cfg != pucch_cfg.pucch_res_list.end() ? &(*res_cfg) : nullptr; + } + + // Get PUCCH resource ID from the PUCCH resource set. + const unsigned pucch_cell_res_id = pucch_res_id.cell_res_id; + // Extra safe check. Make sure cell_res_id is valid, even though this should be ensured by the UE config validator. - if (pucch_res_id >= res_counter.ues_using_pucch_res.size()) { + if (pucch_cell_res_id >= res_counter.ues_using_pucch_res.size()) { return nullptr; } // Get the PUCCH resource tracker in the PUCCH resource manager. - auto& pucch_res_tracker = res_counter.ues_using_pucch_res[pucch_res_id]; + auto& pucch_res_tracker = res_counter.ues_using_pucch_res[pucch_cell_res_id]; const auto& pucch_res_list = pucch_cfg.pucch_res_list; // Check first if the wanted PUCCH resource is available. @@ -446,8 +473,8 @@ const pucch_resource* pucch_resource_manager::reserve_harq_res_by_res_indicator( // Search for the PUCCH resource with the correct PUCCH resource ID from the PUCCH resource list. const auto* res_cfg = - std::find_if(pucch_res_list.begin(), pucch_res_list.end(), [pucch_res_id](const pucch_resource& res) { - return res.res_id.cell_res_id == pucch_res_id; + std::find_if(pucch_res_list.begin(), pucch_res_list.end(), [pucch_cell_res_id](const pucch_resource& res) { + return res.res_id.cell_res_id == pucch_cell_res_id; }); if (res_cfg == pucch_res_list.end()) { @@ -479,13 +506,23 @@ bool pucch_resource_manager::release_harq_resource(slot_point slot_harq const pucch_resource_usage res_usage = res_set_idx == pucch_res_set_idx::set_0 ? pucch_resource_usage::HARQ_SET_0 : pucch_resource_usage::HARQ_SET_1; + const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; + // Get the span over the array of resources for the specific UE. const auto& ue_res_id_set_for_harq = pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(res_set_idx)].pucch_res_id_list; unsigned ue_first_res_id = ue_res_id_set_for_harq.front().cell_res_id; srsran_assert(ue_first_res_id + ue_res_id_set_for_harq.size() <= slot_res_array.size(), "Indexing of PUCCH resource set exceeds the size of the cell resource array"); - span slot_ue_res_array(&slot_res_array[ue_first_res_id], ue_res_id_set_for_harq.size()); + // For PUCCH format 0, we don't use the last 2 resources of the PUCCH resource set; these are reserved the UE for CSI + // and SR slots and should only be picked for through the specific PUCCH resource indicator. + const unsigned nof_eligible_resource = + is_format0 ? ue_res_id_set_for_harq.size() - 2U : ue_res_id_set_for_harq.size(); + srsran_assert(nof_eligible_resource >= 1U, + "rnti={}: Not enough eligible resources from PUCCH resource set={}", + crnti, + pucch_res_set_idx_to_uint(res_set_idx)); + span slot_ue_res_array(&slot_res_array[ue_first_res_id], nof_eligible_resource); // Check first if the target PUCCH resource (given the CRNTI and usage) exists within the resource tracker. auto* target_res = diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 96514214ad..4ad849d8d4 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -744,3 +744,145 @@ INSTANTIATE_TEST_SUITE_P( ) // clang-format on ); + +static du_cell_config +make_custom_du_cell_config_for_format_0(const pucch_cnt_builder_params& pucch_params_, + const srsran::config_helpers::cell_config_builder_params_extended& params = {}) +{ + du_cell_config du_cfg = config_helpers::make_default_du_cell_config(params); + auto& pucch_params = du_cfg.pucch_cfg; + pucch_params.nof_sr_resources = pucch_params_.nof_res_sr; + pucch_params.nof_csi_resources = pucch_params_.nof_res_csi; + pucch_params.f0_or_f1_params.emplace(); + + du_cfg.ue_ded_serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg->sr_res_list[0].period = pucch_params_.sr_period; + if (du_cfg.ue_ded_serv_cell_cfg.csi_meas_cfg.has_value()) { + std::get( + du_cfg.ue_ded_serv_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list[0].report_cfg_type) + .report_slot_period = pucch_params_.csi_period; + } + + auto& pucch_res_list = du_cfg.ue_ded_serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value().pucch_res_list; + for (auto& res : pucch_res_list) { + if (res.format == srsran::pucch_format::FORMAT_1) { + res.format = srsran::pucch_format::FORMAT_0; + res.format_params.emplace(); + } + } + + return du_cfg; +} + +class du_ran_res_mng_pucch_format_0_tester : public du_ran_resource_manager_tester_base, + public ::testing::TestWithParam +{ +protected: + explicit du_ran_res_mng_pucch_format_0_tester(cell_config_builder_params params_ = {.dl_arfcn = 520002U}) : + du_ran_resource_manager_tester_base(params_, + make_custom_du_cell_config_for_format_0(GetParam(), params_), + GetParam().max_allowed_pucch_grants) + { + srsran_assert(default_ue_cell_cfg.csi_meas_cfg.has_value() and + not default_ue_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list.empty() and + std::holds_alternative( + default_ue_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list[0].report_cfg_type), + "CSI report configuration is required for this unittest;"); + } + + unsigned lcm_csi_sr_period; + std::vector pucch_cnts; +}; + +TEST_P(du_ran_res_mng_pucch_format_0_tester, sr_and_csi_pucch_resources_have_overlapping_symbols) +{ + du_ue_index_t next_ue_index = to_du_ue_index(0); + + // > Created UEs have unique (PUCCH resource, SR offset) pairs. + std::set> sr_offsets; + std::set> csi_offsets; + for (unsigned i = 0; i != 2; ++i) { + const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); + if (ue_res.empty()) { + ues.erase(next_ue_index); + break; + } + ASSERT_FALSE(ue_res.empty()); + + // Check if the SR has been assigned to the UE. + const auto& sr_res_list = ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + ASSERT_FALSE(sr_res_list.empty()); + ASSERT_EQ(sr_offsets.count(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)), 0); + sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); + unsigned sr_offset = sr_res_list[0].offset; + const auto& sr_pucch_res_cfg = ue_res->cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() + .pucch_res_list[sr_res_list[0].pucch_res_id.ue_res_id]; + ASSERT_TRUE(sr_pucch_res_cfg.format == pucch_format::FORMAT_0); + ASSERT_TRUE(std::holds_alternative(sr_pucch_res_cfg.format_params)); + + // Check if the CSI has been assigned to the UE. + ASSERT_TRUE(has_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg)); + const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg); + ASSERT_FALSE(ue_csi_cfg.pucch_csi_res_list.empty()); + const unsigned csi_pucch_res_id = ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.cell_res_id; + const unsigned csi_offset = ue_csi_cfg.report_slot_offset; + ASSERT_EQ(csi_offsets.count(std::make_pair(csi_pucch_res_id, csi_offset)), 0); + csi_offsets.insert(std::make_pair(csi_pucch_res_id, csi_offset)); + const auto& csi_pucch_res_cfg = ue_res->cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() + .pucch_res_list[ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.ue_res_id]; + ASSERT_TRUE(csi_pucch_res_cfg.format == pucch_format::FORMAT_2); + ASSERT_TRUE(std::holds_alternative(csi_pucch_res_cfg.format_params)); + + // Check the offsets results in the SR and CSI not exceeding the max PUCCH grants. + std::set csi_sr_offset_for_pucch_cnt; + for (unsigned sr_off = sr_offset; sr_off < lcm_csi_sr_period; sr_off += get_config_sr_period()) { + csi_sr_offset_for_pucch_cnt.emplace(sr_off); + } + + for (unsigned csi_off = csi_offset; csi_off < lcm_csi_sr_period; csi_off += get_config_csi_period()) { + csi_sr_offset_for_pucch_cnt.emplace(csi_off); + } + + for (auto offset : csi_sr_offset_for_pucch_cnt) { + srsran_assert(offset < static_cast(pucch_cnts.size()), + "Index exceeds the size of the PUCCH grants vector"); + ++pucch_cnts[offset]; + } + + for (auto pucch_slot_cnt : pucch_cnts) { + ASSERT_TRUE(pucch_slot_cnt <= GetParam().max_allowed_pucch_grants); + } + + const auto& sr_pucch_cfg = std::get(sr_pucch_res_cfg.format_params); + const auto& csi_pucch_cfg = std::get(csi_pucch_res_cfg.format_params); + ofdm_symbol_range sr_symbols{sr_pucch_cfg.starting_sym_idx, + sr_pucch_cfg.starting_sym_idx + sr_pucch_cfg.nof_symbols}; + ofdm_symbol_range csi_symbols{csi_pucch_cfg.starting_sym_idx, + csi_pucch_cfg.starting_sym_idx + csi_pucch_cfg.nof_symbols}; + ASSERT_TRUE(sr_symbols.overlaps(csi_symbols)); + + next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); + } + + // Erase a random UE and attempt. + const du_ue_index_t ue_idx_to_rem = to_du_ue_index(test_rgen::uniform_int(0, ues.size() - 1)); + ues.erase(ue_idx_to_rem); + + // Attempt a new allocation and verify it is successful. + next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); + const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); + ASSERT_FALSE(ue_res.empty()); +} + +INSTANTIATE_TEST_SUITE_P( + parametrized_test_for_format_0, + du_ran_res_mng_pucch_format_0_tester, + // clang-format off + ::testing::Values( + pucch_cnt_builder_params{ 7, 7, 15, srsran::sr_periodicity::sl_10, srsran::csi_report_periodicity::slots10 }, + pucch_cnt_builder_params{ 9, 9, 18, srsran::sr_periodicity::sl_20, srsran::csi_report_periodicity::slots20 }, + pucch_cnt_builder_params{ 11, 11, 22, srsran::sr_periodicity::sl_20, srsran::csi_report_periodicity::slots20 } + ) + // clang-format on +); \ No newline at end of file diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index cda9107613..b55c81fdc0 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -587,6 +587,15 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParamfront().serv_cell_cfg) { + if (GetParam().nof_res_f0_harq != 0) { + auto& pucch_res_list = serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg->pucch_res_list; + for (auto& res : pucch_res_list) { + if (res.format == srsran::pucch_format::FORMAT_1) { + res.format = srsran::pucch_format::FORMAT_0; + res.format_params.emplace(); + } + } + } } bool verify_nof_res_and_idx(unsigned harq_cfg_idx, unsigned sr_idx, unsigned csi_idx) const @@ -613,7 +622,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam= nof_f0_f1_res_harq_per_ue * harq_cfg_idx and res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * (harq_cfg_idx + 1); - // The PUCCH resource ID for the ASN1 message for PUCCH F1 resources is expected to be from 0 to - // nof_f0_f1_res_harq_per_ue for all UEs. + // The PUCCH resource ID for the ASN1 message for PUCCH + // F1 resources is expected to be from 0 to nof_f0_f1_res_harq_per_ue for all UEs. const bool pucch_ue_res_id_test = res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue; const bool pucch_ue_cell_res_id_test = res_idx.cell_res_id - nof_f0_f1_res_harq_per_ue * harq_cfg_idx == res_idx.ue_res_id; - // Make sure the PUCCH resource ID in the set has a corresponding resource in the PUCCH resource list. - auto* res_it = get_pucch_resource_with_id(res_idx); - test_result = test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and pucch_ue_cell_res_id_test and - res_it != pucch_cfg.pucch_res_list.end(); + + test_result = has_f0_res ? res_it != pucch_cfg.pucch_res_list.end() + : test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and + pucch_ue_cell_res_id_test and res_it != pucch_cfg.pucch_res_list.end(); } // Check the PUCCH resources indexing in PUCCH resource Set 1. for (pucch_res_id_t res_idx : pucch_cfg.pucch_res_set[1].pucch_res_id_list) { + // Make sure the PUCCH resource ID in the set has a corresponding resource in the PUCCH resource list. + auto* res_it = get_pucch_resource_with_id(res_idx); + + // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. const bool pucch_cell_res_id_test = res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + nof_f2_res_harq_per_ue * harq_cfg_idx and res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + nof_f2_res_harq_per_ue * (harq_cfg_idx + 1); - // The PUCCH resource ID for the ASN1 message for PUCCH F2 resources is expected to be from - // (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue) for all UEs. + // The PUCCH resource ID for the ASN1 message for PUCCH + // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + + // nof_f2_res_harq_per_ue) for all UEs. const bool pucch_ue_res_id_test = res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1 and res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue; // Check if the PUCCH cell resourece ID is set correspondingly to the PUCCH UE resource ID. @@ -650,10 +668,10 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam(sr_pucch_res_cfg.format_params), + "SR PUCCH resource must be of Format 0 if any of the PUCCH resources from set 0 has Format 0."); + srsran_assert(csi_pucch_res_cfg.format == pucch_format::FORMAT_2 and + std::holds_alternative(csi_pucch_res_cfg.format_params), + "CSI PUCCH resource must be of Format 2"); + const auto& sr_pucch_cfg = std::get(sr_pucch_res_cfg.format_params); + const auto& csi_pucch_cfg = std::get(csi_pucch_res_cfg.format_params); + ofdm_symbol_range sr_symbols{sr_pucch_cfg.starting_sym_idx, + sr_pucch_cfg.starting_sym_idx + sr_pucch_cfg.nof_symbols}; + ofdm_symbol_range csi_symbols{csi_pucch_cfg.starting_sym_idx, + csi_pucch_cfg.starting_sym_idx + csi_pucch_cfg.nof_symbols}; + test_result = test_result and sr_symbols.overlaps(csi_symbols); + } return test_result; } @@ -777,7 +813,7 @@ INSTANTIATE_TEST_SUITE_P(ue_pucch_config_builder, pucch_cfg_builder_params{ 3, 0, 6, 1, 2, 1 }, pucch_cfg_builder_params{ 7, 0, 3, 1, 1, 1 }, pucch_cfg_builder_params{ 8, 0, 8, 1, 4, 1 }, - pucch_cfg_builder_params{ 1, 0, 1, 1, 1, 1 }, + pucch_cfg_builder_params{ 2, 0, 2, 1, 1, 1 }, pucch_cfg_builder_params{ 7, 0, 7, 1, 3, 1 }, pucch_cfg_builder_params{ 8, 0, 8, 4, 4, 4 }, pucch_cfg_builder_params{ 5, 0, 2, 10, 2, 7 }, diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index 836e50e013..d484143d3b 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -121,7 +121,7 @@ class pucch_allocator_base_tester class test_pucch_allocator_ded_resources : public ::testing::Test, public pucch_allocator_base_tester { public: - test_pucch_allocator_ded_resources() : pucch_allocator_base_tester() + test_pucch_allocator_ded_resources() { // Set expected grant for PUCCH Format 1 SR. pucch_expected_f1_sr.format = pucch_format::FORMAT_1; @@ -448,12 +448,12 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_2bits_over_sr) auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; - const auto first_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), - slot_grid.result.ul.pucchs.end(), - [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { - return pdu.crnti == rnti and pdu.format_1.harq_ack_nof_bits == 1U and - pdu.format_1.sr_bits == sr_nof_bits::no_sr; - }); + const auto* first_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { + return pdu.crnti == rnti and pdu.format_1.harq_ack_nof_bits == 1U and + pdu.format_1.sr_bits == sr_nof_bits::no_sr; + }); ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 2; @@ -474,12 +474,12 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_2bits_over_sr) })); // Make sure the second PUCCH allocation uses the same PRBs and symbols as the first one. - const auto second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), - slot_grid.result.ul.pucchs.end(), - [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { - return pdu.crnti == rnti and pdu.format_1.harq_ack_nof_bits == 2U and - pdu.format_1.sr_bits == sr_nof_bits::no_sr; - }); + const auto* second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), + slot_grid.result.ul.pucchs.end(), + [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { + return pdu.crnti == rnti and pdu.format_1.harq_ack_nof_bits == 2U and + pdu.format_1.sr_bits == sr_nof_bits::no_sr; + }); ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); ASSERT_EQ(first_alloc->resources.prbs, second_alloc->resources.prbs); ASSERT_EQ(first_alloc->resources.symbols, second_alloc->resources.symbols); @@ -805,7 +805,7 @@ TEST_F(test_pucch_allocator_ded_resources, with_f2_res_1_harq_bit_adding_adding_ auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; - const auto first_alloc = + const auto* first_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), slot_grid.result.ul.pucchs.end(), [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { return pdu.crnti == rnti; }); @@ -819,7 +819,7 @@ TEST_F(test_pucch_allocator_ded_resources, with_f2_res_1_harq_bit_adding_adding_ ASSERT_EQ(test_pucch_res_indicator.value(), test_pucch_res_indicator_new.value()); // Make sure the second PUCCH allocation uses the same PRBs and symbols as the first one. - const auto second_alloc = + const auto* second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), slot_grid.result.ul.pucchs.end(), [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { return pdu.crnti == rnti; }); @@ -1649,7 +1649,34 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc { public: test_pucch_allocator_format_0() : - pucch_allocator_base_tester(test_bench_params{.pucch_res_common = 0, .use_format_0 = true}) + pucch_allocator_base_tester(test_bench_params{.pucch_res_common = 0, .use_format_0 = true}), + pucch_res_idx_f0_for_sr(t_bench.get_main_ue() + .get_pcell() + .cfg() + .cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)] + .pucch_res_id_list.size() - + 1U), + pucch_res_idx_f2_for_sr(t_bench.get_main_ue() + .get_pcell() + .cfg() + .cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)] + .pucch_res_id_list.size() - + 2U), + pucch_res_idx_f2_for_csi(t_bench.get_main_ue() + .get_pcell() + .cfg() + .cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)] + .pucch_res_id_list.size() - + 1U) { // Set expected grant for PUCCH Format 0 SR. pucch_expected_f0_sr.format = pucch_format::FORMAT_0; @@ -1658,7 +1685,7 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc pucch_expected_f0_sr.resources.prbs = prb_interval{0, 1}; pucch_expected_f0_sr.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_f0_sr.resources.symbols = ofdm_symbol_range{6, 8}; + pucch_expected_f0_sr.resources.symbols = ofdm_symbol_range{12, 14}; pucch_expected_f0_sr.format_0.initial_cyclic_shift = 0; pucch_expected_f0_sr.format_0.sr_bits = sr_nof_bits::one; @@ -1686,7 +1713,7 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc pucch_expected_f2.format = srsran::pucch_format::FORMAT_2; pucch_expected_f2.crnti = to_rnti(0x4601); pucch_expected_f2.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - pucch_expected_f2.resources.prbs = prb_interval{2, 3}; + pucch_expected_f2.resources.prbs = prb_interval{1, 2}; pucch_expected_f2.resources.second_hop_prbs = prb_interval{0, 0}; pucch_expected_f2.resources.symbols = ofdm_symbol_range{0, 2}; @@ -1694,12 +1721,24 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc pucch_expected_f2.format_2.n_id_scambling = t_bench.cell_cfg.pci; pucch_expected_f2.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; + // This PUCCH resource is located on the same symbols and PRBs as the PUCCH Format 0 resource for SR. + pucch_expected_f2_harq_for_sr.format = srsran::pucch_format::FORMAT_2; + pucch_expected_f2_harq_for_sr.crnti = to_rnti(0x4601); + pucch_expected_f2_harq_for_sr.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_expected_f2_harq_for_sr.resources.prbs = prb_interval{0, 1}; + pucch_expected_f2_harq_for_sr.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f2_harq_for_sr.resources.symbols = ofdm_symbol_range{12, 14}; + + pucch_expected_f2_harq_for_sr.format_2.max_code_rate = max_pucch_code_rate::dot_25; + pucch_expected_f2_harq_for_sr.format_2.n_id_scambling = t_bench.cell_cfg.pci; + pucch_expected_f2_harq_for_sr.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; + pucch_expected_csi.format = srsran::pucch_format::FORMAT_2; pucch_expected_csi.crnti = to_rnti(0x4601); pucch_expected_csi.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - pucch_expected_csi.resources.prbs = prb_interval{2, 3}; + pucch_expected_csi.resources.prbs = prb_interval{1, 2}; pucch_expected_csi.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_csi.resources.symbols = ofdm_symbol_range{12, 14}; + pucch_expected_csi.resources.symbols = ofdm_symbol_range{0, 2}; pucch_expected_csi.format_2.max_code_rate = max_pucch_code_rate::dot_25; pucch_expected_csi.format_2.n_id_scambling = t_bench.cell_cfg.pci; @@ -1708,10 +1747,14 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc protected: // Parameters that are passed by the routine to run the tests. - pucch_info pucch_expected_f0_sr; - pucch_info pucch_expected_f0_harq; - pucch_info pucch_expected_f2; - pucch_info pucch_expected_csi; + pucch_info pucch_expected_f0_sr; + pucch_info pucch_expected_f0_harq; + pucch_info pucch_expected_f2_harq_for_sr; + pucch_info pucch_expected_f2; + pucch_info pucch_expected_csi; + const unsigned pucch_res_idx_f0_for_sr; + const unsigned pucch_res_idx_f2_for_sr; + const unsigned pucch_res_idx_f2_for_csi; }; TEST_F(test_pucch_allocator_format_0, test_sr_allocation_only) @@ -1781,16 +1824,15 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_over_sr) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 1U; - pucch_expected_f0_harq.format_0.sr_bits = srsran::sr_nof_bits::no_sr; - pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; - pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + // According to the multiplexing procedure defined by TS 38.213, Section 9.2.5, the resource to use to report 1 + // HARQ-ACK bit + 1 SR bit is the HARQ-ACK resource. However, to circumvent the lack of capability of some UES (that + // cannot transmit more than 1 PUCCH), we set last resource of PUCCH resource set 0 to be the SR resource and the UE + // will use this. + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 1U; + pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); + ASSERT_EQ(pucch_res_idx_f0_for_sr, test_pucch_res_indicator); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { return pucch_info_match(expected, pdu); })); @@ -1806,45 +1848,28 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_sr) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(pucch_res_idx_f0_for_sr, test_pucch_res_indicator); - const auto first_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), - slot_grid.result.ul.pucchs.end(), - [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { - return pdu.crnti == rnti and pdu.format_0.harq_ack_nof_bits == 1U and - pdu.format_0.sr_bits == sr_nof_bits::no_sr; - }); - ASSERT_TRUE(first_alloc != slot_grid.result.ul.pucchs.end()); + const auto first_alloc = slot_grid.result.ul.pucchs.front(); const std::optional test_pucch_res_indicator_1 = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; - pucch_expected_f0_harq.format_0.sr_bits = srsran::sr_nof_bits::no_sr; - pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; - pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 2U; + pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; ASSERT_TRUE(test_pucch_res_indicator_1.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator_1); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); + ASSERT_EQ(pucch_res_idx_f0_for_sr, test_pucch_res_indicator_1); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { return pucch_info_match(expected, pdu); })); // Make sure the resource used for the second HARQ-ACK allocation uses the same PRBs and symbols as the first // allocation. - const auto second_alloc = std::find_if(slot_grid.result.ul.pucchs.begin(), - slot_grid.result.ul.pucchs.end(), - [rnti = t_bench.get_main_ue().crnti](const auto& pdu) { - return pdu.crnti == rnti and pdu.format_0.harq_ack_nof_bits == 2U and - pdu.format_0.sr_bits == sr_nof_bits::no_sr; - }); - ASSERT_TRUE(second_alloc != slot_grid.result.ul.pucchs.end()); - ASSERT_EQ(first_alloc->resources.prbs, second_alloc->resources.prbs); - ASSERT_EQ(first_alloc->resources.symbols, second_alloc->resources.symbols); - ASSERT_EQ(first_alloc->resources.second_hop_prbs, second_alloc->resources.second_hop_prbs); + const auto second_alloc = slot_grid.result.ul.pucchs.front(); + ASSERT_EQ(first_alloc.resources.prbs, second_alloc.resources.prbs); + ASSERT_EQ(first_alloc.resources.symbols, second_alloc.resources.symbols); + ASSERT_EQ(first_alloc.resources.second_hop_prbs, second_alloc.resources.second_hop_prbs); } TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_sr) @@ -1861,24 +1886,13 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_sr) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f2.format_2.harq_ack_nof_bits = 3U; - pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; - pucch_expected_f2.format_2.csi_part1_bits = 0U; - // Change PRBs and symbol, as for Format 0 we use a different set of resources: - // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). - // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with - // symbols [12..14). - pucch_expected_f2.resources.prbs.set(1, 2); - pucch_expected_f2.resources.symbols.set(0, 2); - pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; - pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + pucch_expected_f2_harq_for_sr.format_2.harq_ack_nof_bits = 3U; + pucch_expected_f2_harq_for_sr.format_2.sr_bits = srsran::sr_nof_bits::one; + pucch_expected_f2_harq_for_sr.format_2.csi_part1_bits = 0U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + ASSERT_EQ(pucch_res_idx_f2_for_sr, test_pucch_res_indicator); + ASSERT_EQ(1U, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2_harq_for_sr](const auto& pdu) { return pucch_info_match(expected, pdu); })); } @@ -1894,24 +1908,13 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_sr) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f2.format_2.harq_ack_nof_bits = 4U; - pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; - pucch_expected_f2.format_2.csi_part1_bits = 0U; - // Change PRBs and symbol, as for Format 0 we use a different set of resources: - // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). - // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with - // symbols [12..14). - pucch_expected_f2.resources.prbs.set(1, 2); - pucch_expected_f2.resources.symbols.set(0, 2); - pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; - pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + pucch_expected_f2_harq_for_sr.format_2.harq_ack_nof_bits = 4U; + pucch_expected_f2_harq_for_sr.format_2.sr_bits = srsran::sr_nof_bits::one; + pucch_expected_f2_harq_for_sr.format_2.csi_part1_bits = 0U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + ASSERT_EQ(pucch_res_idx_f2_for_sr, test_pucch_res_indicator); + ASSERT_EQ(1U, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2_harq_for_sr](const auto& pdu) { return pucch_info_match(expected, pdu); })); } @@ -1927,22 +1930,16 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_over_csi) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 1U; - // Change PRBs and symbol, as for Format 0 we use a different set of resources: - // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). - // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with - // symbols [12..14). - pucch_expected_csi.resources.prbs.set(1, 2); - pucch_expected_csi.resources.symbols.set(12, 14); - pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; - pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; - pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + // After the multiplexing, the PUCCH F2 resource is that one that have the same PUCCH resource indicator as + // pucch_res_idx_f0_for_csi; we need to update the PRBs and symbols accordingly. With the given configuration, this + // resource will have the same PRBs and symbols as the F2 resource for SR. + pucch_expected_csi.format_2.harq_ack_nof_bits = 1U; + pucch_expected_csi.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_csi.format_2.csi_part1_bits = 4U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); + // The allocation should preserve the pucch_res_idx_f0_for_csi + ASSERT_EQ(pucch_res_idx_f2_for_csi, test_pucch_res_indicator); + ASSERT_EQ(1U, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { return pucch_info_match(expected, pdu); })); @@ -1961,22 +1958,12 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_csi) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; - // Change PRBs and symbol, as for Format 0 we use a different set of resources: - // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). - // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with - // symbols [12..14). - pucch_expected_csi.resources.prbs.set(1, 2); - pucch_expected_csi.resources.symbols.set(12, 14); - pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; - pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; - pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + pucch_expected_csi.format_2.harq_ack_nof_bits = 2U; + pucch_expected_csi.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_csi.format_2.csi_part1_bits = 4U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); + ASSERT_EQ(pucch_res_idx_f2_for_csi, test_pucch_res_indicator); + ASSERT_EQ(1U, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { return pucch_info_match(expected, pdu); })); @@ -1997,26 +1984,12 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_csi) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f2.format_2.harq_ack_nof_bits = 3U; - pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; - pucch_expected_f2.format_2.csi_part1_bits = 0U; - // Change PRBs and symbol, as for Format 0 we use a different set of resources: - // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). - // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with - // symbols [12..14). - pucch_expected_f2.resources.prbs.set(1, 2); - pucch_expected_f2.resources.symbols.set(0, 2); - pucch_expected_csi.resources.prbs.set(1, 2); - pucch_expected_csi.resources.symbols.set(12, 14); - pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; - pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; - pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + pucch_expected_csi.format_2.harq_ack_nof_bits = 3U; + pucch_expected_csi.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_csi.format_2.csi_part1_bits = 4U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); + ASSERT_EQ(pucch_res_idx_f2_for_csi, test_pucch_res_indicator); + ASSERT_EQ(1U, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { return pucch_info_match(expected, pdu); })); @@ -2034,26 +2007,12 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_csi) const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - pucch_expected_f2.format_2.harq_ack_nof_bits = 4U; - pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; - pucch_expected_f2.format_2.csi_part1_bits = 0U; - // Change PRBs and symbol, as for Format 0 we use a different set of resources: - // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). - // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with - // symbols [12..14). - pucch_expected_f2.resources.prbs.set(1, 2); - pucch_expected_f2.resources.symbols.set(0, 2); - pucch_expected_csi.resources.prbs.set(1, 2); - pucch_expected_csi.resources.symbols.set(12, 14); - pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; - pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; - pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + pucch_expected_csi.format_2.harq_ack_nof_bits = 4U; + pucch_expected_csi.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_csi.format_2.csi_part1_bits = 4U; ASSERT_TRUE(test_pucch_res_indicator.has_value()); - ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); - ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); - ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { - return pucch_info_match(expected, pdu); - })); + ASSERT_EQ(pucch_res_idx_f2_for_csi, test_pucch_res_indicator); + ASSERT_EQ(1U, slot_grid.result.ul.pucchs.size()); ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { return pucch_info_match(expected, pdu); })); diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 7c2c590d08..85444c76ef 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -193,7 +193,8 @@ test_bench::test_bench(const test_bench_params& params, if (use_format_0) { pucch_builder_params pucch_params{}; - pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 3; + pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6; + pucch_params.nof_ue_pucch_f2_res_harq = 6; pucch_params.f0_or_f1_params.emplace(); pucch_builder.setup( cell_cfg.ul_cfg_common.init_ul_bwp, params.is_tdd ? cell_cfg.tdd_cfg_common : std::nullopt, pucch_params); From 3db96208574fa744b2e97b6eafb75b6bf77bb2ae Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 17 Jul 2024 15:52:07 +0200 Subject: [PATCH 207/407] du: generate pucch ue cfg for UE capabilities for F0 Signed-off-by: Carlo Galiotto --- .../pucch_resource_generator.cpp | 120 ++++-- .../pucch_resource_generator_test.cpp | 363 ++++++++++++------ 2 files changed, 339 insertions(+), 144 deletions(-) diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp index 991284ebff..e5339ee367 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -599,12 +599,13 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned return res_list; } -static unsigned cell_res_list_validator(const std::vector& res_list, - bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_res_harq, - unsigned nof_harq_pucch_cfgs, - unsigned nof_cell_pucch_f1_res_sr, - unsigned nof_cell_pucch_f2_res_csi) +static unsigned +cell_res_list_and_params_validator(const std::vector& res_list, + bounded_integer nof_ue_pucch_f0_f1_res_harq, + bounded_integer nof_ue_pucch_f2_res_harq, + unsigned nof_harq_pucch_cfgs, + unsigned nof_cell_pucch_f1_res_sr, + unsigned nof_cell_pucch_f2_res_csi) { const unsigned FAILURE_CASE = 0U; @@ -622,6 +623,19 @@ static unsigned cell_res_list_validator(const std::vector& return res.format == pucch_format::FORMAT_0; }) != res_list.end(); + if (contain_format_0) { + if (nof_ue_pucch_f0_f1_res_harq.to_uint() > 6U) { + srsran_assertion_failure("With Format 0, nof_ue_pucch_f0_f1_res_harq cannot be greater than 6, as 2 " + "resources in set 0 are reserved."); + return FAILURE_CASE; + } + if (nof_ue_pucch_f2_res_harq.to_uint() > 6U) { + srsran_assertion_failure("With Format 0, nof_ue_pucch_f2_res_harq cannot be greater than 6, as 2 " + "resources in set 1 are reserved."); + return FAILURE_CASE; + } + } + const unsigned tot_nof_f0_res = count_resources(pucch_format::FORMAT_0); const unsigned tot_nof_f1_res = count_resources(pucch_format::FORMAT_1); const unsigned tot_nof_f2_res = count_resources(pucch_format::FORMAT_2); @@ -639,16 +653,9 @@ static unsigned cell_res_list_validator(const std::vector& return FAILURE_CASE; } - if (contain_format_0) { - if (tot_nof_f0_f1_res < 3 or tot_nof_f2_res < 2) { - srsran_assertion_failure("The cell PUCCH resource list must contain at least 3 F0/F1 and 2 F2 PUCCH resources."); - return FAILURE_CASE; - } - } else { - if (tot_nof_f0_f1_res < 2 or tot_nof_f2_res < 2) { - srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2 PUCCH resources."); - return FAILURE_CASE; - } + if (tot_nof_f0_f1_res < 2 or tot_nof_f2_res < 2) { + srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2 PUCCH resources."); + return FAILURE_CASE; } if (nof_ue_pucch_f0_f1_res_harq.to_uint() > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr or @@ -687,12 +694,12 @@ bool srsran::srs_du::ue_pucch_config_builder( unsigned nof_cell_pucch_f0_f1_res_sr, unsigned nof_cell_pucch_f2_res_csi) { - const unsigned tot_nof_cell_f0_f1_res = cell_res_list_validator(res_list, - nof_ue_pucch_f0_f1_res_harq, - nof_ue_pucch_f2_res_harq, - nof_harq_pucch_sets, - nof_cell_pucch_f0_f1_res_sr, - nof_cell_pucch_f2_res_csi); + const unsigned tot_nof_cell_f0_f1_res = cell_res_list_and_params_validator(res_list, + nof_ue_pucch_f0_f1_res_harq, + nof_ue_pucch_f2_res_harq, + nof_harq_pucch_sets, + nof_cell_pucch_f0_f1_res_sr, + nof_cell_pucch_f2_res_csi); if (tot_nof_cell_f0_f1_res == 0U) { return false; @@ -716,6 +723,8 @@ bool srsran::srs_du::ue_pucch_config_builder( // Add F1 for HARQ. const unsigned f0_f1_idx_offset = (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq.to_uint(); + const bool is_format_0 = res_list[f0_f1_idx_offset].format == pucch_format::FORMAT_0; + for (unsigned ue_f1_cnt = 0; ue_f1_cnt < nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f1_cnt) { const auto& cell_res = res_list[ue_f1_cnt + f0_f1_idx_offset]; @@ -734,8 +743,22 @@ bool srsran::srs_du::ue_pucch_config_builder( ++ue_pucch_res_id; } + const unsigned f0_res_on_csi_prbs_syms_idx = nof_ue_pucch_f0_f1_res_harq.to_uint(); + if (is_format_0 and serv_cell_cfg.csi_meas_cfg.has_value()) { + // Add PUCCH resource to pucch_res_list. + pucch_cfg.pucch_res_list.emplace_back(pucch_resource{ + .res_id = {std::numeric_limits::max(), ue_pucch_res_id}, .format = pucch_format::FORMAT_0}); + + // Add PUCCH resource index to pucch_res_id_list of PUCCH resource set id=0. + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)].pucch_res_id_list.emplace_back( + pucch_res_id_t{std::numeric_limits::max(), ue_pucch_res_id}); + + // Increment the PUCCH resource ID for ASN1 message. + ++ue_pucch_res_id; + } + // Add SR resource. - const unsigned sr_res_idx = nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_sets + (du_sr_res_idx); + const unsigned sr_res_idx = nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_sets + du_sr_res_idx; const auto& sr_cell_res = res_list[sr_res_idx]; const unsigned ue_pucch_res_id_for_sr = ue_pucch_res_id; pucch_cfg.pucch_res_list.emplace_back( @@ -748,19 +771,17 @@ bool srsran::srs_du::ue_pucch_config_builder( // Increment the PUCCH resource ID for ASN1 message. ++ue_pucch_res_id; - // For Format 0, copy maps the last resource of the set 0 to the SR resource. - const bool is_format_0 = res_list[f0_f1_idx_offset].format == pucch_format::FORMAT_0; + // For Format 0, map the last resource of the set 0 to the SR resource. if (is_format_0) { - const unsigned last_harq_res_set_0_idx = nof_ue_pucch_f0_f1_res_harq.to_uint() - 1U; - auto& last_harq_res_set_0 = pucch_cfg.pucch_res_list[last_harq_res_set_0_idx]; + auto& last_harq_res_set_0 = pucch_cfg.pucch_res_list.back(); last_harq_res_set_0.res_id.cell_res_id = sr_cell_res.res_id.cell_res_id; last_harq_res_set_0.res_id.ue_res_id = ue_pucch_res_id_for_sr; last_harq_res_set_0.starting_prb = sr_cell_res.starting_prb; last_harq_res_set_0.second_hop_prb = sr_cell_res.second_hop_prb; last_harq_res_set_0.format = sr_cell_res.format; last_harq_res_set_0.format_params = sr_cell_res.format_params; - pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)] - .pucch_res_id_list[last_harq_res_set_0_idx] = {sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}; + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)].pucch_res_id_list.emplace_back( + pucch_res_id_t{sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}); } // Add F2 for HARQ. @@ -781,10 +802,31 @@ bool srsran::srs_du::ue_pucch_config_builder( ++ue_pucch_res_id; } + const unsigned f2_res_on_sr_prbs_syms_idx = ue_pucch_res_id; + if (is_format_0) { + // Add PUCCH resource to pucch_res_list. + pucch_cfg.pucch_res_list.emplace_back(pucch_resource{ + .res_id = {std::numeric_limits::max(), ue_pucch_res_id}, .format = pucch_format::FORMAT_2}); + + // Add PUCCH resource index to pucch_res_id_list of PUCCH resource set id=0. + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.emplace_back( + pucch_res_id_t{std::numeric_limits::max(), ue_pucch_res_id}); + + // Increment the PUCCH resource ID for ASN1 message. + ++ue_pucch_res_id; + + auto& f2_harq_on_sr_resources = pucch_cfg.pucch_res_list[f2_res_on_sr_prbs_syms_idx]; + f2_harq_on_sr_resources.starting_prb = sr_cell_res.starting_prb; + f2_harq_on_sr_resources.second_hop_prb = sr_cell_res.second_hop_prb; + const auto& sr_params_cfg = std::get(sr_cell_res.format_params); + f2_harq_on_sr_resources.format_params.emplace(pucch_format_2_3_cfg{ + .nof_prbs = 1U, .nof_symbols = sr_params_cfg.nof_symbols, .starting_sym_idx = sr_params_cfg.starting_sym_idx}); + } + if (serv_cell_cfg.csi_meas_cfg.has_value()) { // Add CSI resource. const unsigned csi_res_idx = - tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_sets + (du_csi_res_idx); + tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_sets + du_csi_res_idx; const auto& csi_cell_res = res_list[csi_res_idx]; const unsigned ue_pucch_res_id_for_csi = ue_pucch_res_id; pucch_cfg.pucch_res_list.emplace_back( @@ -793,6 +835,7 @@ bool srsran::srs_du::ue_pucch_config_builder( .second_hop_prb = csi_cell_res.second_hop_prb, .format = csi_cell_res.format, .format_params = csi_cell_res.format_params}); + const auto& csi_params_cfg = std::get(csi_cell_res.format_params); std::get( serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list[0].report_cfg_type) .pucch_csi_res_list.front() @@ -801,18 +844,23 @@ bool srsran::srs_du::ue_pucch_config_builder( ++ue_pucch_res_id; if (is_format_0) { - const unsigned last_harq_res_set_1_idx = - nof_ue_pucch_f0_f1_res_harq.to_uint() + 1U + nof_ue_pucch_f2_res_harq.to_uint() - 1U; - auto& last_harq_res_set_1 = pucch_cfg.pucch_res_list[last_harq_res_set_1_idx]; + auto& last_harq_res_set_1 = pucch_cfg.pucch_res_list.back(); last_harq_res_set_1.res_id.cell_res_id = csi_cell_res.res_id.cell_res_id; last_harq_res_set_1.res_id.ue_res_id = ue_pucch_res_id_for_csi; last_harq_res_set_1.starting_prb = csi_cell_res.starting_prb; last_harq_res_set_1.second_hop_prb = csi_cell_res.second_hop_prb; last_harq_res_set_1.format = csi_cell_res.format; last_harq_res_set_1.format_params = csi_cell_res.format_params; - pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)] - .pucch_res_id_list[nof_ue_pucch_f2_res_harq.to_uint() - 1U] = {csi_cell_res.res_id.cell_res_id, - ue_pucch_res_id_for_csi}; + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.emplace_back( + pucch_res_id_t{csi_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_csi}); + + auto& f0_harq_on_csi_resources = pucch_cfg.pucch_res_list[f0_res_on_csi_prbs_syms_idx]; + f0_harq_on_csi_resources.starting_prb = csi_cell_res.starting_prb; + f0_harq_on_csi_resources.second_hop_prb = csi_cell_res.second_hop_prb; + f0_harq_on_csi_resources.format_params.emplace( + pucch_format_0_cfg{.initial_cyclic_shift = 0U, + .nof_symbols = csi_params_cfg.nof_symbols, + .starting_sym_idx = csi_params_cfg.starting_sym_idx}); } } diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index b55c81fdc0..b3b359d8a0 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -596,6 +596,10 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam 0; const unsigned nof_f0_f1_res_harq_per_ue = has_f0_res ? nof_f0_res_harq_per_ue : nof_f1_res_harq_per_ue; + bool test_result = true; + // Check the number of resources in the PUCCH resource list is correct. - bool test_result = pucch_cfg.pucch_res_list.size() == - (nof_f0_f1_res_harq_per_ue + nof_f2_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue); + if (has_f0_res) { + // For Format 0, the pucch_res_list contains 2 extra resources, 1 per PUCCH resource set. + const unsigned extra_resources = has_csi ? 2U : 1U; + test_result = pucch_cfg.pucch_res_list.size() == nof_f0_f1_res_harq_per_ue + nof_f2_res_harq_per_ue + + nof_sr_res_per_ue + nof_csi_res_per_ue + extra_resources; + } else { + test_result = pucch_cfg.pucch_res_list.size() == + nof_f0_f1_res_harq_per_ue + nof_f2_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue; + } // Check the number of PUCCH F1 resources in the PUCCH resource sets is correct. - test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == nof_f0_f1_res_harq_per_ue; - test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_res_harq_per_ue; + if (has_f0_res) { + // For Format 0, each PUCCH resource set contains extra resources. If CSI is enabled, then each PUCCH resource set + // contains 1 (new) PUCCH resource that is added to the pucch_res_list plus 1 that maps to the SR (in set 0) or + // CSI (in set 1). If CSI is not enabled, 1 PUCCH then each PUCCH resource set contains 1 PUCCH resource only. + const unsigned extra_res_per_set = has_csi ? 2U : 1U; + test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == + nof_f0_f1_res_harq_per_ue + extra_res_per_set; + test_result = test_result && + pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_res_harq_per_ue + extra_res_per_set; + } else { + test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == nof_f0_f1_res_harq_per_ue; + test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_res_harq_per_ue; + } // Helper to retrive a given PUCCH resource given its ID from the PUCCH resource list. auto get_pucch_resource_with_id = [&pucch_cfg](pucch_res_id_t res_id) { @@ -629,116 +656,231 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam( + csi_cfg.csi_report_cfg_list.front().report_cfg_type) and + not std::get( + csi_cfg.csi_report_cfg_list.front().report_cfg_type) + .pucch_csi_res_list.empty(), + "PUCCH-CSI-ResourceList has not been configured in the CSI-reportConfig"); + + const pucch_res_id_t csi_res_id = std::get( + csi_cfg.csi_report_cfg_list.front().report_cfg_type) + .pucch_csi_res_list.front() + .pucch_res_id; + + // Check the PUCCH resouce ID for CSI is correct. + if (has_f0_res) { + const bool csi_cell_res_id_test = + csi_res_id.cell_res_id == nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * nof_harq_cfg_per_ue + csi_idx; + const bool csi_ue_res_id_test = csi_res_id.ue_res_id == nof_f0_f1_res_harq_per_ue + 3U + nof_f2_res_harq_per_ue; + test_result = test_result and csi_cell_res_id_test and csi_ue_res_id_test; + } else { + const bool csi_cell_res_id_test = + csi_res_id.cell_res_id == nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * nof_harq_cfg_per_ue + csi_idx; + const bool csi_ue_res_id_test = csi_res_id.ue_res_id == nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue; + test_result = test_result and csi_cell_res_id_test and csi_ue_res_id_test; + } + // Check the PUCCH resouce for SR present in the list. + res_it = get_pucch_resource_with_id(csi_res_id); + test_result = test_result and res_it != pucch_cfg.pucch_res_list.end(); + } + // Check the PUCCH resources indexing in PUCCH resource Set 0. for (pucch_res_id_t res_idx : pucch_cfg.pucch_res_set[0].pucch_res_id_list) { // Make sure the PUCCH resource ID in the set has a corresponding resource in the PUCCH resource list. - auto* res_it = get_pucch_resource_with_id(res_idx); - - // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. - const bool pucch_cell_res_id_test = res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * harq_cfg_idx and - res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * (harq_cfg_idx + 1); - // The PUCCH resource ID for the ASN1 message for PUCCH - // F1 resources is expected to be from 0 to nof_f0_f1_res_harq_per_ue for all UEs. - const bool pucch_ue_res_id_test = res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue; - const bool pucch_ue_cell_res_id_test = - res_idx.cell_res_id - nof_f0_f1_res_harq_per_ue * harq_cfg_idx == res_idx.ue_res_id; - - test_result = has_f0_res ? res_it != pucch_cfg.pucch_res_list.end() - : test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and - pucch_ue_cell_res_id_test and res_it != pucch_cfg.pucch_res_list.end(); + res_it = get_pucch_resource_with_id(res_idx); + + if (has_f0_res) { + test_result = test_result and res_it != pucch_cfg.pucch_res_list.end(); + // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. + + const bool pucch_cell_res_id_test = (res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * harq_cfg_idx and + res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * (harq_cfg_idx + 1)) or + res_idx.cell_res_id == sr_pucch_res_id.cell_res_id or + res_idx.cell_res_id == std::numeric_limits::max(); + const bool pucch_ue_res_id_test = + res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1U or res_idx.ue_res_id == sr_pucch_res_id.ue_res_id; + test_result = test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and + res_it != pucch_cfg.pucch_res_list.end(); + } else { + // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. + const bool pucch_cell_res_id_test = res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * harq_cfg_idx and + res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * (harq_cfg_idx + 1); + // The PUCCH resource ID for the ASN1 message for PUCCH + // F1 resources is expected to be from 0 to nof_f0_f1_res_harq_per_ue for all UEs. + const bool pucch_ue_res_id_test = res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue; + const bool pucch_ue_cell_res_id_test = + res_idx.cell_res_id - nof_f0_f1_res_harq_per_ue * harq_cfg_idx == res_idx.ue_res_id; + + test_result = test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and pucch_ue_cell_res_id_test and + res_it != pucch_cfg.pucch_res_list.end(); + } } // Check the PUCCH resources indexing in PUCCH resource Set 1. for (pucch_res_id_t res_idx : pucch_cfg.pucch_res_set[1].pucch_res_id_list) { // Make sure the PUCCH resource ID in the set has a corresponding resource in the PUCCH resource list. - auto* res_it = get_pucch_resource_with_id(res_idx); - - // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. - const bool pucch_cell_res_id_test = - res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * harq_cfg_idx and - res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * (harq_cfg_idx + 1); - // The PUCCH resource ID for the ASN1 message for PUCCH - // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + - // nof_f2_res_harq_per_ue) for all UEs. - const bool pucch_ue_res_id_test = res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1 and - res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue; - // Check if the PUCCH cell resourece ID is set correspondingly to the PUCCH UE resource ID. - const bool pucch_ue_cell_res_id_test = - res_idx.cell_res_id - (nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * harq_cfg_idx) == - res_idx.ue_res_id - (nof_f0_f1_res_harq_per_ue + 1); - - test_result = has_f0_res ? res_it != pucch_cfg.pucch_res_list.end() - : test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and - pucch_ue_cell_res_id_test and res_it != pucch_cfg.pucch_res_list.end(); + res_it = get_pucch_resource_with_id(res_idx); + + if (has_f0_res) { + // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. + bool pucch_cell_res_id_test = true; + bool pucch_ue_res_id_test = true; + if (has_csi) { + const pucch_res_id_t csi_res_id = + std::get( + serv_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list.front().report_cfg_type) + .pucch_csi_res_list.front() + .pucch_res_id; + pucch_cell_res_id_test = + (res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * harq_cfg_idx and + res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * (harq_cfg_idx + 1)) or + res_idx.cell_res_id == csi_res_id.cell_res_id or + res_idx.cell_res_id == std::numeric_limits::max(); + + // The PUCCH resource ID for the ASN1 message for PUCCH + // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + + // nof_f2_res_harq_per_ue) for all UEs. + pucch_ue_res_id_test = (res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 2U and + res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 3U + nof_f2_res_harq_per_ue) or + res_idx.ue_res_id == csi_res_id.ue_res_id; + } else { + pucch_cell_res_id_test = + (res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * harq_cfg_idx and + res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * (harq_cfg_idx + 1)) or + res_idx.cell_res_id == std::numeric_limits::max(); + + // The PUCCH resource ID for the ASN1 message for PUCCH + // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + + // nof_f2_res_harq_per_ue) for all UEs. + pucch_ue_res_id_test = res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1U and + res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 2U + nof_f2_res_harq_per_ue; + } + + test_result = has_f0_res ? res_it != pucch_cfg.pucch_res_list.end() + : test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and + res_it != pucch_cfg.pucch_res_list.end(); + } else { + // The checks on the PUCCH resource indices are only valid for configurations that doesn't have Format 0. + const bool pucch_cell_res_id_test = + res_idx.cell_res_id >= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * harq_cfg_idx and + res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * (harq_cfg_idx + 1); + // The PUCCH resource ID for the ASN1 message for PUCCH + // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + + // nof_f2_res_harq_per_ue) for all UEs. + const bool pucch_ue_res_id_test = res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1 and + res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue; + // Check if the PUCCH cell resourece ID is set correspondingly to the PUCCH UE resource ID. + const bool pucch_ue_cell_res_id_test = + res_idx.cell_res_id - (nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + + nof_f2_res_harq_per_ue * harq_cfg_idx) == + res_idx.ue_res_id - (nof_f0_f1_res_harq_per_ue + 1); + + test_result = test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and pucch_ue_cell_res_id_test and + res_it != pucch_cfg.pucch_res_list.end(); + } } // Check the format correctness. - const pucch_format format_pucch_set_0 = has_f0_res ? pucch_format::FORMAT_0 : pucch_format::FORMAT_1; - for (const auto& res : pucch_cfg.pucch_res_list) { - const pucch_format expected_format = - res.res_id.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell - ? format_pucch_set_0 - : srsran::pucch_format::FORMAT_2; - test_result = test_result && expected_format == res.format; + if (has_f0_res) { + for (const auto& res : pucch_cfg.pucch_res_list) { + const unsigned extra_set_0_res = has_csi ? 2U : 1U; + const pucch_format expected_format = res.res_id.ue_res_id < nof_f0_f1_res_harq_per_ue + extra_set_0_res + ? srsran::pucch_format::FORMAT_0 + : srsran::pucch_format::FORMAT_2; + test_result = test_result && expected_format == res.format; + } + } else { + for (const auto& res : pucch_cfg.pucch_res_list) { + const pucch_format expected_format = res.res_id.ue_res_id < nof_f0_f1_res_harq_per_ue + 1U + ? srsran::pucch_format::FORMAT_1 + : srsran::pucch_format::FORMAT_2; + test_result = test_result && expected_format == res.format; + } } - // Check SR and related PUCCH resource. - test_result = test_result and pucch_cfg.sr_res_list.size() == 1; - const pucch_res_id_t sr_pucch_res_id = pucch_cfg.sr_res_list.front().pucch_res_id; - // Check the PUCCH resouce ID for SR is correct. - const bool sr_cell_res_id_test = - sr_pucch_res_id.cell_res_id == (nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + sr_idx); - const bool sr_ue_res_id_test = sr_pucch_res_id.ue_res_id == nof_f0_f1_res_harq_per_ue; - test_result = test_result and sr_cell_res_id_test and sr_ue_res_id_test; - // Check the PUCCH resouce for SR present in the list. - const auto* res_it = get_pucch_resource_with_id(pucch_cfg.sr_res_list.front().pucch_res_id); - test_result = test_result and res_it != pucch_cfg.pucch_res_list.end(); - const auto& sr_pucch_res_cfg = *res_it; - - // Check SR and related PUCCH resource. - srsran_assert(serv_cell_cfg.csi_meas_cfg.has_value(), "CSI meas config is expected to be present"); - auto& csi_cfg = serv_cell_cfg.csi_meas_cfg.value(); - srsran_assert(serv_cell_cfg.csi_meas_cfg.has_value(), "CSI meas config is expected to be present"); - srsran_assert(not csi_cfg.csi_report_cfg_list.empty() and - std::holds_alternative( - csi_cfg.csi_report_cfg_list.front().report_cfg_type) and - not std::get( - csi_cfg.csi_report_cfg_list.front().report_cfg_type) - .pucch_csi_res_list.empty(), - "PUCCH-CSI-ResourceList has not been configured in the CSI-reportConfig"); - - const pucch_res_id_t csi_res_id = std::get( - csi_cfg.csi_report_cfg_list.front().report_cfg_type) - .pucch_csi_res_list.front() - .pucch_res_id; - - // Check the PUCCH resouce ID for CSI is correct. - const bool csi_cell_res_id_test = - csi_res_id.cell_res_id == nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * nof_harq_cfg_per_ue + csi_idx; - const bool csi_ue_res_id_test = csi_res_id.ue_res_id == nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue; - test_result = test_result and csi_cell_res_id_test and csi_ue_res_id_test; - // Check the PUCCH resouce for SR present in the list. - res_it = get_pucch_resource_with_id(csi_res_id); - test_result = test_result and res_it != pucch_cfg.pucch_res_list.end(); - const auto& csi_pucch_res_cfg = *res_it; - if (has_f0_res) { srsran_assert(sr_pucch_res_cfg.format == pucch_format::FORMAT_0 and std::holds_alternative(sr_pucch_res_cfg.format_params), "SR PUCCH resource must be of Format 0 if any of the PUCCH resources from set 0 has Format 0."); - srsran_assert(csi_pucch_res_cfg.format == pucch_format::FORMAT_2 and - std::holds_alternative(csi_pucch_res_cfg.format_params), - "CSI PUCCH resource must be of Format 2"); - const auto& sr_pucch_cfg = std::get(sr_pucch_res_cfg.format_params); - const auto& csi_pucch_cfg = std::get(csi_pucch_res_cfg.format_params); - ofdm_symbol_range sr_symbols{sr_pucch_cfg.starting_sym_idx, - sr_pucch_cfg.starting_sym_idx + sr_pucch_cfg.nof_symbols}; - ofdm_symbol_range csi_symbols{csi_pucch_cfg.starting_sym_idx, - csi_pucch_cfg.starting_sym_idx + csi_pucch_cfg.nof_symbols}; - test_result = test_result and sr_symbols.overlaps(csi_symbols); + const auto& sr_pucch_params_cfg = std::get(sr_pucch_res_cfg.format_params); + + const auto harq_res_set_0_for_sr_idx = + pucch_cfg.pucch_res_set[0].pucch_res_id_list[pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() - 1]; + const auto harq_res_set_0_for_sr = pucch_cfg.pucch_res_list[harq_res_set_0_for_sr_idx.ue_res_id]; + test_result = test_result and harq_res_set_0_for_sr == sr_pucch_res_cfg; + + const unsigned extra_set_1_res = has_csi ? 2U : 1U; + const auto harq_res_set_1_for_sr_idx = + pucch_cfg.pucch_res_set[1] + .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - extra_set_1_res]; + const auto harq_res_set_1_for_sr = pucch_cfg.pucch_res_list[harq_res_set_1_for_sr_idx.ue_res_id]; + const auto& harq_res_set_1_for_sr_params = std::get(harq_res_set_1_for_sr.format_params); + test_result = test_result and harq_res_set_1_for_sr.starting_prb == sr_pucch_res_cfg.starting_prb and + harq_res_set_1_for_sr.second_hop_prb == sr_pucch_res_cfg.second_hop_prb and + harq_res_set_1_for_sr_params.starting_sym_idx == sr_pucch_params_cfg.starting_sym_idx and + harq_res_set_1_for_sr_params.nof_symbols == sr_pucch_params_cfg.nof_symbols; + + if (has_csi) { + const pucch_res_id_t csi_res_id = + std::get( + serv_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list.front().report_cfg_type) + .pucch_csi_res_list.front() + .pucch_res_id; + + const auto* csi_it = get_pucch_resource_with_id(csi_res_id); + srsran_assert(csi_it != pucch_cfg.pucch_res_list.end(), + "CSI PUCCH resource not found in the PUCCH resource list"); + const auto& csi_pucch_res_cfg = *csi_it; + + srsran_assert(csi_pucch_res_cfg.format == pucch_format::FORMAT_2 and + std::holds_alternative(csi_pucch_res_cfg.format_params), + "CSI PUCCH resource must be of Format 2"); + const auto& csi_pucch_params_cfg = std::get(csi_pucch_res_cfg.format_params); + + const auto harq_res_set_1_for_csi_idx = + pucch_cfg.pucch_res_set[1].pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - 1]; + const auto harq_res_set_1_for_csi = pucch_cfg.pucch_res_list[harq_res_set_1_for_csi_idx.ue_res_id]; + test_result = test_result and harq_res_set_1_for_csi == csi_pucch_res_cfg; + + const auto harq_res_set_0_for_csi_idx = + pucch_cfg.pucch_res_set[0].pucch_res_id_list[pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() - 2U]; + const auto harq_res_set_0_for_csi = pucch_cfg.pucch_res_list[harq_res_set_0_for_csi_idx.ue_res_id]; + const auto& harq_res_set_0_for_csi_params = std::get(harq_res_set_0_for_csi.format_params); + test_result = test_result and harq_res_set_0_for_csi.starting_prb == csi_pucch_res_cfg.starting_prb and + harq_res_set_0_for_csi.second_hop_prb == csi_pucch_res_cfg.second_hop_prb and + harq_res_set_0_for_csi_params.starting_sym_idx == csi_pucch_params_cfg.starting_sym_idx and + harq_res_set_0_for_csi_params.nof_symbols == csi_pucch_params_cfg.nof_symbols; + } } return test_result; @@ -810,15 +952,20 @@ INSTANTIATE_TEST_SUITE_P(ue_pucch_config_builder, pucch_cfg_builder_params{ 0, 5, 2, 10, 2, 7 }, pucch_cfg_builder_params{ 0, 2, 7, 3, 7, 3 }, pucch_cfg_builder_params{ 0, 6, 4, 5, 6, 2 }, - pucch_cfg_builder_params{ 3, 0, 6, 1, 2, 1 }, - pucch_cfg_builder_params{ 7, 0, 3, 1, 1, 1 }, - pucch_cfg_builder_params{ 8, 0, 8, 1, 4, 1 }, + pucch_cfg_builder_params{ 6, 0, 6, 1, 8, 8 }, + pucch_cfg_builder_params{ 5, 0, 3, 1, 1, 1 }, + pucch_cfg_builder_params{ 6, 0, 6, 1, 4, 1 }, pucch_cfg_builder_params{ 2, 0, 2, 1, 1, 1 }, - pucch_cfg_builder_params{ 7, 0, 7, 1, 3, 1 }, - pucch_cfg_builder_params{ 8, 0, 8, 4, 4, 4 }, + pucch_cfg_builder_params{ 3, 0, 5, 1, 3, 1 }, + pucch_cfg_builder_params{ 3, 0, 5, 1, 1, 3 }, + pucch_cfg_builder_params{ 6, 0, 6, 4, 4, 4 }, pucch_cfg_builder_params{ 5, 0, 2, 10, 2, 7 }, - pucch_cfg_builder_params{ 2, 0, 7, 3, 7, 3 }, - pucch_cfg_builder_params{ 6, 0, 4, 5, 6, 2 } + pucch_cfg_builder_params{ 2, 0, 5, 10, 2, 7 }, + pucch_cfg_builder_params{ 2, 0, 5, 10, 7, 2 }, + pucch_cfg_builder_params{ 4, 0, 4, 10, 21, 14 }, + pucch_cfg_builder_params{ 2, 0, 6, 3, 7, 3 }, + pucch_cfg_builder_params{ 6, 0, 4, 5, 6, 2 }, + pucch_cfg_builder_params{ 6, 0, 6, 3, 6, 0 } ) // clang-format on ); From f1c9c3d7ca8fb2352aafb90e952a7bcb91ead04a Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 17 Jul 2024 18:38:15 +0200 Subject: [PATCH 208/407] sched: check pucch_cfg for UE capabilities for F0 Signed-off-by: Carlo Galiotto --- .../config/serving_cell_config_validator.cpp | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index 047a63a579..1a7ab47ec4 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -234,6 +234,35 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(pucch_res_sr->format == pucch_format::FORMAT_0 or pucch_res_sr->format == pucch_format::FORMAT_1, "PUCCH resource used for SR is expected to be Format 0 or Format 1"); + // With Format 0, the last resource in PUCCH resource set 1 should point at the SR resource. Also, the last (or second + // last if there is CSI) resource in PUCCH resource set 1 should have symbols and starting PRBs that match those of + // the SR resource. + if (has_format_0) { + const auto* last_res_in_set_0 = + get_pucch_resource_with_id(pucch_cfg.pucch_res_set[0].pucch_res_id_list.back().cell_res_id); + VERIFY(pucch_cfg.pucch_res_list.end() != last_res_in_set_0 and + last_res_in_set_0->res_id == pucch_cfg.sr_res_list.front().pucch_res_id, + "With Format 0, the last PUCCH resource in PUCCH resource set 0 should point at the SR resource"); + const unsigned offset_due_to_csi = ue_cell_cfg.csi_meas_cfg.has_value() ? 2U : 1U; + const auto* harq_res_in_set_1_for_sr = get_pucch_resource_with_id( + pucch_cfg.pucch_res_set[1] + .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - offset_due_to_csi] + .cell_res_id); + VERIFY(pucch_cfg.pucch_res_list.end() != harq_res_in_set_1_for_sr and + harq_res_in_set_1_for_sr->format == pucch_format::FORMAT_2 and + std::holds_alternative(harq_res_in_set_1_for_sr->format_params), + "With Format 0, PUCCH resource set 1 should contain a reserved HARQ-ACK resource for SR slots of Format 2"); + const auto& sr_pucch_params_cfg = std::get(pucch_res_sr->format_params); + const auto& harq_res_in_set_1_for_sr_params = + std::get(harq_res_in_set_1_for_sr->format_params); + VERIFY(harq_res_in_set_1_for_sr->starting_prb == pucch_res_sr->starting_prb and + harq_res_in_set_1_for_sr->second_hop_prb == pucch_res_sr->second_hop_prb and + harq_res_in_set_1_for_sr_params.starting_sym_idx == sr_pucch_params_cfg.starting_sym_idx and + harq_res_in_set_1_for_sr_params.nof_symbols == sr_pucch_params_cfg.nof_symbols, + "With Format 0, PUCCH resource set 1 should contain a resource Format 2 reserved for HARQ-ACK with symbols " + " and starting PRBs that match the SR resource"); + } + // Verify that the PUCCH setting used for CSI report have been configured properly. if (ue_cell_cfg.csi_meas_cfg.has_value()) { const auto& csi_cfg = ue_cell_cfg.csi_meas_cfg.value(); @@ -295,8 +324,8 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel const unsigned uci_bits_harq_resource = csi_report_size + harq_bits_mplexed_with_csi + sr_bits_mplexed_with_csi; const unsigned pucch_res_set_idx_for_f2 = 1; for (pucch_res_id_t res_idx : pucch_cfg.pucch_res_set[pucch_res_set_idx_for_f2].pucch_res_id_list) { - const auto* res_f2_it = get_pucch_resource_with_id(res_idx.cell_res_id); - const auto& harq_f2_pucch_res_params = std::get(res_f2_it->format_params); + const auto* csi_res_f2 = get_pucch_resource_with_id(res_idx.cell_res_id); + const auto& harq_f2_pucch_res_params = std::get(csi_res_f2->format_params); const unsigned pucch_harq_f2_max_payload = get_pucch_format2_max_payload(harq_f2_pucch_res_params.nof_prbs, harq_f2_pucch_res_params.nof_symbols, @@ -305,6 +334,34 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel "UCI num. of bits ({}) exceeds the maximum HARQ-ACK's PUCCH Format 2 payload ({})", uci_bits_harq_resource, pucch_harq_f2_max_payload); + + // With Format 0 and CSI, the last resource in PUCCH resource set 1 should point at the CSI resource. Also, the + // second last resource in PUCCH resource set 0 should have symbols and starting PRBs that match those of the CSI + // resource. + if (has_format_0) { + const auto* last_res_in_set_1 = + get_pucch_resource_with_id(pucch_cfg.pucch_res_set[1].pucch_res_id_list.back().cell_res_id); + VERIFY( + pucch_cfg.pucch_res_list.end() != last_res_in_set_1 and last_res_in_set_1->res_id == csi_res_f2->res_id, + "With Format 0 and CSI, the last PUCCH resource in PUCCH resource set 1 should point at the CSI resource"); + + const auto* harq_res_in_set_0_for_csi = + get_pucch_resource_with_id(pucch_cfg.pucch_res_set[1] + .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - 2U] + .cell_res_id); + VERIFY(pucch_cfg.pucch_res_list.end() != harq_res_in_set_0_for_csi and + harq_res_in_set_0_for_csi->format == pucch_format::FORMAT_0 and + std::holds_alternative(harq_res_in_set_0_for_csi->format_params), + "With Format 0, PUCCH resource set 0 should contain a F2 HARQ-ACK resource reserved for CSI slots"); + const auto& harq_res_in_set_0_for_csi_params = + std::get(harq_res_in_set_0_for_csi->format_params); + VERIFY(harq_res_in_set_0_for_csi->starting_prb == csi_res_f2->starting_prb and + harq_res_in_set_0_for_csi->second_hop_prb == csi_res_f2->second_hop_prb and + harq_res_in_set_0_for_csi_params.starting_sym_idx == harq_f2_pucch_res_params.starting_sym_idx and + harq_res_in_set_0_for_csi_params.nof_symbols == harq_f2_pucch_res_params.nof_symbols, + "With Format 0, PUCCH resource set 0 should contain a F0 resource reserved for HARQ-ACK with symbols " + " and starting PRBs that match the CSI resource"); + } } } From 0cb4d30981afe51aaebe59a9deee6cffde521b61 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 17 Jul 2024 18:40:18 +0200 Subject: [PATCH 209/407] du: remove outdated unittest Signed-off-by: Carlo Galiotto --- .../flexible_du/du_high/du_high_config.h | 7 +- .../du_high/du_high_config_translators.cpp | 20 ++- .../config/serving_cell_config_validator.cpp | 96 ++++++------ .../du_ran_resource_manager_test.cpp | 142 ------------------ 4 files changed, 68 insertions(+), 197 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 d4c4e8dd17..fb01cedf84 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -213,12 +213,13 @@ struct du_high_unit_pucch_config { unsigned pucch_resource_common = 11; /// \c PUCCH-Config parameters. - /// Number of PUCCH resources per UE for HARQ-ACK reporting. Values {1,...,8}. + /// Force Format 0 for the PUCCH resources belonging to PUCCH resource set 0. + bool use_format_0 = false; + /// Number of PUCCH resources per UE for HARQ-ACK reporting. + /// Values {3,...,8} if \c use_format_0 is set. Else, Values {1,...,8}. /// \remark We assume the number of PUCCH F0/F1 resources for HARQ-ACK is equal to the equivalent number of Format 2 /// resources. unsigned nof_ue_pucch_res_harq_per_set = 8; - /// Force Format 0 for the PUCCH resources belonging to PUCCH resource set 0. - bool use_format_0 = false; /// \brief Number of separate PUCCH resource sets for HARQ-ACK reporting that are available in a cell. /// \remark UEs will be distributed possibly over different HARQ-ACK PUCCH sets; the more sets, the fewer UEs will /// have to share the same set, which reduces the chances that UEs won't be allocated PUCCH due to lack of 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 6478f25c4b..29979ecd8f 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 @@ -508,19 +508,23 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c // Parameters for PUCCH-Config builder (these parameters will be used later on to generate the PUCCH resources). pucch_builder_params& du_pucch_cfg = out_cell.pucch_cfg; const du_high_unit_pucch_config& user_pucch_cfg = base_cell.pucch_cfg; - du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; - du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; du_pucch_cfg.nof_cell_harq_pucch_res_sets = user_pucch_cfg.nof_cell_harq_pucch_sets; du_pucch_cfg.nof_sr_resources = user_pucch_cfg.nof_cell_sr_resources; du_pucch_cfg.nof_csi_resources = user_pucch_cfg.nof_cell_csi_resources; if (user_pucch_cfg.use_format_0) { - auto& f0_params = du_pucch_cfg.f0_or_f1_params.emplace(); - f0_params.intraslot_freq_hopping = user_pucch_cfg.f0_intraslot_freq_hopping; + auto& f0_params = du_pucch_cfg.f0_or_f1_params.emplace(); + // Subtract 2 PUCCH resources from value: with Format 0, 2 extra resources will be added by the DU resource + // allocator when the DU create the UE configuration. + du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; + du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; + f0_params.intraslot_freq_hopping = user_pucch_cfg.f0_intraslot_freq_hopping; } else { - auto& f1_params = du_pucch_cfg.f0_or_f1_params.emplace(); - f1_params.occ_supported = user_pucch_cfg.f1_enable_occ; - f1_params.nof_cyc_shifts = static_cast(user_pucch_cfg.nof_cyclic_shift); - f1_params.intraslot_freq_hopping = user_pucch_cfg.f1_intraslot_freq_hopping; + auto& f1_params = du_pucch_cfg.f0_or_f1_params.emplace(); + du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; + du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; + f1_params.occ_supported = user_pucch_cfg.f1_enable_occ; + f1_params.nof_cyc_shifts = static_cast(user_pucch_cfg.nof_cyclic_shift); + f1_params.intraslot_freq_hopping = user_pucch_cfg.f1_intraslot_freq_hopping; } du_pucch_cfg.f2_params.max_code_rate = user_pucch_cfg.max_code_rate; du_pucch_cfg.f2_params.max_nof_rbs = user_pucch_cfg.f2_max_nof_rbs; diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index 1a7ab47ec4..a1a0de458e 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -142,12 +142,18 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel const auto& pucch_cfg = ue_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(); // Helper to retrives a given PUCCH resource given its ID from the PUCCH resource list. - auto get_pucch_resource_with_id = [&pucch_cfg](unsigned res_id) { + auto get_pucch_resource_with_cell_id = [&pucch_cfg](unsigned res_id) { return std::find_if(pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), [res_id](const pucch_resource& res) { return res.res_id.cell_res_id == res_id; }); }; + auto get_pucch_resource_with_ue_id = [&pucch_cfg](unsigned res_id) { + return std::find_if(pucch_cfg.pucch_res_list.begin(), + pucch_cfg.pucch_res_list.end(), + [res_id](const pucch_resource& res) { return res.res_id.ue_res_id == res_id; }); + }; + // Verify that the PUCCH resources IDs of each PUCCH resource set point at a corresponding item in the PUCCH reource // list. VERIFY(pucch_cfg.pucch_res_set.size() >= 2, "At least 2 PUCCH resource sets need to be configured in PUCCH-Config"); @@ -159,7 +165,7 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel "PUCCH resource sets 0 and 1 are expected to have a non-empty set of PUCCH resource id"); for (size_t pucch_res_set_idx = 0; pucch_res_set_idx != 2; ++pucch_res_set_idx) { for (auto res_idx : pucch_cfg.pucch_res_set[pucch_res_set_idx].pucch_res_id_list) { - const auto* pucch_res_it = get_pucch_resource_with_id(res_idx.cell_res_id); + const auto* pucch_res_it = get_pucch_resource_with_cell_id(res_idx.cell_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != pucch_res_it, "PUCCH cell res. id={} in PUCCH res. set id={} not found in the PUCCH resource list", res_idx.cell_res_id, @@ -209,13 +215,13 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel // Check PUCCH Formats for each PUCCH Resource Set. for (auto res_idx : pucch_cfg.pucch_res_set[0].pucch_res_id_list) { - const auto* pucch_res_it = get_pucch_resource_with_id(res_idx.cell_res_id); + const auto* pucch_res_it = get_pucch_resource_with_ue_id(res_idx.ue_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != pucch_res_it and (pucch_res_it->format == pucch_format::FORMAT_0 or pucch_res_it->format == pucch_format::FORMAT_1), "Only PUCCH Resource Format 0 or Format 1 expected in PUCCH resource set 0."); } for (auto res_idx : pucch_cfg.pucch_res_set[1].pucch_res_id_list) { - const auto* pucch_res_it = get_pucch_resource_with_id(res_idx.cell_res_id); + const auto* pucch_res_it = get_pucch_resource_with_ue_id(res_idx.ue_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != pucch_res_it and pucch_res_it->format == pucch_format::FORMAT_2, "Only PUCCH Resource Format 2 expected in PUCCH resource set 1."); } @@ -223,11 +229,11 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel // Verify the PUCCH resource id that indicated in the SR resource config exists in the PUCCH resource list. VERIFY(pucch_cfg.sr_res_list.size() == 1, "Only SchedulingRequestResourceConfig with size 1 supported"); VERIFY(pucch_cfg.pucch_res_list.end() != - get_pucch_resource_with_id(pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id), + get_pucch_resource_with_cell_id(pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id), "PUCCH cell res. id={} given in SR resource config not found in the PUCCH resource list", pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id); - const auto* pucch_res_sr = get_pucch_resource_with_id(pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id); + const auto* pucch_res_sr = get_pucch_resource_with_cell_id(pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != pucch_res_sr, "PUCCH cell res. id={} for SR could not be found in PUCCH resource list", pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id); @@ -239,15 +245,17 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel // the SR resource. if (has_format_0) { const auto* last_res_in_set_0 = - get_pucch_resource_with_id(pucch_cfg.pucch_res_set[0].pucch_res_id_list.back().cell_res_id); + get_pucch_resource_with_cell_id(pucch_cfg.pucch_res_set[0].pucch_res_id_list.back().cell_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != last_res_in_set_0 and last_res_in_set_0->res_id == pucch_cfg.sr_res_list.front().pucch_res_id, "With Format 0, the last PUCCH resource in PUCCH resource set 0 should point at the SR resource"); - const unsigned offset_due_to_csi = ue_cell_cfg.csi_meas_cfg.has_value() ? 2U : 1U; - const auto* harq_res_in_set_1_for_sr = get_pucch_resource_with_id( + const unsigned offset_due_to_csi = ue_cell_cfg.csi_meas_cfg.has_value() ? 2U : 1U; + // The harq_res_in_set_1_for_sr is only created in the UE, it doesn't exist in the cell list of resources. Use the + // ue_res_id to find it. + const auto* harq_res_in_set_1_for_sr = get_pucch_resource_with_ue_id( pucch_cfg.pucch_res_set[1] .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - offset_due_to_csi] - .cell_res_id); + .ue_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != harq_res_in_set_1_for_sr and harq_res_in_set_1_for_sr->format == pucch_format::FORMAT_2 and std::holds_alternative(harq_res_in_set_1_for_sr->format_params), @@ -278,15 +286,14 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel csi_cfg.csi_report_cfg_list.front().report_cfg_type); const unsigned csi_res_id = csi.pucch_csi_res_list.front().pucch_res_id.cell_res_id; // Verify the PUCCH resource id that indicated in the CSI resource config exists in the PUCCH resource list. - const auto* csi_pucch_res_id = get_pucch_resource_with_id(csi_res_id); - VERIFY(csi_pucch_res_id != pucch_cfg.pucch_res_list.end(), + const auto* csi_pucch_res = get_pucch_resource_with_cell_id(csi_res_id); + VERIFY(csi_pucch_res != pucch_cfg.pucch_res_list.end(), "PUCCH cell res. id={} given in PUCCH-CSI-resourceList not found in the PUCCH resource list", csi_res_id); - VERIFY(csi_pucch_res_id->format == pucch_format::FORMAT_2, - "PUCCH resource used for CSI is expected to be Format 2"); + VERIFY(csi_pucch_res->format == pucch_format::FORMAT_2, "PUCCH resource used for CSI is expected to be Format 2"); // Verify the CSI/SR bits do not exceed the PUCCH F2 payload. - const auto& csi_pucch_res_params = std::get(csi_pucch_res_id->format_params); + const auto& csi_pucch_res_params = std::get(csi_pucch_res->format_params); const unsigned pucch_f2_max_payload = get_pucch_format2_max_payload(csi_pucch_res_params.nof_prbs, csi_pucch_res_params.nof_symbols, @@ -324,8 +331,8 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel const unsigned uci_bits_harq_resource = csi_report_size + harq_bits_mplexed_with_csi + sr_bits_mplexed_with_csi; const unsigned pucch_res_set_idx_for_f2 = 1; for (pucch_res_id_t res_idx : pucch_cfg.pucch_res_set[pucch_res_set_idx_for_f2].pucch_res_id_list) { - const auto* csi_res_f2 = get_pucch_resource_with_id(res_idx.cell_res_id); - const auto& harq_f2_pucch_res_params = std::get(csi_res_f2->format_params); + const auto* res_f2 = get_pucch_resource_with_ue_id(res_idx.ue_res_id); + const auto& harq_f2_pucch_res_params = std::get(res_f2->format_params); const unsigned pucch_harq_f2_max_payload = get_pucch_format2_max_payload(harq_f2_pucch_res_params.nof_prbs, harq_f2_pucch_res_params.nof_symbols, @@ -334,34 +341,35 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel "UCI num. of bits ({}) exceeds the maximum HARQ-ACK's PUCCH Format 2 payload ({})", uci_bits_harq_resource, pucch_harq_f2_max_payload); + } - // With Format 0 and CSI, the last resource in PUCCH resource set 1 should point at the CSI resource. Also, the - // second last resource in PUCCH resource set 0 should have symbols and starting PRBs that match those of the CSI - // resource. - if (has_format_0) { - const auto* last_res_in_set_1 = - get_pucch_resource_with_id(pucch_cfg.pucch_res_set[1].pucch_res_id_list.back().cell_res_id); - VERIFY( - pucch_cfg.pucch_res_list.end() != last_res_in_set_1 and last_res_in_set_1->res_id == csi_res_f2->res_id, - "With Format 0 and CSI, the last PUCCH resource in PUCCH resource set 1 should point at the CSI resource"); - - const auto* harq_res_in_set_0_for_csi = - get_pucch_resource_with_id(pucch_cfg.pucch_res_set[1] - .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - 2U] - .cell_res_id); - VERIFY(pucch_cfg.pucch_res_list.end() != harq_res_in_set_0_for_csi and - harq_res_in_set_0_for_csi->format == pucch_format::FORMAT_0 and - std::holds_alternative(harq_res_in_set_0_for_csi->format_params), - "With Format 0, PUCCH resource set 0 should contain a F2 HARQ-ACK resource reserved for CSI slots"); - const auto& harq_res_in_set_0_for_csi_params = - std::get(harq_res_in_set_0_for_csi->format_params); - VERIFY(harq_res_in_set_0_for_csi->starting_prb == csi_res_f2->starting_prb and - harq_res_in_set_0_for_csi->second_hop_prb == csi_res_f2->second_hop_prb and - harq_res_in_set_0_for_csi_params.starting_sym_idx == harq_f2_pucch_res_params.starting_sym_idx and - harq_res_in_set_0_for_csi_params.nof_symbols == harq_f2_pucch_res_params.nof_symbols, - "With Format 0, PUCCH resource set 0 should contain a F0 resource reserved for HARQ-ACK with symbols " - " and starting PRBs that match the CSI resource"); - } + // With Format 0 and CSI, the last resource in PUCCH resource set 1 should point at the CSI resource. Also, the + // second last resource in PUCCH resource set 0 should have symbols and starting PRBs that match those of the CSI + // resource. + if (has_format_0) { + const auto* last_res_in_set_1 = + get_pucch_resource_with_ue_id(pucch_cfg.pucch_res_set[1].pucch_res_id_list.back().ue_res_id); + VERIFY(pucch_cfg.pucch_res_list.end() != last_res_in_set_1 and last_res_in_set_1->res_id == csi_pucch_res->res_id, + "With Format 0 and CSI, the last PUCCH resource in PUCCH resource set 1 should point at the CSI resource"); + + // The harq_res_in_set_1_for_sr is only created in the UE, it doesn't exist in the cell list of resources. Use + // the ue_res_id to find it. + const auto* harq_res_in_set_0_for_csi = + get_pucch_resource_with_ue_id(pucch_cfg.pucch_res_set[0] + .pucch_res_id_list[pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() - 2U] + .ue_res_id); + VERIFY(pucch_cfg.pucch_res_list.end() != harq_res_in_set_0_for_csi and + harq_res_in_set_0_for_csi->format == pucch_format::FORMAT_0 and + std::holds_alternative(harq_res_in_set_0_for_csi->format_params), + "With Format 0, PUCCH resource set 0 should contain a F2 HARQ-ACK resource reserved for CSI slots"); + const auto& harq_res_in_set_0_for_csi_params = + std::get(harq_res_in_set_0_for_csi->format_params); + VERIFY(harq_res_in_set_0_for_csi->starting_prb == csi_pucch_res->starting_prb and + harq_res_in_set_0_for_csi->second_hop_prb == csi_pucch_res->second_hop_prb and + harq_res_in_set_0_for_csi_params.starting_sym_idx == csi_pucch_res_params.starting_sym_idx and + harq_res_in_set_0_for_csi_params.nof_symbols == csi_pucch_res_params.nof_symbols, + "With Format 0, PUCCH resource set 0 should contain a F0 resource reserved for HARQ-ACK with symbols " + " and starting PRBs that match the CSI resource"); } } diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 4ad849d8d4..96514214ad 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -744,145 +744,3 @@ INSTANTIATE_TEST_SUITE_P( ) // clang-format on ); - -static du_cell_config -make_custom_du_cell_config_for_format_0(const pucch_cnt_builder_params& pucch_params_, - const srsran::config_helpers::cell_config_builder_params_extended& params = {}) -{ - du_cell_config du_cfg = config_helpers::make_default_du_cell_config(params); - auto& pucch_params = du_cfg.pucch_cfg; - pucch_params.nof_sr_resources = pucch_params_.nof_res_sr; - pucch_params.nof_csi_resources = pucch_params_.nof_res_csi; - pucch_params.f0_or_f1_params.emplace(); - - du_cfg.ue_ded_serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg->sr_res_list[0].period = pucch_params_.sr_period; - if (du_cfg.ue_ded_serv_cell_cfg.csi_meas_cfg.has_value()) { - std::get( - du_cfg.ue_ded_serv_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list[0].report_cfg_type) - .report_slot_period = pucch_params_.csi_period; - } - - auto& pucch_res_list = du_cfg.ue_ded_serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value().pucch_res_list; - for (auto& res : pucch_res_list) { - if (res.format == srsran::pucch_format::FORMAT_1) { - res.format = srsran::pucch_format::FORMAT_0; - res.format_params.emplace(); - } - } - - return du_cfg; -} - -class du_ran_res_mng_pucch_format_0_tester : public du_ran_resource_manager_tester_base, - public ::testing::TestWithParam -{ -protected: - explicit du_ran_res_mng_pucch_format_0_tester(cell_config_builder_params params_ = {.dl_arfcn = 520002U}) : - du_ran_resource_manager_tester_base(params_, - make_custom_du_cell_config_for_format_0(GetParam(), params_), - GetParam().max_allowed_pucch_grants) - { - srsran_assert(default_ue_cell_cfg.csi_meas_cfg.has_value() and - not default_ue_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list.empty() and - std::holds_alternative( - default_ue_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list[0].report_cfg_type), - "CSI report configuration is required for this unittest;"); - } - - unsigned lcm_csi_sr_period; - std::vector pucch_cnts; -}; - -TEST_P(du_ran_res_mng_pucch_format_0_tester, sr_and_csi_pucch_resources_have_overlapping_symbols) -{ - du_ue_index_t next_ue_index = to_du_ue_index(0); - - // > Created UEs have unique (PUCCH resource, SR offset) pairs. - std::set> sr_offsets; - std::set> csi_offsets; - for (unsigned i = 0; i != 2; ++i) { - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - if (ue_res.empty()) { - ues.erase(next_ue_index); - break; - } - ASSERT_FALSE(ue_res.empty()); - - // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; - ASSERT_FALSE(sr_res_list.empty()); - ASSERT_EQ(sr_offsets.count(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)), 0); - sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); - unsigned sr_offset = sr_res_list[0].offset; - const auto& sr_pucch_res_cfg = ue_res->cells[0] - .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() - .pucch_res_list[sr_res_list[0].pucch_res_id.ue_res_id]; - ASSERT_TRUE(sr_pucch_res_cfg.format == pucch_format::FORMAT_0); - ASSERT_TRUE(std::holds_alternative(sr_pucch_res_cfg.format_params)); - - // Check if the CSI has been assigned to the UE. - ASSERT_TRUE(has_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg)); - const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg); - ASSERT_FALSE(ue_csi_cfg.pucch_csi_res_list.empty()); - const unsigned csi_pucch_res_id = ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.cell_res_id; - const unsigned csi_offset = ue_csi_cfg.report_slot_offset; - ASSERT_EQ(csi_offsets.count(std::make_pair(csi_pucch_res_id, csi_offset)), 0); - csi_offsets.insert(std::make_pair(csi_pucch_res_id, csi_offset)); - const auto& csi_pucch_res_cfg = ue_res->cells[0] - .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() - .pucch_res_list[ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.ue_res_id]; - ASSERT_TRUE(csi_pucch_res_cfg.format == pucch_format::FORMAT_2); - ASSERT_TRUE(std::holds_alternative(csi_pucch_res_cfg.format_params)); - - // Check the offsets results in the SR and CSI not exceeding the max PUCCH grants. - std::set csi_sr_offset_for_pucch_cnt; - for (unsigned sr_off = sr_offset; sr_off < lcm_csi_sr_period; sr_off += get_config_sr_period()) { - csi_sr_offset_for_pucch_cnt.emplace(sr_off); - } - - for (unsigned csi_off = csi_offset; csi_off < lcm_csi_sr_period; csi_off += get_config_csi_period()) { - csi_sr_offset_for_pucch_cnt.emplace(csi_off); - } - - for (auto offset : csi_sr_offset_for_pucch_cnt) { - srsran_assert(offset < static_cast(pucch_cnts.size()), - "Index exceeds the size of the PUCCH grants vector"); - ++pucch_cnts[offset]; - } - - for (auto pucch_slot_cnt : pucch_cnts) { - ASSERT_TRUE(pucch_slot_cnt <= GetParam().max_allowed_pucch_grants); - } - - const auto& sr_pucch_cfg = std::get(sr_pucch_res_cfg.format_params); - const auto& csi_pucch_cfg = std::get(csi_pucch_res_cfg.format_params); - ofdm_symbol_range sr_symbols{sr_pucch_cfg.starting_sym_idx, - sr_pucch_cfg.starting_sym_idx + sr_pucch_cfg.nof_symbols}; - ofdm_symbol_range csi_symbols{csi_pucch_cfg.starting_sym_idx, - csi_pucch_cfg.starting_sym_idx + csi_pucch_cfg.nof_symbols}; - ASSERT_TRUE(sr_symbols.overlaps(csi_symbols)); - - next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); - } - - // Erase a random UE and attempt. - const du_ue_index_t ue_idx_to_rem = to_du_ue_index(test_rgen::uniform_int(0, ues.size() - 1)); - ues.erase(ue_idx_to_rem); - - // Attempt a new allocation and verify it is successful. - next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); -} - -INSTANTIATE_TEST_SUITE_P( - parametrized_test_for_format_0, - du_ran_res_mng_pucch_format_0_tester, - // clang-format off - ::testing::Values( - pucch_cnt_builder_params{ 7, 7, 15, srsran::sr_periodicity::sl_10, srsran::csi_report_periodicity::slots10 }, - pucch_cnt_builder_params{ 9, 9, 18, srsran::sr_periodicity::sl_20, srsran::csi_report_periodicity::slots20 }, - pucch_cnt_builder_params{ 11, 11, 22, srsran::sr_periodicity::sl_20, srsran::csi_report_periodicity::slots20 } - ) - // clang-format on -); \ No newline at end of file From a12e4f57dd566d0760119a00ed5daee1a0692ed8 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 18 Jul 2024 14:13:54 +0200 Subject: [PATCH 210/407] du,sched: with F0, invert pos of last 2 pucch res Signed-off-by: Carlo Galiotto --- include/srsran/du/du_cell_config.h | 2 +- .../pucch_resource_generator.cpp | 56 +++++++++---------- .../config/serving_cell_config_validator.cpp | 27 +++++---- .../pucch_scheduling/pucch_allocator_impl.cpp | 22 +++++--- .../pucch_resource_generator_test.cpp | 36 ++++++------ .../pucch_alloc_harq_sr_csi_test.cpp | 16 +++++- 6 files changed, 90 insertions(+), 69 deletions(-) diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index b833d95023..9dc21b183e 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -73,7 +73,7 @@ struct pucch_builder_params { /// UE specific parameters. Use to set the number of resources per UE for HARQ-ACK reporting (not including SR/CSI /// dedicated resources). NOTE: by default, each UE is assigned 1 SR and 1 CSI resource. /// \remark Format 0 and Format 1 resources are mutually exclusive. - bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 7; + bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 6; bounded_integer nof_ue_pucch_f2_res_harq = 6; /// \brief Number of separate PUCCH resource sets for HARQ-ACK reporting that are available in a cell. /// \remark UEs will be distributed possibly over different HARQ-ACK PUCCH sets; the more sets, the fewer UEs will diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp index e5339ee367..cc5fa459f5 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -802,27 +802,6 @@ bool srsran::srs_du::ue_pucch_config_builder( ++ue_pucch_res_id; } - const unsigned f2_res_on_sr_prbs_syms_idx = ue_pucch_res_id; - if (is_format_0) { - // Add PUCCH resource to pucch_res_list. - pucch_cfg.pucch_res_list.emplace_back(pucch_resource{ - .res_id = {std::numeric_limits::max(), ue_pucch_res_id}, .format = pucch_format::FORMAT_2}); - - // Add PUCCH resource index to pucch_res_id_list of PUCCH resource set id=0. - pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.emplace_back( - pucch_res_id_t{std::numeric_limits::max(), ue_pucch_res_id}); - - // Increment the PUCCH resource ID for ASN1 message. - ++ue_pucch_res_id; - - auto& f2_harq_on_sr_resources = pucch_cfg.pucch_res_list[f2_res_on_sr_prbs_syms_idx]; - f2_harq_on_sr_resources.starting_prb = sr_cell_res.starting_prb; - f2_harq_on_sr_resources.second_hop_prb = sr_cell_res.second_hop_prb; - const auto& sr_params_cfg = std::get(sr_cell_res.format_params); - f2_harq_on_sr_resources.format_params.emplace(pucch_format_2_3_cfg{ - .nof_prbs = 1U, .nof_symbols = sr_params_cfg.nof_symbols, .starting_sym_idx = sr_params_cfg.starting_sym_idx}); - } - if (serv_cell_cfg.csi_meas_cfg.has_value()) { // Add CSI resource. const unsigned csi_res_idx = @@ -844,13 +823,13 @@ bool srsran::srs_du::ue_pucch_config_builder( ++ue_pucch_res_id; if (is_format_0) { - auto& last_harq_res_set_1 = pucch_cfg.pucch_res_list.back(); - last_harq_res_set_1.res_id.cell_res_id = csi_cell_res.res_id.cell_res_id; - last_harq_res_set_1.res_id.ue_res_id = ue_pucch_res_id_for_csi; - last_harq_res_set_1.starting_prb = csi_cell_res.starting_prb; - last_harq_res_set_1.second_hop_prb = csi_cell_res.second_hop_prb; - last_harq_res_set_1.format = csi_cell_res.format; - last_harq_res_set_1.format_params = csi_cell_res.format_params; + auto& harq_set_1_res_for_csi = pucch_cfg.pucch_res_list.back(); + harq_set_1_res_for_csi.res_id.cell_res_id = csi_cell_res.res_id.cell_res_id; + harq_set_1_res_for_csi.res_id.ue_res_id = ue_pucch_res_id_for_csi; + harq_set_1_res_for_csi.starting_prb = csi_cell_res.starting_prb; + harq_set_1_res_for_csi.second_hop_prb = csi_cell_res.second_hop_prb; + harq_set_1_res_for_csi.format = csi_cell_res.format; + harq_set_1_res_for_csi.format_params = csi_cell_res.format_params; pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.emplace_back( pucch_res_id_t{csi_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_csi}); @@ -864,5 +843,26 @@ bool srsran::srs_du::ue_pucch_config_builder( } } + const unsigned f2_res_on_sr_prbs_syms_idx = ue_pucch_res_id; + if (is_format_0) { + // Add PUCCH resource to pucch_res_list. + pucch_cfg.pucch_res_list.emplace_back(pucch_resource{ + .res_id = {std::numeric_limits::max(), ue_pucch_res_id}, .format = pucch_format::FORMAT_2}); + + // Add PUCCH resource index to pucch_res_id_list of PUCCH resource set id=0. + pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.emplace_back( + pucch_res_id_t{std::numeric_limits::max(), ue_pucch_res_id}); + + // Increment the PUCCH resource ID for ASN1 message. + ++ue_pucch_res_id; + + auto& f2_harq_on_sr_resources = pucch_cfg.pucch_res_list[f2_res_on_sr_prbs_syms_idx]; + f2_harq_on_sr_resources.starting_prb = sr_cell_res.starting_prb; + f2_harq_on_sr_resources.second_hop_prb = sr_cell_res.second_hop_prb; + const auto& sr_params_cfg = std::get(sr_cell_res.format_params); + f2_harq_on_sr_resources.format_params.emplace(pucch_format_2_3_cfg{ + .nof_prbs = 1U, .nof_symbols = sr_params_cfg.nof_symbols, .starting_sym_idx = sr_params_cfg.starting_sym_idx}); + } + return true; } diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index a1a0de458e..fd774958ea 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -213,6 +213,11 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel } VERIFY(pucch_cfg.format_2_common_param.has_value(), "Missing PUCCH-format2 parameters in PUCCH-Config"); + if (has_format_0) { + VERIFY(pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), + "With Format 0, the PUCCH resource sets 0 and 1 must have the same size"); + } + // Check PUCCH Formats for each PUCCH Resource Set. for (auto res_idx : pucch_cfg.pucch_res_set[0].pucch_res_id_list) { const auto* pucch_res_it = get_pucch_resource_with_ue_id(res_idx.ue_res_id); @@ -249,13 +254,10 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(pucch_cfg.pucch_res_list.end() != last_res_in_set_0 and last_res_in_set_0->res_id == pucch_cfg.sr_res_list.front().pucch_res_id, "With Format 0, the last PUCCH resource in PUCCH resource set 0 should point at the SR resource"); - const unsigned offset_due_to_csi = ue_cell_cfg.csi_meas_cfg.has_value() ? 2U : 1U; // The harq_res_in_set_1_for_sr is only created in the UE, it doesn't exist in the cell list of resources. Use the // ue_res_id to find it. - const auto* harq_res_in_set_1_for_sr = get_pucch_resource_with_ue_id( - pucch_cfg.pucch_res_set[1] - .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - offset_due_to_csi] - .ue_res_id); + const auto* harq_res_in_set_1_for_sr = + get_pucch_resource_with_ue_id(pucch_cfg.pucch_res_set[1].pucch_res_id_list.back().ue_res_id); VERIFY(pucch_cfg.pucch_res_list.end() != harq_res_in_set_1_for_sr and harq_res_in_set_1_for_sr->format == pucch_format::FORMAT_2 and std::holds_alternative(harq_res_in_set_1_for_sr->format_params), @@ -343,15 +345,18 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel pucch_harq_f2_max_payload); } - // With Format 0 and CSI, the last resource in PUCCH resource set 1 should point at the CSI resource. Also, the - // second last resource in PUCCH resource set 0 should have symbols and starting PRBs that match those of the CSI - // resource. if (has_format_0) { - const auto* last_res_in_set_1 = - get_pucch_resource_with_ue_id(pucch_cfg.pucch_res_set[1].pucch_res_id_list.back().ue_res_id); - VERIFY(pucch_cfg.pucch_res_list.end() != last_res_in_set_1 and last_res_in_set_1->res_id == csi_pucch_res->res_id, + // With Format 0 and CSI, the second-last resource in PUCCH resource set 1 should point at the CSI resource. + const auto* harq_set_1_res_for_csi = + get_pucch_resource_with_ue_id(pucch_cfg.pucch_res_set[1] + .pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - 2U] + .ue_res_id); + VERIFY(pucch_cfg.pucch_res_list.end() != harq_set_1_res_for_csi and + harq_set_1_res_for_csi->res_id == csi_pucch_res->res_id, "With Format 0 and CSI, the last PUCCH resource in PUCCH resource set 1 should point at the CSI resource"); + // The second-last resource in PUCCH resource set 0 should have symbols and starting PRBs that match those of the + // CSI resource. // The harq_res_in_set_1_for_sr is only created in the UE, it doesn't exist in the cell list of resources. Use // the ue_res_id to find it. const auto* harq_res_in_set_0_for_csi = diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 60778a5e11..8b9b4b4fce 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1444,14 +1444,14 @@ static unsigned get_pucch_resource_ind_f0_sr_csi(pucch_uci_bits bits, const pucc // This if for bits.harq_ack_nof_bits > 2U. - // At position (PUCCH resource set 1 size - 2U) the resource is of Format 2, but set on the same PRBs/symbols as the + // At position (PUCCH resource set 1 size - 1U) the resource is of Format 2, but set on the same PRBs/symbols as the // SR resource. if (bits.sr_bits != sr_nof_bits::no_sr) { - return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.size() - 2U; + return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.size() - 1U; } // NOTE: Either CSI or SR bits are non-zero, but not both. - // At position (PUCCH resource set 1 size - 1U) the resource coincides with the CSI resource. - return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.size() - 1U; + // At position (PUCCH resource set 1 size - 2U) the resource coincides with the CSI resource. + return pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.size() - 2U; } std::optional @@ -1946,9 +1946,12 @@ pucch_allocator_impl::merge_pucch_resources(spanformat != pucch_format::FORMAT_0 and r_harq->format != pucch_format::FORMAT_1) { new_resource = *r_harq; - } else { + } + // NOTE: In this case, the PUCCH resource before merging is from PUCCH resource set 0. + else { + // Get a resource from PUCCH resource set idx 1, if available, with the same PUCCH resource indicator as for + // the PUCCH resource from set idx 0. + const pucch_resource* pucch_res = resource_manager.reserve_set_1_res_by_res_indicator( slot_harq, crnti, r_harq->harq_id.pucch_res_ind, pucch_cfg); resource_manager.set_new_resource_allocation(crnti, pucch_resource_usage::HARQ_SET_1); diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index b3b359d8a0..de81f98ee8 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -695,7 +695,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam(harq_res_set_1_for_sr.format_params); test_result = test_result and harq_res_set_1_for_sr.starting_prb == sr_pucch_res_cfg.starting_prb and @@ -868,7 +865,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam(csi_pucch_res_cfg.format_params); const auto harq_res_set_1_for_csi_idx = - pucch_cfg.pucch_res_set[1].pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - 1]; + pucch_cfg.pucch_res_set[1].pucch_res_id_list[pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() - 2U]; const auto harq_res_set_1_for_csi = pucch_cfg.pucch_res_list[harq_res_set_1_for_csi_idx.ue_res_id]; test_result = test_result and harq_res_set_1_for_csi == csi_pucch_res_cfg; @@ -937,21 +934,22 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) ASSERT_TRUE(verify_nof_res_and_idx(harq_idx_cfg, sr_idx_cfg, csi_idx_cfg)); } -INSTANTIATE_TEST_SUITE_P(ue_pucch_config_builder, - test_ue_pucch_config_builder, - // clang-format off +INSTANTIATE_TEST_SUITE_P( + ue_pucch_config_builder, + test_ue_pucch_config_builder, + // clang-format off // nof: f0 | f1 | f2 | harq | sr | csi // nof: f0 | f1 | f2 | cfg | sr | csi ::testing::Values( - pucch_cfg_builder_params{ 0, 3, 6, 1, 2, 1 }, - pucch_cfg_builder_params{ 0, 7, 3, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 8, 8, 1, 4, 1 }, - pucch_cfg_builder_params{ 0, 1, 1, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 7, 7, 1, 3, 1 }, - pucch_cfg_builder_params{ 0, 8, 8, 4, 4, 4 }, - pucch_cfg_builder_params{ 0, 5, 2, 10, 2, 7 }, - pucch_cfg_builder_params{ 0, 2, 7, 3, 7, 3 }, - pucch_cfg_builder_params{ 0, 6, 4, 5, 6, 2 }, +// pucch_cfg_builder_params{ 0, 3, 6, 1, 2, 1 }, +// pucch_cfg_builder_params{ 0, 7, 3, 1, 1, 1 }, +// pucch_cfg_builder_params{ 0, 8, 8, 1, 4, 1 }, +// pucch_cfg_builder_params{ 0, 1, 1, 1, 1, 1 }, +// pucch_cfg_builder_params{ 0, 7, 7, 1, 3, 1 }, +// pucch_cfg_builder_params{ 0, 8, 8, 4, 4, 4 }, +// pucch_cfg_builder_params{ 0, 5, 2, 10, 2, 7 }, +// pucch_cfg_builder_params{ 0, 2, 7, 3, 7, 3 }, +// pucch_cfg_builder_params{ 0, 6, 4, 5, 6, 2 }, pucch_cfg_builder_params{ 6, 0, 6, 1, 8, 8 }, pucch_cfg_builder_params{ 5, 0, 3, 1, 1, 1 }, pucch_cfg_builder_params{ 6, 0, 6, 1, 4, 1 }, @@ -967,5 +965,5 @@ INSTANTIATE_TEST_SUITE_P(ue_pucch_config_builder, pucch_cfg_builder_params{ 6, 0, 4, 5, 6, 2 }, pucch_cfg_builder_params{ 6, 0, 6, 3, 6, 0 } ) - // clang-format on + // clang-format on ); diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index d484143d3b..7674128b90 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -1659,6 +1659,15 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)] .pucch_res_id_list.size() - 1U), + pucch_res_idx_f0_for_csi(t_bench.get_main_ue() + .get_pcell() + .cfg() + .cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_0)] + .pucch_res_id_list.size() - + 2U), pucch_res_idx_f2_for_sr(t_bench.get_main_ue() .get_pcell() .cfg() @@ -1667,7 +1676,7 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc .init_ul_bwp.pucch_cfg.value() .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)] .pucch_res_id_list.size() - - 2U), + 1U), pucch_res_idx_f2_for_csi(t_bench.get_main_ue() .get_pcell() .cfg() @@ -1676,7 +1685,7 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc .init_ul_bwp.pucch_cfg.value() .pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)] .pucch_res_id_list.size() - - 1U) + 2U) { // Set expected grant for PUCCH Format 0 SR. pucch_expected_f0_sr.format = pucch_format::FORMAT_0; @@ -1738,7 +1747,7 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc pucch_expected_csi.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; pucch_expected_csi.resources.prbs = prb_interval{1, 2}; pucch_expected_csi.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_csi.resources.symbols = ofdm_symbol_range{0, 2}; + pucch_expected_csi.resources.symbols = ofdm_symbol_range{12, 14}; pucch_expected_csi.format_2.max_code_rate = max_pucch_code_rate::dot_25; pucch_expected_csi.format_2.n_id_scambling = t_bench.cell_cfg.pci; @@ -1753,6 +1762,7 @@ class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_alloc pucch_info pucch_expected_f2; pucch_info pucch_expected_csi; const unsigned pucch_res_idx_f0_for_sr; + const unsigned pucch_res_idx_f0_for_csi; const unsigned pucch_res_idx_f2_for_sr; const unsigned pucch_res_idx_f2_for_csi; }; From c02cd2c8ac63d5027fad2003adf1ec2e878ffe60 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 22 Jul 2024 18:23:00 +0200 Subject: [PATCH 211/407] sched: adapt test_mode to PUCCH Format 0 Signed-off-by: Carlo Galiotto --- .../adapters/mac_test_mode_adapter.cpp | 52 +++++++++++++------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/lib/du_high/adapters/mac_test_mode_adapter.cpp b/lib/du_high/adapters/mac_test_mode_adapter.cpp index 07e3dff472..dbabc5bdaf 100644 --- a/lib/du_high/adapters/mac_test_mode_adapter.cpp +++ b/lib/du_high/adapters/mac_test_mode_adapter.cpp @@ -131,6 +131,7 @@ void mac_test_mode_cell_adapter::handle_slot_indication(slot_point sl_tx) mac_uci_pdu& pdu = uci_ind.ucis.emplace_back(); pdu.rnti = pucch.crnti; switch (pucch.format) { + case pucch_format::FORMAT_0: case pucch_format::FORMAT_1: { fill_uci_pdu(pdu.pdu.emplace(), pucch); } break; @@ -211,18 +212,33 @@ void mac_test_mode_cell_adapter::fill_uci_pdu(mac_uci_pdu::pucch_f0_or_f1_type& const pucch_info& pucch) const { pucch_ind.ul_sinr_dB = 100; - if (pucch.format_1.sr_bits != sr_nof_bits::no_sr) { - // In test mode, SRs are never detected, and instead BSR is injected. - pucch_ind.sr_info.emplace(); - pucch_ind.sr_info.value().detected = false; - } - if (pucch.format_1.harq_ack_nof_bits > 0) { - pucch_ind.harq_info.emplace(); - // In case of PUCCH F1 with only HARQ-ACK bits, set all HARQ-ACK bits to ACK. If SR is included, then we - // consider that the PUCCH is not detected. - auto ack_val = pucch.format_1.sr_bits == sr_nof_bits::no_sr ? uci_pucch_f0_or_f1_harq_values::ack - : uci_pucch_f0_or_f1_harq_values::dtx; - pucch_ind.harq_info->harqs.resize(pucch.format_1.harq_ack_nof_bits, ack_val); + srsran_assert(pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1, + "Expected PUCCH Format is F0 or F1"); + if (pucch.format == pucch_format::FORMAT_0) { + // In case of Format 0, the number of PUCCHs is always 1, even if there are SR + HARQ bits. + if (pucch.format_0.sr_bits != sr_nof_bits::no_sr) { + // In test mode, SRs are never detected, and instead BSR is injected. + pucch_ind.sr_info.emplace(); + pucch_ind.sr_info.value().detected = false; + } + if (pucch.format_0.harq_ack_nof_bits > 0) { + pucch_ind.harq_info.emplace(); + pucch_ind.harq_info->harqs.resize(pucch.format_0.harq_ack_nof_bits, uci_pucch_f0_or_f1_harq_values::ack); + } + } else { + if (pucch.format_1.sr_bits != sr_nof_bits::no_sr) { + // In test mode, SRs are never detected, and instead BSR is injected. + pucch_ind.sr_info.emplace(); + pucch_ind.sr_info.value().detected = false; + } + if (pucch.format_1.harq_ack_nof_bits > 0) { + pucch_ind.harq_info.emplace(); + // In case of PUCCH F1 with only HARQ-ACK bits, set all HARQ-ACK bits to ACK. If SR is included, then we + // consider that the PUCCH is not detected. + auto ack_val = pucch.format_1.sr_bits == sr_nof_bits::no_sr ? uci_pucch_f0_or_f1_harq_values::ack + : uci_pucch_f0_or_f1_harq_values::dtx; + pucch_ind.harq_info->harqs.resize(pucch.format_1.harq_ack_nof_bits, ack_val); + } } } @@ -271,13 +287,17 @@ static bool pucch_info_and_uci_ind_match(const pucch_info& pucch, const mac_uci_ if (pucch.crnti != uci_ind.rnti) { return false; } - if (pucch.format == pucch_format::FORMAT_1 and + if ((pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1) and std::holds_alternative(uci_ind.pdu)) { + const auto pucch_pdu_sr_bits = + pucch.format == pucch_format::FORMAT_1 ? pucch.format_1.sr_bits : pucch.format_0.sr_bits; const auto& f1_ind = std::get(uci_ind.pdu); - if (f1_ind.sr_info.has_value() != (pucch.format_1.sr_bits != sr_nof_bits::no_sr)) { + if (f1_ind.sr_info.has_value() != (pucch_pdu_sr_bits != sr_nof_bits::no_sr)) { return false; } - if (f1_ind.harq_info.has_value() != (pucch.format_1.harq_ack_nof_bits > 0)) { + const auto pucch_pdu_harq_bits = + pucch.format == pucch_format::FORMAT_1 ? pucch.format_1.harq_ack_nof_bits : pucch.format_0.harq_ack_nof_bits; + if (f1_ind.harq_info.has_value() != (pucch_pdu_harq_bits > 0)) { return false; } return true; @@ -398,7 +418,7 @@ void mac_test_mode_cell_adapter::handle_uci(const mac_uci_indication_message& ms for (const pucch_info& pucch : entry.pucchs) { if (pucch_info_and_uci_ind_match(pucch, test_uci)) { // Intercept the UCI indication and force HARQ-ACK=ACK and UCI. - if (pucch.format == pucch_format::FORMAT_1) { + if (pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1) { fill_uci_pdu(std::get(test_uci.pdu), pucch); } else { fill_uci_pdu(std::get(test_uci.pdu), pucch); From 9f127ce51c3493c0d81e11f2f33d6cc8bf5852a7 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 9 Aug 2024 13:12:18 +0200 Subject: [PATCH 212/407] du,mac: improve comments Signed-off-by: Carlo Galiotto --- apps/units/flexible_du/du_high/du_high_config.h | 2 +- lib/du_high/adapters/mac_test_mode_adapter.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 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 fb01cedf84..036140cf47 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -215,7 +215,7 @@ struct du_high_unit_pucch_config { /// \c PUCCH-Config parameters. /// Force Format 0 for the PUCCH resources belonging to PUCCH resource set 0. bool use_format_0 = false; - /// Number of PUCCH resources per UE for HARQ-ACK reporting. + /// Number of PUCCH resources per UE (per PUCCH resource set) for HARQ-ACK reporting. /// Values {3,...,8} if \c use_format_0 is set. Else, Values {1,...,8}. /// \remark We assume the number of PUCCH F0/F1 resources for HARQ-ACK is equal to the equivalent number of Format 2 /// resources. diff --git a/lib/du_high/adapters/mac_test_mode_adapter.cpp b/lib/du_high/adapters/mac_test_mode_adapter.cpp index dbabc5bdaf..d148ddc10b 100644 --- a/lib/du_high/adapters/mac_test_mode_adapter.cpp +++ b/lib/du_high/adapters/mac_test_mode_adapter.cpp @@ -215,7 +215,8 @@ void mac_test_mode_cell_adapter::fill_uci_pdu(mac_uci_pdu::pucch_f0_or_f1_type& srsran_assert(pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1, "Expected PUCCH Format is F0 or F1"); if (pucch.format == pucch_format::FORMAT_0) { - // In case of Format 0, the number of PUCCHs is always 1, even if there are SR + HARQ bits. + // In case of Format 0, unlike with Format 0, the GNB only schedules 1 PUCCH per slot; this PUCCH (and the + // corresponding UCI indication) can have HARQ-ACK bits or SR bits, or both. if (pucch.format_0.sr_bits != sr_nof_bits::no_sr) { // In test mode, SRs are never detected, and instead BSR is injected. pucch_ind.sr_info.emplace(); From 9377509fb7615f7619ec51804bcd3f05b9bff927 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 9 Aug 2024 16:05:44 +0200 Subject: [PATCH 213/407] sched: fix ue cfg validator for Format 0 Signed-off-by: Carlo Galiotto --- .../config/serving_cell_config_validator.cpp | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index fd774958ea..3ab586710b 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -177,13 +177,6 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() <= pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), "PUCCH resource set 1's size should be greater or equal to PUCCH resource set 0's size"); - // Verify that each PUCCH resource has a valid cell resource ID. - for (auto res_idx : pucch_cfg.pucch_res_list) { - VERIFY(res_idx.res_id.cell_res_id < pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES, - "PUCCH cell res. id={} exceeds the maximum supported PUCCH resource ID", - res_idx.res_id.cell_res_id); - } - // Verify each resource format matches the corresponding parameters. for (auto res : pucch_cfg.pucch_res_list) { const bool format_match_format_params = @@ -207,6 +200,23 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(not(has_format_0 and has_format_1), "Only PUCCH Format 0 or Format 1 can be configured in a UE configuration, not both."); + // Verify that each PUCCH resource has a valid cell resource ID. + for (auto res_idx : pucch_cfg.pucch_res_list) { + if (has_format_0) { + // For Format 0, we use a special cell resources ID to indicate that the resource does not exist in the cell + // resource list, but only exists in the UE dedicated configuration. + unsigned cell_res_id_special_res = std::numeric_limits::max(); + VERIFY(res_idx.res_id.cell_res_id < pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES or + res_idx.res_id.cell_res_id == cell_res_id_special_res, + "PUCCH cell res. id={} exceeds the maximum supported PUCCH resource ID", + res_idx.res_id.cell_res_id); + } else { + VERIFY(res_idx.res_id.cell_res_id < pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES, + "PUCCH cell res. id={} exceeds the maximum supported PUCCH resource ID", + res_idx.res_id.cell_res_id); + } + } + // NOTE: No need to check this for Format 0, as this struct doesn't exist for F0. if (has_format_1) { VERIFY(pucch_cfg.format_1_common_param.has_value(), "Missing PUCCH-format1 parameters in PUCCH-Config"); From 8f7738dd83a5c241d4dd93f6fb0482bc1dc7d082 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 18:37:44 +0200 Subject: [PATCH 214/407] du_manager: store QoS of DRBs in DU UE context --- .../converters/asn1_rrc_config_helpers.h | 2 +- .../scheduler_configuration_helpers.cpp | 4 +- lib/du_manager/du_ue/du_ue.h | 4 +- lib/du_manager/du_ue/du_ue_manager.cpp | 2 +- .../procedures/ue_configuration_procedure.cpp | 42 +++--- .../procedures/ue_configuration_procedure.h | 3 +- .../procedures/ue_creation_procedure.cpp | 11 +- .../du_pucch_resource_manager.h | 2 +- .../du_ran_resource_manager.h | 19 +-- .../du_ran_resource_manager_impl.cpp | 136 +++++++++--------- .../du_ran_resource_manager_impl.h | 12 +- ...group_config.h => du_ue_resource_config.h} | 16 +++ .../pucch_resource_generator.h | 2 +- .../du_manager/du_manager_test_helpers.cpp | 34 ++--- .../du_manager/du_manager_test_helpers.h | 14 +- .../du_ran_resource_manager_test.cpp | 85 ++++++----- .../du_manager_procedure_test_helpers.cpp | 38 ++--- .../procedures/ue_configuration_test.cpp | 30 ++-- .../procedures/ue_creation_test.cpp | 4 +- 19 files changed, 254 insertions(+), 206 deletions(-) rename lib/du_manager/ran_resource_management/{cell_group_config.h => du_ue_resource_config.h} (61%) diff --git a/lib/du_manager/converters/asn1_rrc_config_helpers.h b/lib/du_manager/converters/asn1_rrc_config_helpers.h index 422ae01ecd..9a5b618e90 100644 --- a/lib/du_manager/converters/asn1_rrc_config_helpers.h +++ b/lib/du_manager/converters/asn1_rrc_config_helpers.h @@ -10,7 +10,7 @@ #pragma once -#include "../ran_resource_management/cell_group_config.h" +#include "../ran_resource_management/du_ue_resource_config.h" #include "srsran/asn1/rrc_nr/cell_group_config.h" #include "srsran/asn1/rrc_nr/ho_prep_info.h" diff --git a/lib/du_manager/converters/scheduler_configuration_helpers.cpp b/lib/du_manager/converters/scheduler_configuration_helpers.cpp index 7c73486711..2d4d921421 100644 --- a/lib/du_manager/converters/scheduler_configuration_helpers.cpp +++ b/lib/du_manager/converters/scheduler_configuration_helpers.cpp @@ -81,8 +81,8 @@ sched_ue_config_request srsran::srs_du::create_scheduler_ue_config_request(const sched_cfg.cells.emplace(); sched_cfg.cells->resize(1); - (*sched_cfg.cells)[0] = ue_ctx.resources->cells[0]; - sched_cfg.sched_request_config_list = ue_ctx.resources->mcg_cfg.scheduling_request_config; + (*sched_cfg.cells)[0] = ue_ctx.resources->cell_group.cells[0]; + sched_cfg.sched_request_config_list = ue_ctx.resources->cell_group.mcg_cfg.scheduling_request_config; // Add SRB and DRB logical channels. sched_cfg.lc_config_list.emplace(); for (const du_ue_srb& bearer : ue_ctx.bearers.srbs()) { diff --git a/lib/du_manager/du_ue/du_ue.h b/lib/du_manager/du_ue/du_ue.h index b64c83637f..18269d6f76 100644 --- a/lib/du_manager/du_ue/du_ue.h +++ b/lib/du_manager/du_ue/du_ue.h @@ -10,8 +10,8 @@ #pragma once -#include "../ran_resource_management/cell_group_config.h" #include "../ran_resource_management/du_ran_resource_manager.h" +#include "../ran_resource_management/du_ue_resource_config.h" #include "du_ue_bearer_manager.h" #include "srsran/ran/du_types.h" #include "srsran/ran/rnti.h" @@ -98,7 +98,7 @@ class du_ue : public du_ue_context, public du_ue_controller /// \brief Determines whether this UE is running the RRC Reestablishment procedure and which context was retrieved /// from the old UE. - std::unique_ptr reestablished_cfg_pending; + std::unique_ptr reestablished_cfg_pending; }; } // namespace srs_du diff --git a/lib/du_manager/du_ue/du_ue_manager.cpp b/lib/du_manager/du_ue/du_ue_manager.cpp index a7a84c8b87..a25d012ca8 100644 --- a/lib/du_manager/du_ue/du_ue_manager.cpp +++ b/lib/du_manager/du_ue/du_ue_manager.cpp @@ -117,7 +117,7 @@ void du_ue_manager::handle_reestablishment_request(du_ue_index_t new_ue_index, d // Retrieve the old UE context for the RRC connection reestablishment procedure, as defined in TS 48.473, 8.4.2.2 and // TS 38.401. - new_ue.reestablished_cfg_pending = std::make_unique(old_ue_it->resources.value()); + new_ue.reestablished_cfg_pending = std::make_unique(old_ue_it->resources.value()); // Delete the old UE context. schedule_async_task(old_ue_index, handle_ue_delete_request(f1ap_ue_delete_request{old_ue_index})); diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 4060d9c02d..3defb7f23b 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -43,7 +43,7 @@ void ue_configuration_procedure::operator()(coro_contextresources.value(); + prev_ue_res_cfg = ue->resources.value(); if (ue->resources.update(ue->pcell_index, request, ue->reestablished_cfg_pending.get()).release_required()) { proc_logger.log_proc_failure("Failed to allocate DU UE resources"); CORO_EARLY_RETURN(make_ue_config_failure()); @@ -75,7 +75,7 @@ async_task ue_configuration_procedure::stop_drbs_to_rem() void ue_configuration_procedure::update_ue_context() { // > Create DU UE SRB objects. - for (const auto& bearer : ue->resources->rlc_bearers) { + for (const auto& bearer : ue->resources->cell_group.rlc_bearers) { if (bearer.drb_id.has_value()) { continue; } @@ -124,8 +124,8 @@ void ue_configuration_procedure::update_ue_context() proc_logger.log_proc_warning("Failed to release {}. Cause: DRB does not exist", drb_to_rem); continue; } - srsran_assert(std::any_of(prev_cell_group.rlc_bearers.begin(), - prev_cell_group.rlc_bearers.end(), + srsran_assert(std::any_of(prev_ue_res_cfg.cell_group.rlc_bearers.begin(), + prev_ue_res_cfg.cell_group.rlc_bearers.end(), [&drb_to_rem](const rlc_bearer_config& e) { return e.drb_id == drb_to_rem; }), "The bearer to be deleted must already exist"); @@ -145,10 +145,11 @@ void ue_configuration_procedure::update_ue_context() } // Find the RLC configuration for this DRB. - auto it = std::find_if(ue->resources->rlc_bearers.begin(), - ue->resources->rlc_bearers.end(), + auto it = std::find_if(ue->resources->cell_group.rlc_bearers.begin(), + ue->resources->cell_group.rlc_bearers.end(), [&drbtoadd](const rlc_bearer_config& e) { return e.drb_id == drbtoadd.drb_id; }); - srsran_assert(it != ue->resources->rlc_bearers.end(), "The bearer config should be created at this point"); + srsran_assert(it != ue->resources->cell_group.rlc_bearers.end(), + "The bearer config should be created at this point"); // Find the F1-U configuration for this DRB. five_qi_t fiveqi = drbtoadd.qos_info.drb_qos.qos_characteristics.get_five_qi(); @@ -187,10 +188,11 @@ void ue_configuration_procedure::update_ue_context() continue; } // Find the RLC configuration for this DRB. - auto it = std::find_if(ue->resources->rlc_bearers.begin(), - ue->resources->rlc_bearers.end(), + auto it = std::find_if(ue->resources->cell_group.rlc_bearers.begin(), + ue->resources->cell_group.rlc_bearers.end(), [&drbtomod](const rlc_bearer_config& e) { return e.drb_id == drbtomod.drb_id; }); - srsran_assert(it != ue->resources->rlc_bearers.end(), "The bearer config should be created at this point"); + srsran_assert(it != ue->resources->cell_group.rlc_bearers.end(), + "The bearer config should be created at this point"); auto drb_it = ue->bearers.drbs().find(drbtomod.drb_id); if (drb_it == ue->bearers.drbs().end()) { @@ -251,8 +253,8 @@ async_task ue_configuration_procedure::update_m mac_ue_reconf_req.ue_index = request.ue_index; mac_ue_reconf_req.crnti = ue->rnti; mac_ue_reconf_req.pcell_index = ue->pcell_index; - mac_ue_reconf_req.mac_cell_group_cfg = ue->resources->mcg_cfg; - mac_ue_reconf_req.phy_cell_group_cfg = ue->resources->pcg_cfg; + mac_ue_reconf_req.mac_cell_group_cfg = ue->resources->cell_group.mcg_cfg; + mac_ue_reconf_req.phy_cell_group_cfg = ue->resources->cell_group.pcg_cfg; for (const srb_id_t srbid : srbs_added) { du_ue_srb& bearer = ue->bearers.srbs()[srbid]; @@ -340,7 +342,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo // set to "RLCReestablish". ue->reestablished_cfg_pending = nullptr; - calculate_cell_group_config_diff(asn1_cell_group, cell_group_config{}, *ue->resources); + calculate_cell_group_config_diff(asn1_cell_group, cell_group_config{}, ue->resources->cell_group); auto it = std::find_if(asn1_cell_group.rlc_bearer_to_add_mod_list.begin(), asn1_cell_group.rlc_bearer_to_add_mod_list.end(), [](const auto& b) { return b.lc_ch_id == LCID_SRB1; }); @@ -354,17 +356,17 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo } } else if (request.full_config_required) { // The CU requested a full configuration of the UE cellGroupConfig. - calculate_cell_group_config_diff(asn1_cell_group, {}, *ue->resources); + calculate_cell_group_config_diff(asn1_cell_group, {}, ue->resources->cell_group); resp.full_config_present = true; } else if (not request.source_cell_group_cfg.empty()) { // In case of source cell group configuration is passed, a delta configuration should be generated with it. // TODO: Apply diff using sourceCellGroup. For now, we use fullConfig. - calculate_cell_group_config_diff(asn1_cell_group, {}, *ue->resources); + calculate_cell_group_config_diff(asn1_cell_group, {}, ue->resources->cell_group); resp.full_config_present = true; } else { - calculate_cell_group_config_diff(asn1_cell_group, prev_cell_group, *ue->resources); + calculate_cell_group_config_diff(asn1_cell_group, prev_ue_res_cfg.cell_group, ue->resources->cell_group); } // Include reconfiguration with sync if HandoverPreparationInformation is included. @@ -378,8 +380,12 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo return make_ue_config_failure(); } } - asn1_cell_group.sp_cell_cfg.recfg_with_sync_present = calculate_reconfig_with_sync_diff( - asn1_cell_group.sp_cell_cfg.recfg_with_sync, du_params.ran.cells[0], *ue->resources, ho_prep_info, ue->rnti); + asn1_cell_group.sp_cell_cfg.recfg_with_sync_present = + calculate_reconfig_with_sync_diff(asn1_cell_group.sp_cell_cfg.recfg_with_sync, + du_params.ran.cells[0], + ue->resources->cell_group, + ho_prep_info, + ue->rnti); if (not asn1_cell_group.sp_cell_cfg.recfg_with_sync_present) { proc_logger.log_proc_failure("Failed to calculate ReconfigWithSync"); return make_ue_config_failure(); diff --git a/lib/du_manager/procedures/ue_configuration_procedure.h b/lib/du_manager/procedures/ue_configuration_procedure.h index 705f42b17a..9da612d3cb 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.h +++ b/lib/du_manager/procedures/ue_configuration_procedure.h @@ -51,7 +51,8 @@ class ue_configuration_procedure du_ue* ue = nullptr; ue_procedure_logger proc_logger; - cell_group_config prev_cell_group; + // Snapshot of the UE resources at the start of the UE configuration procedure. + du_ue_resource_config prev_ue_res_cfg; // SRBs that were actually added during the configuration. static_vector srbs_added; diff --git a/lib/du_manager/procedures/ue_creation_procedure.cpp b/lib/du_manager/procedures/ue_creation_procedure.cpp index 99308f3a51..14d7774d67 100644 --- a/lib/du_manager/procedures/ue_creation_procedure.cpp +++ b/lib/du_manager/procedures/ue_creation_procedure.cpp @@ -148,8 +148,9 @@ bool ue_creation_procedure::setup_du_ue_resources() // Create DU UE SRB0 and SRB1. ue_ctx->bearers.add_srb(srb_id_t::srb0, make_default_srb0_rlc_config()); - ue_ctx->bearers.add_srb( - srb_id_t::srb1, ue_ctx->resources->rlc_bearers[0].rlc_cfg, ue_ctx->resources->rlc_bearers[0].mac_cfg); + ue_ctx->bearers.add_srb(srb_id_t::srb1, + ue_ctx->resources->cell_group.rlc_bearers[0].rlc_cfg, + ue_ctx->resources->cell_group.rlc_bearers[0].mac_cfg); return true; } @@ -184,8 +185,8 @@ async_task ue_creation_procedure::create_mac_ue() mac_ue_create_msg.ue_index = ue_ctx->ue_index; mac_ue_create_msg.crnti = req.tc_rnti; mac_ue_create_msg.cell_index = req.pcell_index; - mac_ue_create_msg.mac_cell_group_cfg = ue_ctx->resources->mcg_cfg; - mac_ue_create_msg.phy_cell_group_cfg = ue_ctx->resources->pcg_cfg; + mac_ue_create_msg.mac_cell_group_cfg = ue_ctx->resources->cell_group.mcg_cfg; + mac_ue_create_msg.phy_cell_group_cfg = ue_ctx->resources->cell_group.pcg_cfg; mac_ue_create_msg.rlf_notifier = &ue_ctx->get_mac_rlf_notifier(); for (du_ue_srb& bearer : ue_ctx->bearers.srbs()) { mac_ue_create_msg.bearers.emplace_back(); @@ -231,7 +232,7 @@ f1ap_ue_creation_response ue_creation_procedure::create_f1ap_ue() // Pack SRB1 configuration that is going to be passed in the F1AP DU-to-CU-RRC-Container IE to the CU as per TS38.473, // Section 8.4.1.2. cell_group_cfg_s cell_group; - calculate_cell_group_config_diff(cell_group, {}, *ue_ctx->resources); + calculate_cell_group_config_diff(cell_group, {}, ue_ctx->resources->cell_group); { asn1::bit_ref bref{f1ap_msg.du_cu_rrc_container}; diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h index eb6fd38284..bb23f72656 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h @@ -10,7 +10,7 @@ #pragma once -#include "cell_group_config.h" +#include "du_ue_resource_config.h" #include "pucch_resource_generator.h" #include diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h index f0bc586ce5..4b6cb0cac0 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h @@ -10,7 +10,7 @@ #pragma once -#include "cell_group_config.h" +#include "du_ue_resource_config.h" #include "srsran/f1ap/du/f1ap_du_ue_context_update.h" namespace srsran { @@ -37,11 +37,12 @@ class ue_ran_resource_configurator /// \brief Interface used to update the UE Resources on Reconfiguration and return the resources back to the pool, /// on UE deletion. struct resource_updater { - virtual ~resource_updater() = default; + virtual ~resource_updater() = default; + virtual du_ue_resource_update_response update(du_cell_index_t pcell_index, const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context) = 0; - virtual const cell_group_config& get() = 0; + const du_ue_resource_config* reestablished_context) = 0; + virtual const du_ue_resource_config& get() = 0; }; explicit ue_ran_resource_configurator(std::unique_ptr ue_res_, std::string error = {}) : @@ -60,7 +61,7 @@ class ue_ran_resource_configurator /// \return Outcome of the configuration. du_ue_resource_update_response update(du_cell_index_t pcell_index, const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context = nullptr) + const du_ue_resource_config* reestablished_context = nullptr) { return ue_res_impl->update(pcell_index, upd_req, reestablished_context); } @@ -71,13 +72,13 @@ class ue_ran_resource_configurator /// \brief Returns the configurator error, which non-empty string only if the procedure failed. std::string get_error() const { return empty() ? configurator_error : std::string{}; } - const cell_group_config& value() const { return *cached_res; } - const cell_group_config& operator*() const { return *cached_res; } - const cell_group_config* operator->() const { return cached_res; } + const du_ue_resource_config& value() const { return *cached_res; } + const du_ue_resource_config& operator*() const { return *cached_res; } + const du_ue_resource_config* operator->() const { return cached_res; } private: std::unique_ptr ue_res_impl; - const cell_group_config* cached_res; + const du_ue_resource_config* cached_res; std::string configurator_error; }; diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index dfb2efeaa4..ea91ce7577 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -44,7 +44,7 @@ static lcid_t find_empty_lcid(const std::vector& rlc_bearers) return lcid; } -du_ue_ran_resource_updater_impl::du_ue_ran_resource_updater_impl(cell_group_config* cell_grp_cfg_, +du_ue_ran_resource_updater_impl::du_ue_ran_resource_updater_impl(du_ue_resource_config* cell_grp_cfg_, du_ran_resource_manager_impl& parent_, du_ue_index_t ue_index_) : cell_grp(cell_grp_cfg_), parent(&parent_), ue_index(ue_index_) @@ -56,9 +56,10 @@ du_ue_ran_resource_updater_impl::~du_ue_ran_resource_updater_impl() parent->deallocate_context(ue_index); } -du_ue_resource_update_response du_ue_ran_resource_updater_impl::update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context) +du_ue_resource_update_response +du_ue_ran_resource_updater_impl::update(du_cell_index_t pcell_index, + const f1ap_ue_context_update_request& upd_req, + const du_ue_resource_config* reestablished_context) { return parent->update_context(ue_index, pcell_index, upd_req, reestablished_context); } @@ -141,16 +142,18 @@ static error_type validate_drb_setup_request(const f1ap_drb_to_setu return {}; } -static void reestablish_context(cell_group_config& new_ue_cfg, const cell_group_config& old_ue_cfg) +static void reestablish_context(du_ue_resource_config& new_ue_cfg, const du_ue_resource_config& old_ue_cfg) { - for (const rlc_bearer_config& old_bearer : old_ue_cfg.rlc_bearers) { - auto it = std::find_if( - new_ue_cfg.rlc_bearers.begin(), new_ue_cfg.rlc_bearers.end(), [&old_bearer](const rlc_bearer_config& item) { - return item.drb_id == old_bearer.drb_id and (item.drb_id.has_value() or (item.lcid == old_bearer.lcid)); - }); - if (it == new_ue_cfg.rlc_bearers.end()) { + for (const rlc_bearer_config& old_bearer : old_ue_cfg.cell_group.rlc_bearers) { + auto it = std::find_if(new_ue_cfg.cell_group.rlc_bearers.begin(), + new_ue_cfg.cell_group.rlc_bearers.end(), + [&old_bearer](const rlc_bearer_config& item) { + return item.drb_id == old_bearer.drb_id and + (item.drb_id.has_value() or (item.lcid == old_bearer.lcid)); + }); + if (it == new_ue_cfg.cell_group.rlc_bearers.end()) { // Bearer not found in new context. Add it. - new_ue_cfg.rlc_bearers.push_back(old_bearer); + new_ue_cfg.cell_group.rlc_bearers.push_back(old_bearer); } } } @@ -159,14 +162,14 @@ du_ue_resource_update_response du_ran_resource_manager_impl::update_context(du_ue_index_t ue_index, du_cell_index_t pcell_idx, const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context) + const du_ue_resource_config* reestablished_context) { srsran_assert(ue_res_pool.contains(ue_index), "This function should only be called for an already allocated UE"); - cell_group_config& ue_mcg = ue_res_pool[ue_index].cg_cfg; + du_ue_resource_config& ue_mcg = ue_res_pool[ue_index].cg_cfg; du_ue_resource_update_response resp; // > Deallocate resources for previously configured cells that have now been removed or changed. - if (ue_mcg.cells.contains(0) and ue_mcg.cells[0].serv_cell_cfg.cell_index != pcell_idx) { + if (ue_mcg.cell_group.cells.contains(0) and ue_mcg.cell_group.cells[0].serv_cell_cfg.cell_index != pcell_idx) { // >> PCell changed. Deallocate PCell resources. deallocate_cell_resources(ue_index, SERVING_CELL_PCELL_IDX); } @@ -176,8 +179,8 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } for (const f1ap_scell_to_setup& scell : upd_req.scells_to_setup) { // >> If SCells to be modified changed DU Cell Index. - if (ue_mcg.cells.contains(scell.serv_cell_index) and - ue_mcg.cells[scell.serv_cell_index].serv_cell_cfg.cell_index != scell.cell_index) { + if (ue_mcg.cell_group.cells.contains(scell.serv_cell_index) and + ue_mcg.cell_group.cells[scell.serv_cell_index].serv_cell_cfg.cell_index != scell.cell_index) { deallocate_cell_resources(ue_index, scell.serv_cell_index); } } @@ -189,11 +192,11 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t // > Deallocate removed SRBs / DRBs. for (drb_id_t drb_id : upd_req.drbs_to_rem) { - auto it = std::find_if(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [drb_id](const rlc_bearer_config& b) { - return b.drb_id == drb_id; - }); - if (it != ue_mcg.rlc_bearers.end()) { - ue_mcg.rlc_bearers.erase(it); + auto it = std::find_if(ue_mcg.cell_group.rlc_bearers.begin(), + ue_mcg.cell_group.rlc_bearers.end(), + [drb_id](const rlc_bearer_config& b) { return b.drb_id == drb_id; }); + if (it != ue_mcg.cell_group.rlc_bearers.end()) { + ue_mcg.cell_group.rlc_bearers.erase(it); continue; } else { logger.warning("Failed to release {}. Cause: DRB not found", drb_id); @@ -204,35 +207,35 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t for (srb_id_t srb_id : upd_req.srbs_to_setup) { // >> New or Modified SRB. lcid_t lcid = srb_id_to_lcid(srb_id); - if (std::any_of(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [lcid](const auto& item) { - return item.lcid == lcid; - })) { + if (std::any_of(ue_mcg.cell_group.rlc_bearers.begin(), + ue_mcg.cell_group.rlc_bearers.end(), + [lcid](const auto& item) { return item.lcid == lcid; })) { // The SRB is already setup (e.g. SRB1 gets setup automatically). continue; } - ue_mcg.rlc_bearers.emplace_back(); - ue_mcg.rlc_bearers.back().lcid = lcid; + ue_mcg.cell_group.rlc_bearers.emplace_back(); + ue_mcg.cell_group.rlc_bearers.back().lcid = lcid; auto srb_it = srb_config.find(srb_id); if (srb_it != srb_config.end()) { - ue_mcg.rlc_bearers.back().rlc_cfg = srb_it->second.rlc; - ue_mcg.rlc_bearers.back().mac_cfg = srb_it->second.mac; + ue_mcg.cell_group.rlc_bearers.back().rlc_cfg = srb_it->second.rlc; + ue_mcg.cell_group.rlc_bearers.back().mac_cfg = srb_it->second.mac; } else { - ue_mcg.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - ue_mcg.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(lcid); + ue_mcg.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + ue_mcg.cell_group.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(lcid); } } // > Create new DRBs. for (const f1ap_drb_to_setup& drb : upd_req.drbs_to_setup) { - auto res = validate_drb_setup_request(drb, ue_mcg.rlc_bearers, qos_config); + auto res = validate_drb_setup_request(drb, ue_mcg.cell_group.rlc_bearers, qos_config); if (not res.has_value()) { resp.failed_drbs.push_back(drb.drb_id); continue; } // > Allocate LCID. - lcid_t lcid = find_empty_lcid(ue_mcg.rlc_bearers); + lcid_t lcid = find_empty_lcid(ue_mcg.cell_group.rlc_bearers); if (lcid > LCID_MAX_DRB) { logger.warning("Failed to allocate {}. Cause: No available LCIDs", drb.drb_id); resp.failed_drbs.push_back(drb.drb_id); @@ -242,14 +245,14 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t // >> Get RLC config from 5QI five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); const du_qos_config& qos = qos_config.at(fiveqi); - ue_mcg.rlc_bearers.emplace_back(); - ue_mcg.rlc_bearers.back().lcid = lcid; - ue_mcg.rlc_bearers.back().drb_id = drb.drb_id; - ue_mcg.rlc_bearers.back().rlc_cfg = qos.rlc; - ue_mcg.rlc_bearers.back().mac_cfg = qos.mac; + ue_mcg.cell_group.rlc_bearers.emplace_back(); + ue_mcg.cell_group.rlc_bearers.back().lcid = lcid; + ue_mcg.cell_group.rlc_bearers.back().drb_id = drb.drb_id; + ue_mcg.cell_group.rlc_bearers.back().rlc_cfg = qos.rlc; + ue_mcg.cell_group.rlc_bearers.back().mac_cfg = qos.mac; // Update pdcp_sn_len in RLC config - auto& rlc_cfg = ue_mcg.rlc_bearers.back().rlc_cfg; + auto& rlc_cfg = ue_mcg.cell_group.rlc_bearers.back().rlc_cfg; switch (rlc_cfg.mode) { case rlc_mode::am: rlc_cfg.am.tx.pdcp_sn_len = drb.pdcp_sn_len; @@ -265,7 +268,7 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t // > Modify existing DRBs. for (const f1ap_drb_to_modify& drb : upd_req.drbs_to_mod) { - auto res = validate_drb_modification_request(drb, ue_mcg.rlc_bearers); + auto res = validate_drb_modification_request(drb, ue_mcg.cell_group.rlc_bearers); if (not res.has_value()) { resp.failed_drbs.push_back(drb.drb_id); continue; @@ -273,12 +276,12 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } // > Sort bearers by LCID. - std::sort(ue_mcg.rlc_bearers.begin(), ue_mcg.rlc_bearers.end(), [](const auto& lhs, const auto& rhs) { - return lhs.lcid < rhs.lcid; - }); + std::sort(ue_mcg.cell_group.rlc_bearers.begin(), + ue_mcg.cell_group.rlc_bearers.end(), + [](const auto& lhs, const auto& rhs) { return lhs.lcid < rhs.lcid; }); // > Allocate resources for new or modified cells. - if (not ue_mcg.cells.contains(0) or ue_mcg.cells[0].serv_cell_cfg.cell_index != pcell_idx) { + if (not ue_mcg.cell_group.cells.contains(0) or ue_mcg.cell_group.cells[0].serv_cell_cfg.cell_index != pcell_idx) { // >> PCell changed. Allocate new PCell resources. error_type outcome = allocate_cell_resources(ue_index, pcell_idx, SERVING_CELL_PCELL_IDX); if (not outcome.has_value()) { @@ -299,9 +302,9 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t void du_ran_resource_manager_impl::deallocate_context(du_ue_index_t ue_index) { srsran_assert(ue_res_pool.contains(ue_index), "This function should only be called for an already allocated UE"); - cell_group_config& ue_mcg = ue_res_pool[ue_index].cg_cfg; + du_ue_resource_config& ue_mcg = ue_res_pool[ue_index].cg_cfg; - for (const auto& sc : ue_mcg.cells) { + for (const auto& sc : ue_mcg.cell_group.cells) { deallocate_cell_resources(ue_index, sc.serv_cell_idx); } ue_res_pool.erase(ue_index); @@ -311,33 +314,33 @@ error_type du_ran_resource_manager_impl::allocate_cell_resources(du du_cell_index_t cell_index, serv_cell_index_t serv_cell_index) { - cell_group_config& ue_res = ue_res_pool[ue_index].cg_cfg; + du_ue_resource_config& ue_res = ue_res_pool[ue_index].cg_cfg; const du_cell_config& cell_cfg_cmn = cell_cfg_list[cell_index]; if (serv_cell_index == SERVING_CELL_PCELL_IDX) { // It is a PCell. - srsran_assert(not ue_res.cells.contains(SERVING_CELL_PCELL_IDX), "Reallocation of PCell detected"); - ue_res.cells.emplace(SERVING_CELL_PCELL_IDX); - ue_res.cells[0].serv_cell_idx = SERVING_CELL_PCELL_IDX; - ue_res.cells[0].serv_cell_cfg = cell_cfg_cmn.ue_ded_serv_cell_cfg; - ue_res.cells[0].serv_cell_cfg.cell_index = cell_index; - ue_res.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(cell_cfg_cmn.mcg_params); + srsran_assert(not ue_res.cell_group.cells.contains(SERVING_CELL_PCELL_IDX), "Reallocation of PCell detected"); + ue_res.cell_group.cells.emplace(SERVING_CELL_PCELL_IDX); + ue_res.cell_group.cells[0].serv_cell_idx = SERVING_CELL_PCELL_IDX; + ue_res.cell_group.cells[0].serv_cell_cfg = cell_cfg_cmn.ue_ded_serv_cell_cfg; + ue_res.cell_group.cells[0].serv_cell_cfg.cell_index = cell_index; + ue_res.cell_group.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(cell_cfg_cmn.mcg_params); // TODO: Move to helper. if (cell_cfg_cmn.pcg_params.p_nr_fr1.has_value()) { - ue_res.pcg_cfg.p_nr_fr1 = cell_cfg_cmn.pcg_params.p_nr_fr1->to_int(); + ue_res.cell_group.pcg_cfg.p_nr_fr1 = cell_cfg_cmn.pcg_params.p_nr_fr1->to_int(); } - ue_res.pcg_cfg.pdsch_harq_codebook = pdsch_harq_ack_codebook::dynamic; + ue_res.cell_group.pcg_cfg.pdsch_harq_codebook = pdsch_harq_ack_codebook::dynamic; - if (not pucch_res_mng.alloc_resources(ue_res)) { + if (not pucch_res_mng.alloc_resources(ue_res.cell_group)) { return make_unexpected(fmt::format("Unable to allocate dedicated PUCCH resources for cell={}", cell_index)); } } else { - srsran_assert(not ue_res.cells.contains(serv_cell_index), "Reallocation of SCell detected"); - ue_res.cells.emplace(serv_cell_index); - ue_res.cells[serv_cell_index].serv_cell_idx = serv_cell_index; - ue_res.cells[serv_cell_index].serv_cell_cfg = cell_cfg_cmn.ue_ded_serv_cell_cfg; - ue_res.cells[serv_cell_index].serv_cell_cfg.cell_index = cell_index; + srsran_assert(not ue_res.cell_group.cells.contains(serv_cell_index), "Reallocation of SCell detected"); + ue_res.cell_group.cells.emplace(serv_cell_index); + ue_res.cell_group.cells[serv_cell_index].serv_cell_idx = serv_cell_index; + ue_res.cell_group.cells[serv_cell_index].serv_cell_cfg = cell_cfg_cmn.ue_ded_serv_cell_cfg; + ue_res.cell_group.cells[serv_cell_index].serv_cell_cfg.cell_index = cell_index; // TODO: Allocate SCell params. } return {}; @@ -345,16 +348,17 @@ error_type du_ran_resource_manager_impl::allocate_cell_resources(du void du_ran_resource_manager_impl::deallocate_cell_resources(du_ue_index_t ue_index, serv_cell_index_t serv_cell_index) { - cell_group_config& ue_res = ue_res_pool[ue_index].cg_cfg; + du_ue_resource_config& ue_res = ue_res_pool[ue_index].cg_cfg; // Return resources back to free lists. if (serv_cell_index == SERVING_CELL_PCELL_IDX) { - srsran_assert(not ue_res.cells.empty() and ue_res.cells[0].serv_cell_cfg.cell_index != INVALID_DU_CELL_INDEX, + srsran_assert(not ue_res.cell_group.cells.empty() and + ue_res.cell_group.cells[0].serv_cell_cfg.cell_index != INVALID_DU_CELL_INDEX, "Double deallocation of same UE cell resources detected"); - pucch_res_mng.dealloc_resources(ue_res); - ue_res.cells[0].serv_cell_cfg.cell_index = INVALID_DU_CELL_INDEX; + pucch_res_mng.dealloc_resources(ue_res.cell_group); + ue_res.cell_group.cells[0].serv_cell_cfg.cell_index = INVALID_DU_CELL_INDEX; } else { // TODO: Remove of SCell params. - ue_res.cells.erase(serv_cell_index); + ue_res.cell_group.cells.erase(serv_cell_index); } } diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h index c16306a462..3c34c7b3bb 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h @@ -22,7 +22,7 @@ class du_ran_resource_manager_impl; class du_ue_ran_resource_updater_impl final : public ue_ran_resource_configurator::resource_updater { public: - du_ue_ran_resource_updater_impl(cell_group_config* cell_cfg_, + du_ue_ran_resource_updater_impl(du_ue_resource_config* cell_cfg_, du_ran_resource_manager_impl& parent_, du_ue_index_t ue_index_); du_ue_ran_resource_updater_impl(const du_ue_ran_resource_updater_impl&) = delete; @@ -33,12 +33,12 @@ class du_ue_ran_resource_updater_impl final : public ue_ran_resource_configurato du_ue_resource_update_response update(du_cell_index_t pcell_index, const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context) override; + const du_ue_resource_config* reestablished_context) override; - const cell_group_config& get() override { return *cell_grp; } + const du_ue_resource_config& get() override { return *cell_grp; } private: - cell_group_config* cell_grp; + du_ue_resource_config* cell_grp; du_ran_resource_manager_impl* parent; du_ue_index_t ue_index; }; @@ -71,7 +71,7 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager du_ue_resource_update_response update_context(du_ue_index_t ue_index, du_cell_index_t pcell_idx, const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context); + const du_ue_resource_config* reestablished_context); /// \brief Deallocates the RAN resources taken by the UE, so that they can be used by future UEs. /// @@ -89,7 +89,7 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager srslog::basic_logger& logger; struct ue_res_item { - cell_group_config cg_cfg; + du_ue_resource_config cg_cfg; }; /// Current UE Resource Allocations. diff --git a/lib/du_manager/ran_resource_management/cell_group_config.h b/lib/du_manager/ran_resource_management/du_ue_resource_config.h similarity index 61% rename from lib/du_manager/ran_resource_management/cell_group_config.h rename to lib/du_manager/ran_resource_management/du_ue_resource_config.h index d27b6aa39a..f543e1c1bd 100644 --- a/lib/du_manager/ran_resource_management/cell_group_config.h +++ b/lib/du_manager/ran_resource_management/du_ue_resource_config.h @@ -15,6 +15,7 @@ #include "srsran/ran/du_types.h" #include "srsran/ran/lcid.h" #include "srsran/ran/physical_cell_group.h" +#include "srsran/ran/qos/qos_parameters.h" #include "srsran/rlc/rlc_config.h" #include "srsran/scheduler/config/serving_cell_config.h" @@ -29,5 +30,20 @@ struct cell_group_config { slotted_vector cells; }; +struct drb_upper_layer_config { + drb_id_t drb_id; + pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; + s_nssai_t s_nssai; + qos_flow_level_qos_parameters qos; +}; + +/// Snapshot of the DU resources taken by a UE at a given instant. +struct du_ue_resource_config { + /// Upper layer configuration of UE DRBs + std::vector drbs; + /// CellGroupConfiguration of the RAN resources allocated to a UE. + cell_group_config cell_group; +}; + } // namespace srs_du } // namespace srsran diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.h b/lib/du_manager/ran_resource_management/pucch_resource_generator.h index b2c473a82a..4df0a71b05 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.h +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.h @@ -10,7 +10,7 @@ #pragma once -#include "cell_group_config.h" +#include "du_ue_resource_config.h" #include "srsran/adt/optional.h" #include "srsran/ran/pucch/pucch_configuration.h" diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index a2508d255d..e4bc115820 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -21,13 +21,14 @@ using namespace srs_du; dummy_ue_resource_configurator_factory::dummy_ue_resource_configurator_factory() { - next_context_update_result.rlc_bearers.resize(1); - next_context_update_result.rlc_bearers[0].lcid = LCID_SRB1; - next_context_update_result.rlc_bearers[0].rlc_cfg = make_default_srb_rlc_config(); - next_context_update_result.rlc_bearers[0].mac_cfg = make_default_srb_mac_lc_config(LCID_SRB1); - next_context_update_result.cells.emplace(0, config_helpers::create_default_initial_ue_spcell_cell_config()); - next_context_update_result.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); - next_context_update_result.pcg_cfg = {}; // TODO + next_context_update_result.cell_group.rlc_bearers.resize(1); + next_context_update_result.cell_group.rlc_bearers[0].lcid = LCID_SRB1; + next_context_update_result.cell_group.rlc_bearers[0].rlc_cfg = make_default_srb_rlc_config(); + next_context_update_result.cell_group.rlc_bearers[0].mac_cfg = make_default_srb_mac_lc_config(LCID_SRB1); + next_context_update_result.cell_group.cells.emplace(0, + config_helpers::create_default_initial_ue_spcell_cell_config()); + next_context_update_result.cell_group.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); + next_context_update_result.cell_group.pcg_cfg = {}; // TODO } dummy_ue_resource_configurator_factory::dummy_resource_updater::dummy_resource_updater( @@ -41,16 +42,16 @@ dummy_ue_resource_configurator_factory::dummy_resource_updater::~dummy_resource_ parent.ue_resource_pool.erase(ue_index); } -du_ue_resource_update_response -dummy_ue_resource_configurator_factory::dummy_resource_updater::update(du_cell_index_t pcell_index, - const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context) +du_ue_resource_update_response dummy_ue_resource_configurator_factory::dummy_resource_updater::update( + du_cell_index_t pcell_index, + const f1ap_ue_context_update_request& upd_req, + const du_ue_resource_config* reestablished_context) { parent.ue_resource_pool[ue_index] = parent.next_context_update_result; return du_ue_resource_update_response{}; } -const cell_group_config& dummy_ue_resource_configurator_factory::dummy_resource_updater::get() +const du_ue_resource_config& dummy_ue_resource_configurator_factory::dummy_resource_updater::get() { return parent.ue_resource_pool[ue_index]; } @@ -64,10 +65,11 @@ dummy_ue_resource_configurator_factory::create_ue_resource_configurator(du_ue_in } last_ue_index = ue_index; last_ue_pcell = pcell_index; - ue_resource_pool.emplace(ue_index, cell_group_config{}); - ue_resource_pool[ue_index].cells.emplace(0, config_helpers::create_default_initial_ue_spcell_cell_config()); - ue_resource_pool[ue_index].cells[0].serv_cell_cfg.cell_index = pcell_index; - ue_resource_pool[ue_index].cells[0].serv_cell_idx = SERVING_CELL_PCELL_IDX; + ue_resource_pool.emplace(ue_index, du_ue_resource_config{}); + ue_resource_pool[ue_index].cell_group.cells.emplace(0, + config_helpers::create_default_initial_ue_spcell_cell_config()); + ue_resource_pool[ue_index].cell_group.cells[0].serv_cell_cfg.cell_index = pcell_index; + ue_resource_pool[ue_index].cell_group.cells[0].serv_cell_idx = SERVING_CELL_PCELL_IDX; return ue_ran_resource_configurator{std::make_unique(*this, ue_index)}; } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index b972893a8e..ca1b61cfb9 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -285,18 +285,18 @@ class dummy_ue_resource_configurator_factory : public du_ran_resource_manager ~dummy_resource_updater(); du_ue_resource_update_response update(du_cell_index_t pcell_index, const f1ap_ue_context_update_request& upd_req, - const cell_group_config* reestablished_context) override; - const cell_group_config& get() override; + const du_ue_resource_config* reestablished_context) override; + const du_ue_resource_config& get() override; du_ue_index_t ue_index; dummy_ue_resource_configurator_factory& parent; }; - std::optional last_ue_index; - std::optional last_ue_pcell; - f1ap_ue_context_update_request last_ue_ctx_upd; - std::map ue_resource_pool; - cell_group_config next_context_update_result; + std::optional last_ue_index; + std::optional last_ue_pcell; + f1ap_ue_context_update_request last_ue_ctx_upd; + std::map ue_resource_pool; + du_ue_resource_config next_context_update_result; dummy_ue_resource_configurator_factory(); diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 96514214ad..fed6475ee4 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -173,13 +173,13 @@ TEST_P(du_ran_resource_manager_tester, when_ue_resource_config_is_created_then_p const ue_ran_resource_configurator& ue_res = create_ue(ue_idx1); ASSERT_FALSE(ue_res.empty()); - ASSERT_EQ(ue_res->cells.size(), 1); - ASSERT_TRUE(ue_res->cells.contains(0)); - ASSERT_TRUE(ue_res->rlc_bearers.empty()); - ASSERT_EQ(ue_res->cells[0].serv_cell_cfg.cell_index, to_du_cell_index(0)); - ASSERT_EQ(ue_res->cells[0].serv_cell_idx, SERVING_CELL_PCELL_IDX); - ASSERT_FALSE(ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list.empty()); - ASSERT_FALSE(ue_res->mcg_cfg.scheduling_request_config.empty()); + ASSERT_EQ(ue_res->cell_group.cells.size(), 1); + ASSERT_TRUE(ue_res->cell_group.cells.contains(0)); + ASSERT_TRUE(ue_res->cell_group.rlc_bearers.empty()); + ASSERT_EQ(ue_res->cell_group.cells[0].serv_cell_cfg.cell_index, to_du_cell_index(0)); + ASSERT_EQ(ue_res->cell_group.cells[0].serv_cell_idx, SERVING_CELL_PCELL_IDX); + ASSERT_FALSE(ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list.empty()); + ASSERT_FALSE(ue_res->cell_group.mcg_cfg.scheduling_request_config.empty()); } TEST_P(du_ran_resource_manager_tester, when_srb1_is_added_then_ue_resource_config_is_updated) @@ -190,9 +190,9 @@ TEST_P(du_ran_resource_manager_tester, when_srb1_is_added_then_ue_resource_confi ASSERT_FALSE(resp.release_required()); ASSERT_TRUE(resp.failed_srbs.empty()); - ASSERT_EQ(ue_res->rlc_bearers.size(), 1); - ASSERT_EQ(ue_res->rlc_bearers[0].lcid, srsran::LCID_SRB1); - ASSERT_EQ(ue_res->rlc_bearers[0].rlc_cfg.mode, rlc_mode::am); + ASSERT_EQ(ue_res->cell_group.rlc_bearers.size(), 1); + ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].lcid, srsran::LCID_SRB1); + ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].rlc_cfg.mode, rlc_mode::am); } TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_use_different_sr_offsets) @@ -207,7 +207,7 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u for (unsigned i = 0; i != nof_avail_sr_offsets; ++i) { const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); ASSERT_FALSE(ue_res.empty()); - const auto& sr_res_list = ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_periodicity_to_slot(sr_res_list[0].period), sr_period); if (cell_cfg_list[0].tdd_ul_dl_cfg_common.has_value()) { @@ -220,7 +220,7 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); // Check if PUCCH config is correctly updated. - const serving_cell_config serving_cell_cfg = ue_res->cells[0].serv_cell_cfg; + const serving_cell_config serving_cell_cfg = ue_res->cell_group.cells[0].serv_cell_cfg; std::optional csi_pucch_res{}; const bool has_csi_cfg = serving_cell_cfg.csi_meas_cfg.has_value() and not serving_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list.empty() and @@ -232,8 +232,8 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u .pucch_csi_res_list.front() .pucch_res_id.cell_res_id); } - ASSERT_TRUE( - verify_pucch_cfg(ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value(), csi_pucch_res)); + ASSERT_TRUE(verify_pucch_cfg(ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value(), + csi_pucch_res)); next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); } @@ -248,18 +248,21 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u // Removing one UE, should make one SR offset available. const du_ue_index_t ue_idx_to_rem = to_du_ue_index(test_rgen::uniform_int(0, ues.size() - 1)); const unsigned rem_pucch_resource = ues[ue_idx_to_rem] - ->cells[0] + ->cell_group.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] .pucch_res_id.cell_res_id; const unsigned rem_sr_offset = - ues[ue_idx_to_rem]->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset; + ues[ue_idx_to_rem]->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset; ues.erase(ue_idx_to_rem); next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); ASSERT_FALSE(ue_res.empty()); ASSERT_EQ(rem_pucch_resource, - ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].pucch_res_id.cell_res_id); - ASSERT_EQ(rem_sr_offset, ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); + ue_res->cell_group.cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] + .pucch_res_id.cell_res_id); + ASSERT_EQ(rem_sr_offset, + ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); } INSTANTIATE_TEST_SUITE_P(du_ran_resource_manager_tester, @@ -448,7 +451,7 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi ASSERT_FALSE(ue_res.empty()); // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_periodicity_to_slot(sr_res_list[0].period), sr_period); // Make sure the SR is in a fully-UL slot. @@ -462,8 +465,8 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); // Check if the CSI has been assigned to the UE. - ASSERT_TRUE(has_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg)); - const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg); + ASSERT_TRUE(has_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg)); + const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg); ASSERT_FALSE(ue_csi_cfg.pucch_csi_res_list.empty()); const unsigned ue_csi_pucch_res_id = ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.cell_res_id; const unsigned ue_csi_pucch_offset = ue_csi_cfg.report_slot_offset; @@ -482,11 +485,13 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi const interval expected_f1 = get_expected_pucch_res_id_interval(static_cast(next_ue_index), srsran::pucch_format::FORMAT_1); const interval actual_f1 = get_pucch_res_id_interval( - ue_res->cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), srsran::pucch_format::FORMAT_1); + ue_res->cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), + srsran::pucch_format::FORMAT_1); const interval expected_f2 = get_expected_pucch_res_id_interval(static_cast(next_ue_index), srsran::pucch_format::FORMAT_2); const interval actual_f2 = get_pucch_res_id_interval( - ue_res->cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), srsran::pucch_format::FORMAT_2); + ue_res->cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), + srsran::pucch_format::FORMAT_2); ASSERT_TRUE(expected_f1.start() == actual_f1.start() and expected_f1.stop() == actual_f1.stop()); ASSERT_TRUE(expected_f2.start() == actual_f2.start() and expected_f2.stop() == actual_f2.stop()); @@ -504,14 +509,16 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi // Remove 1 UE and verify if the new resource can be allocated to another UE. const du_ue_index_t ue_idx_to_rem = to_du_ue_index(test_rgen::uniform_int(0, ues.size() - 1)); const unsigned rem_sr_pucch_resource = ues[ue_idx_to_rem] - ->cells[0] + ->cell_group.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] .pucch_res_id.cell_res_id; const unsigned rem_sr_offset = - ues[ue_idx_to_rem]->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset; - const unsigned rem_csi_pucch_resource_id = - get_ue_csi_cfg(ues[ue_idx_to_rem]->cells[0].serv_cell_cfg).pucch_csi_res_list.front().pucch_res_id.cell_res_id; - const unsigned rem_csi_offset = get_ue_csi_cfg(ues[ue_idx_to_rem]->cells[0].serv_cell_cfg).report_slot_offset; + ues[ue_idx_to_rem]->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset; + const unsigned rem_csi_pucch_resource_id = get_ue_csi_cfg(ues[ue_idx_to_rem]->cell_group.cells[0].serv_cell_cfg) + .pucch_csi_res_list.front() + .pucch_res_id.cell_res_id; + const unsigned rem_csi_offset = + get_ue_csi_cfg(ues[ue_idx_to_rem]->cell_group.cells[0].serv_cell_cfg).report_slot_offset; ues.erase(ue_idx_to_rem); next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); @@ -522,16 +529,20 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi const bool nof_ue_limited_by_sr_resources = std::get<1>(avail_res); if (nof_ue_limited_by_sr_resources) { ASSERT_EQ(rem_sr_pucch_resource, - ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].pucch_res_id.cell_res_id); - ASSERT_EQ(rem_sr_offset, ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); + ue_res->cell_group.cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] + .pucch_res_id.cell_res_id); + ASSERT_EQ(rem_sr_offset, + ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); } // If the resources and offset were limited by the CSI, then check if a new CSI can be allocated. const bool nof_ue_limited_by_csi_resources = std::get<2>(avail_res); if (nof_ue_limited_by_csi_resources) { - ASSERT_EQ(rem_csi_pucch_resource_id, - get_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg).pucch_csi_res_list.front().pucch_res_id.cell_res_id); - ASSERT_EQ(rem_csi_offset, get_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg).report_slot_offset); + ASSERT_EQ( + rem_csi_pucch_resource_id, + get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg).pucch_csi_res_list.front().pucch_res_id.cell_res_id); + ASSERT_EQ(rem_csi_offset, get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg).report_slot_offset); } } @@ -610,15 +621,15 @@ TEST_P(du_ran_res_mng_pucch_cnt_tester, test_du_pucch_cnt) ASSERT_FALSE(ue_res.empty()); // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_offsets.count(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)), 0); sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); unsigned sr_offset = sr_res_list[0].offset; // Check if the CSI has been assigned to the UE. - ASSERT_TRUE(has_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg)); - const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cells[0].serv_cell_cfg); + ASSERT_TRUE(has_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg)); + const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg); ASSERT_FALSE(ue_csi_cfg.pucch_csi_res_list.empty()); const unsigned csi_pucch_res_id = ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.cell_res_id; const unsigned csi_offset = ue_csi_cfg.report_slot_offset; @@ -704,7 +715,7 @@ TEST_P(du_ran_res_mng_pucch_cnt_sr_only_tester, test_du_pucch_cnt_sr_only) ASSERT_FALSE(ue_res.empty()); // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_offsets.count(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)), 0); sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 61ddbe4783..72caa1e1f3 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -76,32 +76,34 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ // Prepare DU resource allocator response. cell_res_alloc.next_context_update_result = cell_res_alloc.ue_resource_pool[req.ue_index]; for (srb_id_t srb_id : req.srbs_to_setup) { - cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); - cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); - cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { - cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); - cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; - cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); - cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().drb_id = drb.drb_id; + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = + uint_to_lcid(3 + (unsigned)drb.drb_id); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); } for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { - cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); - cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; - cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); - cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().drb_id = drb.drb_id; + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = + uint_to_lcid(3 + (unsigned)drb.drb_id); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); } for (drb_id_t drb_id : req.drbs_to_rem) { - auto it = std::find_if(cell_res_alloc.next_context_update_result.rlc_bearers.begin(), - cell_res_alloc.next_context_update_result.rlc_bearers.end(), + auto it = std::find_if(cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.begin(), + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.end(), [drb_id](const auto& b) { return b.drb_id == drb_id; }); - if (it != cell_res_alloc.next_context_update_result.rlc_bearers.end()) { - cell_res_alloc.next_context_update_result.rlc_bearers.erase(it); + if (it != cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.end()) { + cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.erase(it); } } diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 74bae84aa7..4e23de0e77 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -36,18 +36,22 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test void start_procedure(const f1ap_ue_context_update_request& req) { for (srb_id_t srb_id : req.srbs_to_setup) { - this->cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = + make_default_srb_rlc_config(); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { - this->cell_res_alloc.next_context_update_result.rlc_bearers.emplace_back(); - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().drb_id = drb.drb_id; - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - this->cell_res_alloc.next_context_update_result.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = + uint_to_lcid(3 + (unsigned)drb.drb_id); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().drb_id = drb.drb_id; + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = + make_default_srb_rlc_config(); + this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = + make_default_drb_mac_lc_config(); } proc = launch_async(req, ue_mng, params); @@ -395,10 +399,10 @@ TEST_F(ue_config_tester, when_reestablishment_is_signalled_then_bearers_are_marked_as_reestablishRLC_and_cell_config_are_sent) { // Mark UE as reestablishing. - test_ue->reestablished_cfg_pending = std::make_unique(); - test_ue->reestablished_cfg_pending->rlc_bearers.emplace_back(); - test_ue->reestablished_cfg_pending->rlc_bearers.back().lcid = LCID_MIN_DRB; - test_ue->reestablished_cfg_pending->rlc_bearers.back().drb_id = drb_id_t::drb1; + test_ue->reestablished_cfg_pending = std::make_unique(); + test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.emplace_back(); + test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.back().lcid = LCID_MIN_DRB; + test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.back().drb_id = drb_id_t::drb1; // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = diff --git a/tests/unittests/du_manager/procedures/ue_creation_test.cpp b/tests/unittests/du_manager/procedures/ue_creation_test.cpp index a65311d27e..fedfadc009 100644 --- a/tests/unittests/du_manager/procedures/ue_creation_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_creation_test.cpp @@ -79,7 +79,7 @@ class du_manager_ue_creation_tester : public du_manager_proc_tester, public ::te void set_sr_offset(du_ue_index_t ue_index, du_cell_index_t cell_idx, unsigned sr_offset) { - this->cell_res_alloc.next_context_update_result.cells[0] + this->cell_res_alloc.next_context_update_result.cell_group.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] .offset = sr_offset; } @@ -135,7 +135,7 @@ TEST_F(du_manager_ue_creation_tester, // Test Preamble. // > Generate SR offsets for two UEs. du_ue_index_t ue_idx1 = to_du_ue_index(0), ue_idx2 = to_du_ue_index(1); - unsigned sr_period = sr_periodicity_to_slot(this->cell_res_alloc.next_context_update_result.cells[0] + unsigned sr_period = sr_periodicity_to_slot(this->cell_res_alloc.next_context_update_result.cell_group.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] .period); unsigned sr_offset1 = test_rgen::uniform_int(0, sr_period - 1); From c79e0e1323d55b7301a685c5f49dbf1dcfffa3f0 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 7 Aug 2024 22:20:39 +0200 Subject: [PATCH 215/407] du_manager: refactor DU UE bearer resource management --- .../ran_resource_management/CMakeLists.txt | 1 + .../du_bearer_resource_manager.cpp | 284 ++++++++++++++++++ .../du_bearer_resource_manager.h | 55 ++++ .../du_ran_resource_manager_impl.cpp | 202 +------------ .../du_ran_resource_manager_impl.h | 10 +- 5 files changed, 360 insertions(+), 192 deletions(-) create mode 100644 lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp create mode 100644 lib/du_manager/ran_resource_management/du_bearer_resource_manager.h diff --git a/lib/du_manager/ran_resource_management/CMakeLists.txt b/lib/du_manager/ran_resource_management/CMakeLists.txt index 494c915553..ff62eaf469 100644 --- a/lib/du_manager/ran_resource_management/CMakeLists.txt +++ b/lib/du_manager/ran_resource_management/CMakeLists.txt @@ -9,5 +9,6 @@ add_library(du_resource_manager du_ran_resource_manager_impl.cpp du_pucch_resource_manager.cpp + du_bearer_resource_manager.cpp pucch_resource_generator.cpp) target_link_libraries(du_resource_manager du_manager_converters srsran_du_config_validators mac_configuration_helpers) diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp new file mode 100644 index 0000000000..ff2cbb3e08 --- /dev/null +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp @@ -0,0 +1,284 @@ +/* + * + * 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 "du_bearer_resource_manager.h" +#include "srsran/mac/config/mac_config_helpers.h" +#include "srsran/rlc/rlc_srb_config_factory.h" + +using namespace srsran; +using namespace srs_du; + +template +static auto find_by_srb_id(srb_id_t srb_id, Vec&& bearers) +{ + return std::find_if( + bearers.begin(), bearers.end(), [srb_id](const auto& b) { return b.lcid == srb_id_to_lcid(srb_id); }); +} + +template +static auto find_by_drb_id(drb_id_t drb_id, Vec&& bearers) +{ + return std::find_if(bearers.begin(), bearers.end(), [drb_id](const auto& b) { return b.drb_id == drb_id; }); +} + +/// \brief Finds an unused LCID for DRBs given a list of UE configured RLC bearers. +static lcid_t find_empty_lcid(span rlc_bearers) +{ + static_vector used_lcids; + for (const auto& bearer : rlc_bearers) { + if (bearer.drb_id.has_value()) { + used_lcids.push_back(bearer.lcid); + } + } + std::sort(used_lcids.begin(), used_lcids.end()); + if (used_lcids.empty() or used_lcids[0] > LCID_MIN_DRB) { + return LCID_MIN_DRB; + } + auto it = std::adjacent_find(used_lcids.begin(), used_lcids.end(), [](lcid_t l, lcid_t r) { return l + 1 < r; }); + if (it == used_lcids.end()) { + // no gaps found. Use the last value + 1. + --it; + } + // beginning of the gap + 1. + lcid_t lcid = uint_to_lcid(static_cast(*it) + 1U); + if (lcid > LCID_MAX_DRB) { + return INVALID_LCID; + } + return lcid; +} + +static error_type validate_drb_setup_request(const f1ap_drb_to_setup& drb, + span rlc_bearers, + const std::map& qos_config) +{ + // Validate QOS config. + five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); + auto qos_it = qos_config.find(fiveqi); + if (qos_it == qos_config.end()) { + return make_unexpected(fmt::format("No {} 5QI configured", fiveqi)); + } + const du_qos_config& qos = qos_it->second; + if (qos.rlc.mode != drb.mode) { + return make_unexpected( + fmt::format("RLC mode mismatch for {}. QoS config for {} configures {} but CU-CP requested {}", + drb.drb_id, + fiveqi, + qos.rlc.mode, + drb.mode)); + } + + // Search for established DRB with matching DRB-Id. + auto prev_drb_it = find_by_drb_id(drb.drb_id, rlc_bearers); + if (prev_drb_it != rlc_bearers.end()) { + return make_unexpected("DRB-Id already exists"); + } + + return {}; +} + +static error_type validate_drb_modification_request(const f1ap_drb_to_modify& drb, + span rlc_bearers) +{ + // Search for established DRB with matching DRB-Id. + auto prev_drb_it = find_by_drb_id(drb.drb_id, rlc_bearers); + if (prev_drb_it == rlc_bearers.end()) { + return make_unexpected("DRB-Id not found"); + } + return {}; +} + +static void reestablish_context(du_ue_resource_config& new_ue_cfg, const du_ue_resource_config& old_ue_cfg) +{ + for (const rlc_bearer_config& old_bearer : old_ue_cfg.cell_group.rlc_bearers) { + auto it = std::find_if(new_ue_cfg.cell_group.rlc_bearers.begin(), + new_ue_cfg.cell_group.rlc_bearers.end(), + [&old_bearer](const rlc_bearer_config& item) { + return item.drb_id == old_bearer.drb_id and + (item.drb_id.has_value() or (item.lcid == old_bearer.lcid)); + }); + if (it == new_ue_cfg.cell_group.rlc_bearers.end()) { + // Bearer not found in new context. Add it. + new_ue_cfg.cell_group.rlc_bearers.push_back(old_bearer); + if (old_bearer.drb_id.has_value()) { + const drb_upper_layer_config& old_drb = *find_by_drb_id(old_bearer.drb_id.value(), old_ue_cfg.drbs); + new_ue_cfg.drbs.push_back(old_drb); + } + } else { + // Bearer already exists. Overwrite it. + *it = old_bearer; + if (old_bearer.drb_id.has_value()) { + const drb_upper_layer_config& old_drb = *find_by_drb_id(old_bearer.drb_id.value(), old_ue_cfg.drbs); + drb_upper_layer_config& new_drb = *find_by_drb_id(old_bearer.drb_id.value(), new_ue_cfg.drbs); + new_drb = old_drb; + } + } + } +} + +// du_bearer_resource_manager + +du_bearer_resource_manager::du_bearer_resource_manager(const std::map& srbs_, + const std::map& qos_, + srslog::basic_logger& logger_) : + srb_config(srbs_), qos_config(qos_), logger(logger_) +{ +} + +du_ue_bearer_resource_update_response +du_bearer_resource_manager::update(du_ue_resource_config& ue_cfg, + const du_ue_bearer_resource_update_request& upd_req, + const du_ue_resource_config* reestablished_context) +{ + du_ue_bearer_resource_update_response resp; + + // > In case of RRC Reestablishment, retrieve old DRB context, to be considered in the config update. + if (reestablished_context != nullptr) { + reestablish_context(ue_cfg, *reestablished_context); + } + + // Remove DRBs. + rem_drbs(ue_cfg, upd_req); + + // Setup SRBs. + setup_srbs(ue_cfg, upd_req); + + // Setup DRBs. + resp.drbs_failed_to_setup = setup_drbs(ue_cfg, upd_req); + + // Modify DRBs. + resp.drbs_failed_to_mod = modify_drbs(ue_cfg, upd_req); + + // Sort RAN bearers by LCID. + std::sort(ue_cfg.cell_group.rlc_bearers.begin(), + ue_cfg.cell_group.rlc_bearers.end(), + [](const auto& lhs, const auto& rhs) { return lhs.lcid < rhs.lcid; }); + + // Sort DRBs by DRB ID. + std::sort( + ue_cfg.drbs.begin(), ue_cfg.drbs.end(), [](const auto& lhs, const auto& rhs) { return lhs.drb_id < rhs.drb_id; }); + + return resp; +} + +void du_bearer_resource_manager::setup_srbs(du_ue_resource_config& ue_cfg, + const du_ue_bearer_resource_update_request& upd_req) +{ + for (srb_id_t srb_id : upd_req.srbs_to_setup) { + auto srb_it = find_by_srb_id(srb_id, ue_cfg.cell_group.rlc_bearers); + if (srb_it != ue_cfg.cell_group.rlc_bearers.end()) { + // The SRB is already setup (e.g. SRB1 gets setup automatically). + continue; + } + + auto srb_config_it = srb_config.find(srb_id); + lcid_t lcid = srb_id_to_lcid(srb_id); + auto& new_srb = ue_cfg.cell_group.rlc_bearers.emplace_back(); + new_srb.lcid = lcid; + if (srb_config_it != srb_config.end()) { + new_srb.rlc_cfg = srb_config_it->second.rlc; + new_srb.mac_cfg = srb_config_it->second.mac; + } else { + new_srb.rlc_cfg = make_default_srb_rlc_config(); + new_srb.mac_cfg = make_default_srb_mac_lc_config(lcid); + } + } +} + +std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_config& ue_cfg, + const du_ue_bearer_resource_update_request& upd_req) +{ + std::vector failed_drbs; + + for (const f1ap_drb_to_setup& drb_to_setup : upd_req.drbs_to_setup) { + auto res = validate_drb_setup_request(drb_to_setup, ue_cfg.cell_group.rlc_bearers, qos_config); + if (not res.has_value()) { + failed_drbs.push_back(drb_to_setup.drb_id); + logger.warning("Failed to allocate {}. Cause: {}", drb_to_setup.drb_id, res.error()); + continue; + } + + // Allocate LCID. + lcid_t lcid = find_empty_lcid(ue_cfg.cell_group.rlc_bearers); + if (lcid > LCID_MAX_DRB) { + logger.warning("Failed to allocate {}. Cause: No available LCIDs", drb_to_setup.drb_id); + failed_drbs.push_back(drb_to_setup.drb_id); + continue; + } + + // Get QoS Config from 5QI + five_qi_t fiveqi = drb_to_setup.qos_info.drb_qos.qos_characteristics.get_five_qi(); + const du_qos_config& qos = qos_config.at(fiveqi); + + // Create new DRB QoS Flow. + drb_upper_layer_config& drb_qos = ue_cfg.drbs.emplace_back(); + drb_qos.drb_id = drb_to_setup.drb_id; + drb_qos.pdcp_sn_len = drb_to_setup.pdcp_sn_len; + drb_qos.s_nssai = drb_to_setup.qos_info.s_nssai; + drb_qos.qos = drb_to_setup.qos_info.drb_qos; + + // Create new L2 DRB. + rlc_bearer_config& ran_bearer = ue_cfg.cell_group.rlc_bearers.emplace_back(); + ran_bearer.lcid = lcid; + ran_bearer.drb_id = drb_to_setup.drb_id; + ran_bearer.rlc_cfg = qos.rlc; + ran_bearer.mac_cfg = qos.mac; + + // Update pdcp_sn_len in RLC config + auto& rlc_cfg = ran_bearer.rlc_cfg; + switch (rlc_cfg.mode) { + case rlc_mode::am: + rlc_cfg.am.tx.pdcp_sn_len = drb_to_setup.pdcp_sn_len; + break; + case rlc_mode::um_bidir: + case rlc_mode::um_unidir_dl: + rlc_cfg.um.tx.pdcp_sn_len = drb_to_setup.pdcp_sn_len; + break; + default: + break; + } + } + + return failed_drbs; +} + +std::vector du_bearer_resource_manager::modify_drbs(du_ue_resource_config& ue_cfg, + const du_ue_bearer_resource_update_request& upd_req) +{ + std::vector failed_drbs; + + for (const f1ap_drb_to_modify& drb_to_modify : upd_req.drbs_to_mod) { + auto res = validate_drb_modification_request(drb_to_modify, ue_cfg.cell_group.rlc_bearers); + if (not res.has_value()) { + logger.warning("Failed to modify {}. Cause: {}", drb_to_modify.drb_id, res.error()); + failed_drbs.push_back(drb_to_modify.drb_id); + continue; + } + } + + return failed_drbs; +} + +void du_bearer_resource_manager::rem_drbs(du_ue_resource_config& ue_cfg, + const du_ue_bearer_resource_update_request& upd_req) +{ + for (drb_id_t drb_id : upd_req.drbs_to_rem) { + auto ran_bearer_it = find_by_drb_id(drb_id, ue_cfg.cell_group.rlc_bearers); + if (ran_bearer_it == ue_cfg.cell_group.rlc_bearers.end()) { + logger.warning("Failed to release {}. Cause: DRB not found", drb_id); + continue; + } + + auto bearer_qos_it = find_by_drb_id(drb_id, ue_cfg.drbs); + + // Remove DRB + ue_cfg.cell_group.rlc_bearers.erase(ran_bearer_it); + ue_cfg.drbs.erase(bearer_qos_it); + } +} diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.h b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.h new file mode 100644 index 0000000000..8084dcec39 --- /dev/null +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.h @@ -0,0 +1,55 @@ +/* + * + * 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 "du_ue_resource_config.h" + +namespace srsran { +namespace srs_du { + +struct du_ue_bearer_resource_update_request { + span srbs_to_setup; + span drbs_to_setup; + span drbs_to_mod; + span drbs_to_rem; +}; + +struct du_ue_bearer_resource_update_response { + std::vector drbs_failed_to_setup; + std::vector drbs_failed_to_mod; +}; + +class du_bearer_resource_manager +{ +public: + du_bearer_resource_manager(const std::map& srbs, + const std::map& qos, + srslog::basic_logger& logger); + + /// \brief Allocate bearer resources for a given UE. The resources are stored in the UE's DU UE resource config. + /// \return true if allocation was successful. + du_ue_bearer_resource_update_response update(du_ue_resource_config& ue_cfg, + const du_ue_bearer_resource_update_request& request, + const du_ue_resource_config* reestablished_context); + +private: + void setup_srbs(du_ue_resource_config& ue_cfg, const du_ue_bearer_resource_update_request& request); + std::vector setup_drbs(du_ue_resource_config& ue_cfg, const du_ue_bearer_resource_update_request& request); + std::vector modify_drbs(du_ue_resource_config& ue_cfg, const du_ue_bearer_resource_update_request& request); + void rem_drbs(du_ue_resource_config& ue_cfg, const du_ue_bearer_resource_update_request& request); + + const std::map& srb_config; + const std::map& qos_config; + srslog::basic_logger& logger; +}; + +} // namespace srs_du +} // namespace srsran \ No newline at end of file diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index ea91ce7577..542e69aaab 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -10,40 +10,12 @@ #include "du_ran_resource_manager_impl.h" #include "srsran/mac/config/mac_cell_group_config_factory.h" -#include "srsran/mac/config/mac_config_helpers.h" -#include "srsran/rlc/rlc_srb_config_factory.h" #include "srsran/scheduler/config/serving_cell_config_factory.h" #include "srsran/srslog/srslog.h" using namespace srsran; using namespace srs_du; -/// \brief Finds an unused LCID for DRBs given a list of UE configured RLC bearers. -static lcid_t find_empty_lcid(const std::vector& rlc_bearers) -{ - static_vector used_lcids; - for (const auto& bearer : rlc_bearers) { - if (bearer.drb_id.has_value()) { - used_lcids.push_back(bearer.lcid); - } - } - std::sort(used_lcids.begin(), used_lcids.end()); - if (used_lcids.empty() or used_lcids[0] > LCID_MIN_DRB) { - return LCID_MIN_DRB; - } - auto it = std::adjacent_find(used_lcids.begin(), used_lcids.end(), [](lcid_t l, lcid_t r) { return l + 1 < r; }); - if (it == used_lcids.end()) { - // no gaps found. Use the last value + 1. - --it; - } - // beginning of the gap + 1. - lcid_t lcid = uint_to_lcid(static_cast(*it) + 1U); - if (lcid > LCID_MAX_DRB) { - return INVALID_LCID; - } - return lcid; -} - du_ue_ran_resource_updater_impl::du_ue_ran_resource_updater_impl(du_ue_resource_config* cell_grp_cfg_, du_ran_resource_manager_impl& parent_, du_ue_index_t ue_index_) : @@ -68,13 +40,12 @@ du_ue_ran_resource_updater_impl::update(du_cell_index_t pc du_ran_resource_manager_impl::du_ran_resource_manager_impl(span cell_cfg_list_, const scheduler_expert_config& scheduler_cfg, - const std::map& srbs_, - const std::map& qos_) : + const std::map& srb_config, + const std::map& qos_config) : cell_cfg_list(cell_cfg_list_), - srb_config(srbs_), - qos_config(qos_), logger(srslog::fetch_basic_logger("DU-MNG")), - pucch_res_mng(cell_cfg_list, scheduler_cfg.ue.max_pucchs_per_slot) + pucch_res_mng(cell_cfg_list, scheduler_cfg.ue.max_pucchs_per_slot), + bearer_res_mng(srb_config, qos_config, logger) { } @@ -83,7 +54,7 @@ ue_ran_resource_configurator du_ran_resource_manager_impl::create_ue_resource_co { if (ue_res_pool.contains(ue_index)) { return ue_ran_resource_configurator{std::unique_ptr{nullptr}, - std::string("Double allocation of same not supported")}; + std::string("Double allocation of same UE not supported")}; } ue_res_pool.emplace(ue_index); auto& mcg = ue_res_pool[ue_index].cg_cfg; @@ -98,66 +69,6 @@ ue_ran_resource_configurator du_ran_resource_manager_impl::create_ue_resource_co return ue_ran_resource_configurator{std::make_unique(&mcg, *this, ue_index)}; } -static error_type validate_drb_modification_request(const f1ap_drb_to_modify& drb, - span rlc_bearers) -{ - // Search for established DRB with matching DRB-Id. - auto prev_drb_it = std::find_if(rlc_bearers.begin(), rlc_bearers.end(), [&drb](const rlc_bearer_config& item) { - return item.drb_id.has_value() and item.drb_id.value() == drb.drb_id; - }); - if (prev_drb_it == rlc_bearers.end()) { - return make_unexpected(fmt::format("Failed to modify {}. Cause: DRB not found", drb.drb_id)); - } - return {}; -} - -static error_type validate_drb_setup_request(const f1ap_drb_to_setup& drb, - span rlc_bearers, - const std::map& qos_config) -{ - // Validate QOS config. - five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); - auto qos_it = qos_config.find(fiveqi); - if (qos_it == qos_config.end()) { - return make_unexpected(fmt::format("Failed to allocate {}. Cause: No {} 5QI configured", drb.drb_id, fiveqi)); - } - const du_qos_config& qos = qos_it->second; - if (qos.rlc.mode != drb.mode) { - return make_unexpected( - fmt::format("RLC mode mismatch for {}. QoS config for {} configures {} but CU-CP requested {}", - drb.drb_id, - fiveqi, - qos.rlc.mode, - drb.mode)); - } - - // Search for established DRB with matching DRB-Id. - auto prev_drb_it = std::find_if(rlc_bearers.begin(), rlc_bearers.end(), [&drb](const rlc_bearer_config& item) { - return item.drb_id.has_value() and item.drb_id.value() == drb.drb_id; - }); - if (prev_drb_it != rlc_bearers.end()) { - return make_unexpected(fmt::format("Failed to allocate {}. Cause: DRB already exists", drb.drb_id)); - } - - return {}; -} - -static void reestablish_context(du_ue_resource_config& new_ue_cfg, const du_ue_resource_config& old_ue_cfg) -{ - for (const rlc_bearer_config& old_bearer : old_ue_cfg.cell_group.rlc_bearers) { - auto it = std::find_if(new_ue_cfg.cell_group.rlc_bearers.begin(), - new_ue_cfg.cell_group.rlc_bearers.end(), - [&old_bearer](const rlc_bearer_config& item) { - return item.drb_id == old_bearer.drb_id and - (item.drb_id.has_value() or (item.lcid == old_bearer.lcid)); - }); - if (it == new_ue_cfg.cell_group.rlc_bearers.end()) { - // Bearer not found in new context. Add it. - new_ue_cfg.cell_group.rlc_bearers.push_back(old_bearer); - } - } -} - du_ue_resource_update_response du_ran_resource_manager_impl::update_context(du_ue_index_t ue_index, du_cell_index_t pcell_idx, @@ -185,100 +96,15 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } - // > In case of RRC Reestablishment, retrieve old DRB context, to be considered in the config update. - if (reestablished_context != nullptr) { - reestablish_context(ue_mcg, *reestablished_context); - } - - // > Deallocate removed SRBs / DRBs. - for (drb_id_t drb_id : upd_req.drbs_to_rem) { - auto it = std::find_if(ue_mcg.cell_group.rlc_bearers.begin(), - ue_mcg.cell_group.rlc_bearers.end(), - [drb_id](const rlc_bearer_config& b) { return b.drb_id == drb_id; }); - if (it != ue_mcg.cell_group.rlc_bearers.end()) { - ue_mcg.cell_group.rlc_bearers.erase(it); - continue; - } else { - logger.warning("Failed to release {}. Cause: DRB not found", drb_id); - } - } - - // > Allocate new SRBs. - for (srb_id_t srb_id : upd_req.srbs_to_setup) { - // >> New or Modified SRB. - lcid_t lcid = srb_id_to_lcid(srb_id); - if (std::any_of(ue_mcg.cell_group.rlc_bearers.begin(), - ue_mcg.cell_group.rlc_bearers.end(), - [lcid](const auto& item) { return item.lcid == lcid; })) { - // The SRB is already setup (e.g. SRB1 gets setup automatically). - continue; - } - ue_mcg.cell_group.rlc_bearers.emplace_back(); - ue_mcg.cell_group.rlc_bearers.back().lcid = lcid; - - auto srb_it = srb_config.find(srb_id); - if (srb_it != srb_config.end()) { - ue_mcg.cell_group.rlc_bearers.back().rlc_cfg = srb_it->second.rlc; - ue_mcg.cell_group.rlc_bearers.back().mac_cfg = srb_it->second.mac; - } else { - ue_mcg.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - ue_mcg.cell_group.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(lcid); - } - } - - // > Create new DRBs. - for (const f1ap_drb_to_setup& drb : upd_req.drbs_to_setup) { - auto res = validate_drb_setup_request(drb, ue_mcg.cell_group.rlc_bearers, qos_config); - if (not res.has_value()) { - resp.failed_drbs.push_back(drb.drb_id); - continue; - } - - // > Allocate LCID. - lcid_t lcid = find_empty_lcid(ue_mcg.cell_group.rlc_bearers); - if (lcid > LCID_MAX_DRB) { - logger.warning("Failed to allocate {}. Cause: No available LCIDs", drb.drb_id); - resp.failed_drbs.push_back(drb.drb_id); - continue; - } - - // >> Get RLC config from 5QI - five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); - const du_qos_config& qos = qos_config.at(fiveqi); - ue_mcg.cell_group.rlc_bearers.emplace_back(); - ue_mcg.cell_group.rlc_bearers.back().lcid = lcid; - ue_mcg.cell_group.rlc_bearers.back().drb_id = drb.drb_id; - ue_mcg.cell_group.rlc_bearers.back().rlc_cfg = qos.rlc; - ue_mcg.cell_group.rlc_bearers.back().mac_cfg = qos.mac; - - // Update pdcp_sn_len in RLC config - auto& rlc_cfg = ue_mcg.cell_group.rlc_bearers.back().rlc_cfg; - switch (rlc_cfg.mode) { - case rlc_mode::am: - rlc_cfg.am.tx.pdcp_sn_len = drb.pdcp_sn_len; - break; - case rlc_mode::um_bidir: - case rlc_mode::um_unidir_dl: - rlc_cfg.um.tx.pdcp_sn_len = drb.pdcp_sn_len; - break; - default: - break; - } - } - - // > Modify existing DRBs. - for (const f1ap_drb_to_modify& drb : upd_req.drbs_to_mod) { - auto res = validate_drb_modification_request(drb, ue_mcg.cell_group.rlc_bearers); - if (not res.has_value()) { - resp.failed_drbs.push_back(drb.drb_id); - continue; - } - } - - // > Sort bearers by LCID. - std::sort(ue_mcg.cell_group.rlc_bearers.begin(), - ue_mcg.cell_group.rlc_bearers.end(), - [](const auto& lhs, const auto& rhs) { return lhs.lcid < rhs.lcid; }); + // > Update UE SRBs and DRBs. + du_ue_bearer_resource_update_response bearer_resp = + bearer_res_mng.update(ue_mcg, + du_ue_bearer_resource_update_request{ + upd_req.srbs_to_setup, upd_req.drbs_to_setup, upd_req.drbs_to_mod, upd_req.drbs_to_rem}, + reestablished_context); + resp.failed_drbs = std::move(bearer_resp.drbs_failed_to_setup); + resp.failed_drbs.insert( + resp.failed_drbs.end(), bearer_resp.drbs_failed_to_mod.begin(), bearer_resp.drbs_failed_to_mod.end()); // > Allocate resources for new or modified cells. if (not ue_mcg.cell_group.cells.contains(0) or ue_mcg.cell_group.cells[0].serv_cell_cfg.cell_index != pcell_idx) { diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h index 3c34c7b3bb..49c1423bb9 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h @@ -10,6 +10,7 @@ #pragma once +#include "du_bearer_resource_manager.h" #include "du_pucch_resource_manager.h" #include "du_ran_resource_manager.h" #include "srsran/ran/qos/five_qi.h" @@ -83,10 +84,8 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager allocate_cell_resources(du_ue_index_t ue_index, du_cell_index_t cell_index, serv_cell_index_t serv_cell_index); void deallocate_cell_resources(du_ue_index_t ue_index, serv_cell_index_t serv_cell_index); - span cell_cfg_list; - const std::map& srb_config; - const std::map& qos_config; - srslog::basic_logger& logger; + span cell_cfg_list; + srslog::basic_logger& logger; struct ue_res_item { du_ue_resource_config cg_cfg; @@ -97,6 +96,9 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager /// Allocator of UE PUCCH resources. du_pucch_resource_manager pucch_res_mng; + + /// Allocator of UE bearer resources. + du_bearer_resource_manager bearer_res_mng; }; } // namespace srs_du From 84e025287bab2e61101c75441344f5209cf3f69c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 8 Aug 2024 09:20:59 +0200 Subject: [PATCH 216/407] du_manager: retrieve QoS during DRB reestablishment --- .../procedures/ue_configuration_procedure.cpp | 99 +++++++++---------- .../procedures/ue_configuration_procedure.h | 3 +- .../du_bearer_resource_manager.cpp | 12 +++ .../du_ran_resource_manager.h | 1 - .../du_ue_resource_config.h | 1 + .../du_manager/du_manager_test_helpers.cpp | 2 +- .../du_manager/du_manager_test_helpers.h | 1 + .../du_ran_resource_manager_test.cpp | 1 - .../du_manager_procedure_test_helpers.cpp | 22 +++-- .../procedures/ue_configuration_test.cpp | 50 ++++++---- 10 files changed, 111 insertions(+), 81 deletions(-) diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 3defb7f23b..8509ab0fd6 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -44,7 +44,8 @@ void ue_configuration_procedure::operator()(coro_contextresources.value(); - if (ue->resources.update(ue->pcell_index, request, ue->reestablished_cfg_pending.get()).release_required()) { + ue_res_cfg_resp = ue->resources.update(ue->pcell_index, request, ue->reestablished_cfg_pending.get()); + if (ue_res_cfg_resp.release_required()) { proc_logger.log_proc_failure("Failed to allocate DU UE resources"); CORO_EARLY_RETURN(make_ue_config_failure()); } @@ -81,7 +82,7 @@ void ue_configuration_procedure::update_ue_context() } srb_id_t srbid = to_srb_id(bearer.lcid); if (ue->bearers.srbs().contains(srbid)) { - // >> In case the SRB already exists, we ignore the request for its configuration. + // >> In case the SRB already exists, we ignore the request for its reconfiguration. continue; } srbs_added.push_back(srbid); @@ -121,43 +122,38 @@ void ue_configuration_procedure::update_ue_context() // Note: This DRB pointer will remain valid and accessible from other layers until we update the latter. for (const drb_id_t& drb_to_rem : request.drbs_to_rem) { if (ue->bearers.drbs().count(drb_to_rem) == 0) { - proc_logger.log_proc_warning("Failed to release {}. Cause: DRB does not exist", drb_to_rem); + proc_logger.log_proc_warning("Failed to release {}. Cause: DRB entity does not exist", drb_to_rem); continue; } - srsran_assert(std::any_of(prev_ue_res_cfg.cell_group.rlc_bearers.begin(), - prev_ue_res_cfg.cell_group.rlc_bearers.end(), - [&drb_to_rem](const rlc_bearer_config& e) { return e.drb_id == drb_to_rem; }), - "The bearer to be deleted must already exist"); - drbs_to_rem.push_back(ue->bearers.remove_drb(drb_to_rem)); } // > Create new DU UE DRB objects. for (const f1ap_drb_to_setup& drbtoadd : request.drbs_to_setup) { - if (drbtoadd.uluptnl_info_list.empty()) { - proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtoadd.drb_id); + if (std::find(ue_res_cfg_resp.failed_drbs.begin(), ue_res_cfg_resp.failed_drbs.end(), drbtoadd.drb_id) != + ue_res_cfg_resp.failed_drbs.end()) { + // >> In case it was not possible to setup DRB in the UE resources, we continue to the next DRB. continue; } if (ue->bearers.drbs().count(drbtoadd.drb_id) > 0) { proc_logger.log_proc_warning("Failed to setup {}. Cause: DRB setup for an already existing DRB.", drbtoadd.drb_id); + ue_res_cfg_resp.failed_drbs.push_back(drbtoadd.drb_id); continue; } - // Find the RLC configuration for this DRB. + // Find the configurations for this DRB. auto it = std::find_if(ue->resources->cell_group.rlc_bearers.begin(), ue->resources->cell_group.rlc_bearers.end(), [&drbtoadd](const rlc_bearer_config& e) { return e.drb_id == drbtoadd.drb_id; }); - srsran_assert(it != ue->resources->cell_group.rlc_bearers.end(), - "The bearer config should be created at this point"); - - // Find the F1-U configuration for this DRB. - five_qi_t fiveqi = drbtoadd.qos_info.drb_qos.qos_characteristics.get_five_qi(); - auto f1u_cfg_it = du_params.ran.qos.find(fiveqi); - srsran_assert(f1u_cfg_it != du_params.ran.qos.end(), "Undefined F1-U bearer config for {}", fiveqi); - - // TODO: Adjust QoS characteristics passed while creating a DRB since one DRB can contain multiple QoS flow of - // varying 5QI. + srsran_sanity_check(it != ue->resources->cell_group.rlc_bearers.end(), + "The bearer config should be created at this point"); + auto drb_qos_it = + std::find_if(ue->resources->drbs.begin(), + ue->resources->drbs.end(), + [&drbtoadd](const drb_upper_layer_config& drb) { return drb.drb_id == drbtoadd.drb_id; }); + srsran_sanity_check(drb_qos_it != ue->resources->drbs.end(), "The bearer config should be created at this point"); + five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_five_qi(); // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, @@ -166,15 +162,16 @@ void ue_configuration_procedure::update_ue_context() it->lcid, it->rlc_cfg, it->mac_cfg, - f1u_cfg_it->second.f1u, + drb_qos_it->f1u, drbtoadd.uluptnl_info_list, ue_mng.get_f1u_teid_pool(), du_params, ue->get_rlc_rlf_notifier(), get_5qi_to_qos_characteristics_mapping(fiveqi), - drbtoadd.qos_info.drb_qos.gbr_qos_info, - drbtoadd.qos_info.s_nssai}); + drb_qos_it->qos.gbr_qos_info, + drb_qos_it->s_nssai}); if (drb == nullptr) { + ue_res_cfg_resp.failed_drbs.push_back(drbtoadd.drb_id); proc_logger.log_proc_warning("Failed to create {}. Cause: Failed to allocate DU UE resources.", drbtoadd.drb_id); continue; } @@ -183,52 +180,52 @@ void ue_configuration_procedure::update_ue_context() // > Modify existing UE DRBs. for (const f1ap_drb_to_modify& drbtomod : request.drbs_to_mod) { - if (drbtomod.uluptnl_info_list.empty()) { - proc_logger.log_proc_warning("Failed to create {}. Cause: No UL UP TNL Info List provided.", drbtomod.drb_id); + if (std::find(ue_res_cfg_resp.failed_drbs.begin(), ue_res_cfg_resp.failed_drbs.end(), drbtomod.drb_id) != + ue_res_cfg_resp.failed_drbs.end()) { + // >> Failed to modify DRB, continue to next DRB. continue; } + // Find the RLC configuration for this DRB. auto it = std::find_if(ue->resources->cell_group.rlc_bearers.begin(), ue->resources->cell_group.rlc_bearers.end(), [&drbtomod](const rlc_bearer_config& e) { return e.drb_id == drbtomod.drb_id; }); srsran_assert(it != ue->resources->cell_group.rlc_bearers.end(), "The bearer config should be created at this point"); + auto drb_qos_it = std::find_if(ue->resources->drbs.begin(), + ue->resources->drbs.end(), + [&drbtomod](const auto& drb) { return drb.drb_id == drbtomod.drb_id; }); auto drb_it = ue->bearers.drbs().find(drbtomod.drb_id); if (drb_it == ue->bearers.drbs().end()) { - // It's a DRB modification during RRC Reestablishment. We need to create a new DRB instance. + // >> It's a DRB modification after RRC Reestablishment. We need to create a new DRB instance. - // Find the F1-U configuration for this DRB. - // TODO: Retrieve old UE context for QoS. The way it is now, the old UE QoS has already been lost at this point. - auto f1u_cfg_it = std::find_if(du_params.ran.qos.begin(), du_params.ran.qos.end(), [&it](const auto& p) { - return it->rlc_cfg.mode == p.second.rlc.mode; - }); - srsran_assert(f1u_cfg_it != du_params.ran.qos.end(), "Undefined F1-U bearer config"); + five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_five_qi(); // Create DU DRB instance. - std::unique_ptr drb = - create_drb(drb_creation_info{ue->ue_index, - ue->pcell_index, - drbtomod.drb_id, - it->lcid, - it->rlc_cfg, - it->mac_cfg, - f1u_cfg_it->second.f1u, - drbtomod.uluptnl_info_list, - ue_mng.get_f1u_teid_pool(), - du_params, - ue->get_rlc_rlf_notifier(), - get_5qi_to_qos_characteristics_mapping(f1u_cfg_it->first), - std::nullopt, - {}}); + std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, + ue->pcell_index, + drbtomod.drb_id, + it->lcid, + it->rlc_cfg, + it->mac_cfg, + drb_qos_it->f1u, + drbtomod.uluptnl_info_list, + ue_mng.get_f1u_teid_pool(), + du_params, + ue->get_rlc_rlf_notifier(), + get_5qi_to_qos_characteristics_mapping(fiveqi), + drb_qos_it->qos.gbr_qos_info, + drb_qos_it->s_nssai}); if (drb == nullptr) { proc_logger.log_proc_warning("Failed to create {}. Cause: Failed to allocate DU UE resources.", drbtomod.drb_id); + ue_res_cfg_resp.failed_drbs.push_back(drbtomod.drb_id); continue; } ue->bearers.add_drb(std::move(drb)); } else { - // TODO: Support DRB modifications. + // TODO: Support existing DRB entity modifications. } } } @@ -282,7 +279,8 @@ async_task ue_configuration_procedure::update_m lc_ch.dl_bearer = &bearer.connector.mac_tx_sdu_notifier; } for (const auto& drb : request.drbs_to_mod) { - if (ue->bearers.drbs().count(drb.drb_id) == 0) { + if (std::find(ue_res_cfg_resp.failed_drbs.begin(), ue_res_cfg_resp.failed_drbs.end(), drb.drb_id) != + ue_res_cfg_resp.failed_drbs.end()) { // The DRB failed to be modified. Carry on with other DRBs. continue; } @@ -292,7 +290,6 @@ async_task ue_configuration_procedure::update_m lc_ch.lcid = bearer.lcid; lc_ch.ul_bearer = &bearer.connector.mac_rx_sdu_notifier; lc_ch.dl_bearer = &bearer.connector.mac_tx_sdu_notifier; - // TODO: Support modifications in the MAC config. } // Create Scheduler UE Reconfig Request that will be embedded in the mac configuration request. diff --git a/lib/du_manager/procedures/ue_configuration_procedure.h b/lib/du_manager/procedures/ue_configuration_procedure.h index 9da612d3cb..5e5d509321 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.h +++ b/lib/du_manager/procedures/ue_configuration_procedure.h @@ -52,7 +52,8 @@ class ue_configuration_procedure ue_procedure_logger proc_logger; // Snapshot of the UE resources at the start of the UE configuration procedure. - du_ue_resource_config prev_ue_res_cfg; + du_ue_resource_config prev_ue_res_cfg; + du_ue_resource_update_response ue_res_cfg_resp; // SRBs that were actually added during the configuration. static_vector srbs_added; diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp index ff2cbb3e08..34d9a320f4 100644 --- a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp @@ -74,6 +74,11 @@ static error_type validate_drb_setup_request(const f1ap_drb_to_setu drb.mode)); } + // Validate UL UP TNL INFO. + if (drb.uluptnl_info_list.empty()) { + return make_unexpected("No UL UP TNL Info List provided"); + } + // Search for established DRB with matching DRB-Id. auto prev_drb_it = find_by_drb_id(drb.drb_id, rlc_bearers); if (prev_drb_it != rlc_bearers.end()) { @@ -91,6 +96,12 @@ static error_type validate_drb_modification_request(const f1ap_drb_ if (prev_drb_it == rlc_bearers.end()) { return make_unexpected("DRB-Id not found"); } + + // Validate UL UP TNL INFO. + if (drb.uluptnl_info_list.empty()) { + return make_unexpected("No UL UP TNL Info List provided"); + } + return {}; } @@ -222,6 +233,7 @@ std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_conf drb_qos.pdcp_sn_len = drb_to_setup.pdcp_sn_len; drb_qos.s_nssai = drb_to_setup.qos_info.s_nssai; drb_qos.qos = drb_to_setup.qos_info.drb_qos; + drb_qos.f1u = qos.f1u; // Create new L2 DRB. rlc_bearer_config& ran_bearer = ue_cfg.cell_group.rlc_bearers.emplace_back(); diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h index 4b6cb0cac0..71f9f05c05 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h @@ -21,7 +21,6 @@ struct du_ue_resource_update_response { /// \brief Defines whether the UE release is required due to an error during the update procedure. /// If \c procedure_error doesn't contain any error string, then the UE resource update was successful. error_type procedure_error = {}; - std::vector failed_srbs; std::vector failed_drbs; std::vector failed_scells; diff --git a/lib/du_manager/ran_resource_management/du_ue_resource_config.h b/lib/du_manager/ran_resource_management/du_ue_resource_config.h index f543e1c1bd..018926cbf8 100644 --- a/lib/du_manager/ran_resource_management/du_ue_resource_config.h +++ b/lib/du_manager/ran_resource_management/du_ue_resource_config.h @@ -35,6 +35,7 @@ struct drb_upper_layer_config { pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; s_nssai_t s_nssai; qos_flow_level_qos_parameters qos; + srs_du::f1u_config f1u; }; /// Snapshot of the DU resources taken by a UE at a given instant. diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index e4bc115820..423c0d5d83 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -48,7 +48,7 @@ du_ue_resource_update_response dummy_ue_resource_configurator_factory::dummy_res const du_ue_resource_config* reestablished_context) { parent.ue_resource_pool[ue_index] = parent.next_context_update_result; - return du_ue_resource_update_response{}; + return parent.next_config_resp; } const du_ue_resource_config& dummy_ue_resource_configurator_factory::dummy_resource_updater::get() diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index ca1b61cfb9..02cd338d0c 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -297,6 +297,7 @@ class dummy_ue_resource_configurator_factory : public du_ran_resource_manager f1ap_ue_context_update_request last_ue_ctx_upd; std::map ue_resource_pool; du_ue_resource_config next_context_update_result; + du_ue_resource_update_response next_config_resp; dummy_ue_resource_configurator_factory(); diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index fed6475ee4..c81d6e33d2 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -189,7 +189,6 @@ TEST_P(du_ran_resource_manager_tester, when_srb1_is_added_then_ue_resource_confi auto resp = ue_res.update(to_du_cell_index(0), srb1_creation_req(ue_idx1)); ASSERT_FALSE(resp.release_required()); - ASSERT_TRUE(resp.failed_srbs.empty()); ASSERT_EQ(ue_res->cell_group.rlc_bearers.size(), 1); ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].lcid, srsran::LCID_SRB1); ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].rlc_cfg.mode, rlc_mode::am); diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 72caa1e1f3..fedda89204 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -83,12 +83,17 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().drb_id = drb.drb_id; - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = - uint_to_lcid(3 + (unsigned)drb.drb_id); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + auto& rlc_drb = cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); + rlc_drb.drb_id = drb.drb_id; + rlc_drb.lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); + rlc_drb.rlc_cfg = make_default_srb_rlc_config(); + rlc_drb.mac_cfg = make_default_drb_mac_lc_config(); + drb_upper_layer_config& qos_drb = cell_res_alloc.next_context_update_result.drbs.emplace_back(); + qos_drb.drb_id = drb.drb_id; + qos_drb.pdcp_sn_len = drb.pdcp_sn_len; + qos_drb.s_nssai = drb.qos_info.s_nssai; + qos_drb.qos = drb.qos_info.drb_qos; + qos_drb.f1u = {}; } for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); @@ -97,6 +102,11 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ uint_to_lcid(3 + (unsigned)drb.drb_id); cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + drb_upper_layer_config& qos_drb = cell_res_alloc.next_context_update_result.drbs.emplace_back(); + const du_ue_resource_config& old_ue_cfg = *ue_mng.find_ue(req.ue_index)->reestablished_cfg_pending; + auto old_drb_it = std::find_if( + old_ue_cfg.drbs.begin(), old_ue_cfg.drbs.end(), [&drb](const auto& d) { return d.drb_id == drb.drb_id; }); + qos_drb = *old_drb_it; } for (drb_id_t drb_id : req.drbs_to_rem) { auto it = std::find_if(cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.begin(), diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 4e23de0e77..1133870822 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -33,25 +33,33 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test test_ue = &create_ue(to_du_ue_index(test_rgen::uniform_int(0, MAX_DU_UE_INDEX))); } - void start_procedure(const f1ap_ue_context_update_request& req) + void start_procedure(const f1ap_ue_context_update_request& req, const std::vector& failed_drbs = {}) { + auto& next_cfg = this->cell_res_alloc.next_context_update_result; for (srb_id_t srb_id : req.srbs_to_setup) { - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = - make_default_srb_rlc_config(); - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = - make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); + next_cfg.cell_group.rlc_bearers.emplace_back(); + next_cfg.cell_group.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); + next_cfg.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + next_cfg.cell_group.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = - uint_to_lcid(3 + (unsigned)drb.drb_id); - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().drb_id = drb.drb_id; - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = - make_default_srb_rlc_config(); - this->cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = - make_default_drb_mac_lc_config(); + if (std::find(failed_drbs.begin(), failed_drbs.end(), drb.drb_id) != failed_drbs.end()) { + // This DRB config will fail. + this->cell_res_alloc.next_config_resp.failed_drbs.push_back(drb.drb_id); + continue; + } + next_cfg.cell_group.rlc_bearers.emplace_back(); + next_cfg.cell_group.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); + next_cfg.cell_group.rlc_bearers.back().drb_id = drb.drb_id; + next_cfg.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); + next_cfg.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); + auto& next_drb = next_cfg.drbs.emplace_back(); + next_drb.drb_id = drb.drb_id; + next_drb.pdcp_sn_len = drb.pdcp_sn_len; + next_drb.s_nssai = drb.qos_info.s_nssai; + next_drb.qos = drb.qos_info.drb_qos; + next_drb.f1u.t_notify = 100; + next_drb.f1u.warn_on_drop = false; } proc = launch_async(req, ue_mng, params); @@ -313,8 +321,7 @@ TEST_F(ue_config_tester, when_config_is_invalid_of_drb_to_create_then_drb_is_inc // Start Procedure. f1ap_ue_context_update_request req = create_f1ap_ue_context_update_request(test_ue->ue_index, {srb_id_t::srb2}, {drb_id_t::drb1}); - req.drbs_to_setup[0].uluptnl_info_list.clear(); - start_procedure(req); + start_procedure(req, {drb_id_t::drb1}); // Check MAC received request to update UE configuration without the DRB that could not be created. ASSERT_TRUE(this->mac.last_ue_reconf_msg.has_value()); @@ -400,9 +407,12 @@ TEST_F(ue_config_tester, { // Mark UE as reestablishing. test_ue->reestablished_cfg_pending = std::make_unique(); - test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.emplace_back(); - test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.back().lcid = LCID_MIN_DRB; - test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.back().drb_id = drb_id_t::drb1; + auto& old_bearer = test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.emplace_back(); + old_bearer.lcid = LCID_MIN_DRB; + old_bearer.drb_id = drb_id_t::drb1; + auto& old_drb = test_ue->reestablished_cfg_pending->drbs.emplace_back(); + old_drb.drb_id = drb_id_t::drb1; + old_drb.qos.qos_characteristics.non_dyn_5qi.emplace().five_qi = uint_to_five_qi(9); // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = From 79047c0bcbbfc4b7ecfbc8db92a09f0635882cb0 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 8 Aug 2024 17:17:39 +0200 Subject: [PATCH 217/407] ran: use variant for dyn5qi and non-dyn5qi --- include/srsran/ran/qos/five_qi_qos_mapping.h | 15 +++--- include/srsran/ran/qos/packet_error_rate.h | 42 +++++++++++++++ include/srsran/ran/qos/qos_parameters.h | 54 ++++++++++--------- .../routines/pdu_session_routine_helpers.cpp | 13 +---- .../up_resource_manager_helpers.cpp | 29 ++++------ lib/cu_up/cu_up_manager_impl.cpp | 6 +-- lib/cu_up/pdu_session_manager_impl.cpp | 4 +- lib/cu_up/qos_flow_context.h | 6 +-- .../procedures/ue_configuration_procedure.cpp | 8 +-- .../du_bearer_resource_manager.cpp | 4 +- lib/e1ap/common/e1ap_asn1_converters.h | 4 +- lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h | 10 ++-- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 53 +++++++++--------- .../procedures/f1ap_du_ue_context_common.cpp | 3 +- lib/ngap/ngap_asn1_helpers.h | 8 +-- lib/ran/qos/five_qi_qos_mapping.cpp | 45 ++++++++-------- tests/unittests/cu_cp/cu_cp_test_messages.cpp | 6 +-- .../cu_up/pdu_session_manager_test.h | 4 +- .../du_manager/du_manager_test_helpers.cpp | 14 ++--- .../procedures/ue_configuration_test.cpp | 2 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 2 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 12 ++--- .../f1ap/cu_cp/f1ap_cu_test_helpers.cpp | 12 ++--- tests/unittests/ngap/ngap_test_messages.cpp | 34 ++++++------ .../support/mcs_tbs_calculator_test.cpp | 2 - 25 files changed, 204 insertions(+), 188 deletions(-) create mode 100644 include/srsran/ran/qos/packet_error_rate.h diff --git a/include/srsran/ran/qos/five_qi_qos_mapping.h b/include/srsran/ran/qos/five_qi_qos_mapping.h index b10b050faf..c6f384a0f8 100644 --- a/include/srsran/ran/qos/five_qi_qos_mapping.h +++ b/include/srsran/ran/qos/five_qi_qos_mapping.h @@ -12,6 +12,7 @@ #include "five_qi.h" #include "srsran/adt/optional.h" +#include "srsran/ran/qos/packet_error_rate.h" namespace srsran { @@ -29,23 +30,21 @@ struct qos_characteristics { /// the UPF that terminates the N6 interface. For a certain 5QI the value of the PDB is the same in UL and DL. See /// TS 23.501, clause 5.7.3.4. unsigned packet_delay_budget_ms; - /// The Packet Error Rate (PER) defines an upper bound for the rate of PDUs (e.g. IP packets) that have been processed - /// by the sender of a link layer protocol (e.g. RLC in RAN of a 3GPP access) but that are not successfully delivered - /// by the corresponding receiver to the upper layer (e.g. PDCP in RAN of a 3GPP access). Thus, the PER defines an - /// upper bound for a rate of non-congestion related packet losses. See TS 23.501, clause 5.7.3.5. - double packet_error_rate; + /// The Packet Error Rate (PER) as defined in TS 23.501, 5.7.3.5. + packet_error_rate_t per; /// Each GBR QoS Flow shall be associated with an Averaging window. The Averaging window represents the duration over /// which the GFBR and MFBR shall be calculated (e.g. in the (R)AN, UPF, UE). See TS 23.501, clause 5.7.3.6. std::optional average_window_ms; /// Each GBR QoS Flow with Delay-critical resource type shall be associated with a Maximum Data Burst Volume (MDBV). /// MDBV denotes the largest amount of data that the 5G-AN is required to serve within a period of 5G-AN PDB (i.e. /// 5G-AN part of the PDB). See TS 23.501, clause 5.7.3.7. - std::optional max_data_burst_volume_bytes; + std::optional max_data_burst_volume; }; /// \brief Returns the standardized 5QI to QoS characteristics mapping from TS 23.501, table 5.7.4-1 based on given 5QI. /// \param[in] nof_layers Number of layers. -/// \return The standardized 5QI to QoS characteristics mapping from TS 23.501, table 5.7.4-1. -qos_characteristics get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi); +/// \return The standardized 5QI to QoS characteristics mapping from TS 23.501, table 5.7.4-1. Returns nullptr if the +/// 5QI is not present in the table. +const qos_characteristics* get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi); } // namespace srsran diff --git a/include/srsran/ran/qos/packet_error_rate.h b/include/srsran/ran/qos/packet_error_rate.h new file mode 100644 index 0000000000..4f82a433fc --- /dev/null +++ b/include/srsran/ran/qos/packet_error_rate.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 + +#include +#include + +namespace srsran { + +/// \brief Representation of the Packet Error Rate (PER) as defined in TS 38.473 and TS 23.501, 5.7.3.5. +/// +/// The Packet Error Rate (PER) defines an upper bound for the rate of PDUs (e.g. IP packets) that have been processed +/// by the sender of a link layer protocol (e.g. RLC in RAN of a 3GPP access) but that are not successfully delivered +/// by the corresponding receiver to the upper layer (e.g. PDCP in RAN of a 3GPP access). Thus, the PER defines an +/// upper bound for a rate of non-congestion related packet losses. +struct packet_error_rate_t { + uint8_t scalar = 0; + uint8_t exponent = 0; + + constexpr packet_error_rate_t() = default; + constexpr packet_error_rate_t(uint8_t scalar_, uint8_t exponent_) : scalar(scalar_), exponent(exponent_) {} + + static packet_error_rate_t make(double per_) + { + srsran_assert(per_ > 0 and per_ < 1.0, "Invalid PER value {}", per_); + double exp_val = std::floor(std::log10(per_)); + double scalar = std::round(per_ / std::pow(10, exp_val)); + return packet_error_rate_t{static_cast(scalar), static_cast(-exp_val)}; + } + + double to_double() const { return static_cast(scalar) * std::pow(10, -static_cast(exponent)); } +}; + +} // namespace srsran \ No newline at end of file diff --git a/include/srsran/ran/qos/qos_parameters.h b/include/srsran/ran/qos/qos_parameters.h index 0c5b25184b..4d156df064 100644 --- a/include/srsran/ran/qos/qos_parameters.h +++ b/include/srsran/ran/qos/qos_parameters.h @@ -10,22 +10,15 @@ #pragma once +#include "five_qi_qos_mapping.h" #include "srsran/ran/qos/five_qi.h" +#include "srsran/ran/qos/packet_error_rate.h" #include "srsran/ran/qos/qos_prio_level.h" -#include -#include #include +#include namespace srsran { -/// \brief Representation of the Packet Error Rate (PER) as defined in TS 38.473. -struct packet_error_rate_t { - uint8_t scalar = 0; - uint8_t exponent = 0; - - double to_double() const { return scalar * std::pow(10, exponent); } -}; - struct dyn_5qi_descriptor_t { qos_prio_level_t qos_prio_level; uint16_t packet_delay_budget; @@ -39,30 +32,39 @@ struct dyn_5qi_descriptor_t { }; struct non_dyn_5qi_descriptor_t { - five_qi_t five_qi; + /// Standardized 5QI. Must contain one of the 5QIs in TS23.501, Table 5.7.4-1. The default is a non-GBR 5QI. + five_qi_t five_qi = uint_to_five_qi(9); + /// Priority level, in case the default priority level specified in TS23.501, Table 5.7.4-1 is not used. std::optional qos_prio_level; - std::optional averaging_win; - std::optional max_data_burst_volume; + /// Averaging Window, in case the default value specified in TS23.501, Table 5.7.4-1 is not used. + std::optional averaging_win; + /// \brief Maximum Data Burst Volume, in case the default value specified in TS23.501, Table 5.7.4-1 is not used. + // This value should only be used in delay-critical GBR DRBs. + std::optional max_data_burst_volume; }; struct qos_characteristics_t { - std::optional dyn_5qi; - std::optional non_dyn_5qi; + qos_characteristics_t() : choice(non_dyn_5qi_descriptor_t{}) {} + qos_characteristics_t(const non_dyn_5qi_descriptor_t& val) : choice(val) {} + qos_characteristics_t(const dyn_5qi_descriptor_t& val) : choice(val) {} - five_qi_t get_five_qi() const + bool is_dyn_5qi() const { return std::holds_alternative(choice); } + + five_qi_t get_5qi() const { - if (non_dyn_5qi.has_value()) { - return non_dyn_5qi.value().five_qi; - } - if (dyn_5qi.has_value()) { - if (dyn_5qi.value().five_qi.has_value()) { - return dyn_5qi.value().five_qi.value(); - } - } else { - report_fatal_error("Invalid QoS characteristics. Either dynamic or non-dynamic 5QI must be set"); + if (is_dyn_5qi()) { + return get_dyn_5qi().five_qi.has_value() ? get_dyn_5qi().five_qi.value() : five_qi_t::invalid; } - return five_qi_t::invalid; + return get_nondyn_5qi().five_qi; } + + dyn_5qi_descriptor_t& get_dyn_5qi() { return std::get(choice); } + const dyn_5qi_descriptor_t& get_dyn_5qi() const { return std::get(choice); } + non_dyn_5qi_descriptor_t& get_nondyn_5qi() { return std::get(choice); } + const non_dyn_5qi_descriptor_t& get_nondyn_5qi() const { return std::get(choice); } + +private: + std::variant choice; }; /// \brief QoS parameters for a GBR QoS flow or GBR bearer for downlink and uplink. See TS 38.473, clause 9.3.1.46. diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index 2887608ce8..a431730f54 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -32,17 +32,8 @@ void srsran::srs_cu_cp::fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_it { e1ap_qos_item.qos_flow_id = request_item.qos_flow_id; - if (request_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi.has_value()) { - non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = request_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi.value().five_qi; - - // TODO: Add optional values - - e1ap_qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; - } else { - // logger.warning("qos_flow_id={}: dynamic 5QI not fully supported.", e1ap_qos_item.qos_flow_id); - // TODO: Add dynamic 5qi - } + e1ap_qos_item.qos_flow_level_qos_params.qos_characteristics = + request_item.qos_flow_level_qos_params.qos_characteristics; e1ap_qos_item.qos_flow_level_qos_params.ng_ran_alloc_retention = request_item.qos_flow_level_qos_params.alloc_retention_prio; diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp index 263a77a15c..85f8bfae65 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp @@ -221,12 +221,13 @@ drb_id_t allocate_qos_flow(up_pdu_session_context_update& new_session_contex drb_ctx.default_drb = full_context.drb_map.empty() ? true : false; // make first DRB the default // Fill QoS (TODO: derive QoS params correctly) - auto& qos_params = drb_ctx.qos_params; - qos_params.qos_characteristics.non_dyn_5qi.emplace(); - qos_params.qos_characteristics.non_dyn_5qi.value().five_qi = five_qi; - qos_params.alloc_retention_prio.prio_level_arp = 8; - qos_params.alloc_retention_prio.may_trigger_preemption = false; - qos_params.alloc_retention_prio.is_preemptable = false; + auto& qos_params = drb_ctx.qos_params; + qos_params.qos_characteristics = non_dyn_5qi_descriptor_t{}; + auto& non_dyn_5qi = qos_params.qos_characteristics.get_nondyn_5qi(); + non_dyn_5qi.five_qi = five_qi; + qos_params.alloc_retention_prio.prio_level_arp = 8; + qos_params.alloc_retention_prio.may_trigger_preemption = false; + qos_params.alloc_retention_prio.is_preemptable = false; // Add flow up_qos_flow_context flow_ctx; @@ -268,7 +269,7 @@ up_config_update srsran::srs_cu_cp::calculate_update( logger.debug("Allocated {} to {} with {}", flow_item.qos_flow_id, drb_id, - new_ctxt.drb_to_add.at(drb_id).qos_params.qos_characteristics.get_five_qi()); + new_ctxt.drb_to_add.at(drb_id).qos_params.qos_characteristics.get_5qi()); } config.pdu_sessions_to_setup_list.emplace(new_ctxt.id, new_ctxt); } @@ -284,17 +285,9 @@ five_qi_t srsran::srs_cu_cp::get_five_qi(const cu_cp_qos_flow_add_or_mod_item& q five_qi_t five_qi = five_qi_t::invalid; const auto& qos_params = qos_flow.qos_flow_level_qos_params; - if (qos_params.qos_characteristics.dyn_5qi.has_value()) { - if (qos_params.qos_characteristics.dyn_5qi.value().five_qi.has_value()) { - five_qi = qos_params.qos_characteristics.dyn_5qi.value().five_qi.value(); - } else { - logger.warning("Dynamic 5QI without 5QI not supported"); - return five_qi_t::invalid; - } - } else if (qos_params.qos_characteristics.non_dyn_5qi.has_value()) { - five_qi = qos_params.qos_characteristics.non_dyn_5qi.value().five_qi; - } else { - logger.warning("Invalid QoS characteristics. Either dynamic or non-dynamic 5QI must be set"); + five_qi = qos_params.qos_characteristics.get_5qi(); + if (five_qi == five_qi_t::invalid) { + logger.warning("Dynamic 5QI without 5QI not supported"); return five_qi_t::invalid; } diff --git a/lib/cu_up/cu_up_manager_impl.cpp b/lib/cu_up/cu_up_manager_impl.cpp index e09eb61519..24ab4dcb86 100644 --- a/lib/cu_up/cu_up_manager_impl.cpp +++ b/lib/cu_up/cu_up_manager_impl.cpp @@ -233,9 +233,9 @@ async_task cu_up_manager_impl::enable drb_to_setup.pdcp_cfg.discard_timer = pdcp_discard_timer::infinity; drb_to_setup.pdcp_cfg.t_reordering_timer = pdcp_t_reordering::ms200; - e1ap_qos_flow_qos_param_item qos_item = {}; - qos_item.qos_flow_id = uint_to_qos_flow_id(0x01); - qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = {uint_to_five_qi(9), {}, {}, {}}; + e1ap_qos_flow_qos_param_item qos_item = {}; + qos_item.qos_flow_id = uint_to_qos_flow_id(0x01); + qos_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi_descriptor_t{uint_to_five_qi(9), {}, {}, {}}; drb_to_setup.qos_flow_info_to_be_setup.emplace(qos_item.qos_flow_id, qos_item); pdu_session.drb_to_setup_list_ng_ran.emplace(drb_to_setup.drb_id, drb_to_setup); diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index b716c3e35f..b906430908 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -190,7 +190,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& return drb_result; } five_qi_t five_qi = - drb_to_setup.qos_flow_info_to_be_setup.begin()->qos_flow_level_qos_params.qos_characteristics.get_five_qi(); + drb_to_setup.qos_flow_info_to_be_setup.begin()->qos_flow_level_qos_params.qos_characteristics.get_5qi(); if (qos_cfg.find(five_qi) == qos_cfg.end()) { drb_result.cause = e1ap_cause_radio_network_t::not_supported_5qi_value; return drb_result; @@ -210,7 +210,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& flow_result.qos_flow_id = qos_flow_info.qos_flow_id; if (!new_session.sdap->is_mapped(qos_flow_info.qos_flow_id) && - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.get_five_qi() == five_qi) { + qos_flow_info.qos_flow_level_qos_params.qos_characteristics.get_5qi() == five_qi) { // create QoS flow context const auto& qos_flow = qos_flow_info; new_drb->qos_flows[qos_flow.qos_flow_id] = std::make_unique(qos_flow); diff --git a/lib/cu_up/qos_flow_context.h b/lib/cu_up/qos_flow_context.h index e1521e9a27..798782ee71 100644 --- a/lib/cu_up/qos_flow_context.h +++ b/lib/cu_up/qos_flow_context.h @@ -22,10 +22,8 @@ struct qos_flow_context { qos_flow_context(const e1ap_qos_flow_qos_param_item& flow) : qos_flow_id(flow.qos_flow_id) { const auto& qos_params = flow.qos_flow_level_qos_params.qos_characteristics; - if (qos_params.non_dyn_5qi.has_value()) { - five_qi = qos_params.non_dyn_5qi.value().five_qi; - } - srsran_assert(qos_params.dyn_5qi.has_value() == false, "Dynamic 5QI not supported."); + five_qi = qos_params.get_5qi(); + srsran_assert(not qos_params.is_dyn_5qi(), "Dynamic 5QI not supported."); srsran_assert(five_qi != five_qi_t::invalid, "FiveQI must be set."); }; diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 8509ab0fd6..e013db4747 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -153,7 +153,7 @@ void ue_configuration_procedure::update_ue_context() ue->resources->drbs.end(), [&drbtoadd](const drb_upper_layer_config& drb) { return drb.drb_id == drbtoadd.drb_id; }); srsran_sanity_check(drb_qos_it != ue->resources->drbs.end(), "The bearer config should be created at this point"); - five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_five_qi(); + five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_5qi(); // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, @@ -167,7 +167,7 @@ void ue_configuration_procedure::update_ue_context() ue_mng.get_f1u_teid_pool(), du_params, ue->get_rlc_rlf_notifier(), - get_5qi_to_qos_characteristics_mapping(fiveqi), + *get_5qi_to_qos_characteristics_mapping(fiveqi), drb_qos_it->qos.gbr_qos_info, drb_qos_it->s_nssai}); if (drb == nullptr) { @@ -200,7 +200,7 @@ void ue_configuration_procedure::update_ue_context() if (drb_it == ue->bearers.drbs().end()) { // >> It's a DRB modification after RRC Reestablishment. We need to create a new DRB instance. - five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_five_qi(); + five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_5qi(); // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, @@ -214,7 +214,7 @@ void ue_configuration_procedure::update_ue_context() ue_mng.get_f1u_teid_pool(), du_params, ue->get_rlc_rlf_notifier(), - get_5qi_to_qos_characteristics_mapping(fiveqi), + *get_5qi_to_qos_characteristics_mapping(fiveqi), drb_qos_it->qos.gbr_qos_info, drb_qos_it->s_nssai}); if (drb == nullptr) { diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp index 34d9a320f4..0e430a5971 100644 --- a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp @@ -59,7 +59,7 @@ static error_type validate_drb_setup_request(const f1ap_drb_to_setu const std::map& qos_config) { // Validate QOS config. - five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_five_qi(); + five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_5qi(); auto qos_it = qos_config.find(fiveqi); if (qos_it == qos_config.end()) { return make_unexpected(fmt::format("No {} 5QI configured", fiveqi)); @@ -224,7 +224,7 @@ std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_conf } // Get QoS Config from 5QI - five_qi_t fiveqi = drb_to_setup.qos_info.drb_qos.qos_characteristics.get_five_qi(); + five_qi_t fiveqi = drb_to_setup.qos_info.drb_qos.qos_characteristics.get_5qi(); const du_qos_config& qos = qos_config.at(fiveqi); // Create new DRB QoS Flow. diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index 9b6fce5e4c..309b162f78 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -1119,7 +1119,7 @@ inline void e1ap_asn1_to_flow_map_info(slotted_id_vectordrb_qos.qos_characteristics.non_dyn_5qi().five_qi); drb_obj.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = asn1_drb_info->drb_qos.ngra_nalloc_retention_prio.prio_level; diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index f25aae8a4c..da481ada82 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -295,7 +295,7 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re } // TODO: Add optional values - qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics.dyn_5qi = dyn_5qi; + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics = dyn_5qi; // TODO: Add optional values @@ -304,7 +304,7 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re non_dyn_5qi_descriptor_t non_dyn_5qi = {}; non_dyn_5qi.five_qi = uint_to_five_qi(asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi); - qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; // TODO: Add optional values } @@ -597,7 +597,7 @@ inline bool fill_cu_cp_pdu_session_resource_modify_item_base( } // TODO: Add optional values - qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics.dyn_5qi = dyn_5qi; + qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics = dyn_5qi; // TODO: Add optional values @@ -606,7 +606,7 @@ inline bool fill_cu_cp_pdu_session_resource_modify_item_base( non_dyn_5qi_descriptor_t non_dyn_5qi = {}; non_dyn_5qi.five_qi = uint_to_five_qi(asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi); - qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; // TODO: Add optional values } diff --git a/lib/ran/qos/five_qi_qos_mapping.cpp b/lib/ran/qos/five_qi_qos_mapping.cpp index 9d6bf5f53e..b64e1705ae 100644 --- a/lib/ran/qos/five_qi_qos_mapping.cpp +++ b/lib/ran/qos/five_qi_qos_mapping.cpp @@ -19,55 +19,54 @@ static const std::unordered_map five_qi_to_qos_m // GBR. {uint_to_five_qi(1), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, 10e-2, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, {uint_to_five_qi(2), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 40, 150, 10e-3, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 40, 150, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, {uint_to_five_qi(3), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 30, 50, 10e-3, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 30, 50, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, {uint_to_five_qi(4), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 50, 300, 10e-6, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 50, 300, packet_error_rate_t::make(1e-6), 2000, std::nullopt}}, {uint_to_five_qi(65), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 7, 75, 10e-2, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 7, 75, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, {uint_to_five_qi(66), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, 10e-2, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, {uint_to_five_qi(67), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 15, 100, 10e-3, 2000, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::gbr, 15, 100, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, // Non-GBR. {uint_to_five_qi(5), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 10, 100, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 10, 100, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(6), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 60, 300, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 60, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(7), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 70, 100, 10e-3, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 70, 100, packet_error_rate_t::make(1e-3), std::nullopt, std::nullopt}}, {uint_to_five_qi(8), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 80, 300, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 80, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(9), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 90, 300, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 90, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(69), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 5, 60, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 5, 60, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(70), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 55, 200, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 55, 200, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(79), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 65, 50, 10e-2, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 65, 50, packet_error_rate_t::make(1e-2), std::nullopt, std::nullopt}}, {uint_to_five_qi(80), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 68, 10, 10e-6, std::nullopt, std::nullopt}}, + qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 68, 10, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, // Delay Critical GBR. {uint_to_five_qi(82), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 19, 10, 10e-4, 2000, 255}}, + qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 19, 10, packet_error_rate_t::make(1e-4), 2000, 255}}, {uint_to_five_qi(83), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 22, 10, 10e-4, 2000, 1354}}, + qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 22, 10, packet_error_rate_t::make(1e-4), 2000, 1354}}, {uint_to_five_qi(84), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 24, 30, 10e-5, 2000, 1354}}, + qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 24, 30, packet_error_rate_t::make(1e-5), 2000, 1354}}, {uint_to_five_qi(85), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 21, 5, 10e-5, 2000, 255}}, + qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 21, 5, packet_error_rate_t::make(1e-5), 2000, 255}}, // clang-format on }; -qos_characteristics srsran::get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi) +const qos_characteristics* srsran::get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi) { const auto qos_char = five_qi_to_qos_mapping.find(five_qi); - srsran_assert(qos_char != five_qi_to_qos_mapping.end(), "Undefined QoS characteristics for 5QI={}", five_qi); - return qos_char->second; + return qos_char != five_qi_to_qos_mapping.end() ? &qos_char->second : nullptr; } diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.cpp b/tests/unittests/cu_cp/cu_cp_test_messages.cpp index 55e9cc4869..48eb63d021 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_messages.cpp @@ -60,8 +60,8 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(ue_index_t ue_index, qos_item.qos_flow_id = uint_to_qos_flow_id(i + k + 1); non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = uint_to_five_qi(9); // all with same FiveQI - qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + non_dyn_5qi.five_qi = uint_to_five_qi(9); // all with same FiveQI + qos_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; qos_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 8; @@ -105,7 +105,7 @@ srsran::srs_cu_cp::generate_pdu_session_resource_modification(ue_index_t ue_inde { non_dyn_5qi_descriptor_t non_dyn_5qi; non_dyn_5qi.five_qi = uint_to_five_qi(7); - qos_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; qos_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 8; } diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 154182c6a1..a3451f7573 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -158,7 +158,7 @@ generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qo qos_flow_info.qos_flow_id = qfi; non_dyn_5qi_descriptor_t non_dyn_5qi; non_dyn_5qi.five_qi = five_qi; - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); @@ -222,7 +222,7 @@ generate_pdu_session_res_to_modify_item_to_setup_drb(pdu_session_id_t qos_flow_info.qos_flow_id = qfi; non_dyn_5qi_descriptor_t non_dyn_5qi; non_dyn_5qi.five_qi = five_qi; - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index 423c0d5d83..95d95b5586 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -90,13 +90,13 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t } for (drb_id_t drb_id : drbs_to_add) { - req.drbs_to_setup.emplace_back(); - req.drbs_to_setup.back().drb_id = drb_id; - req.drbs_to_setup.back().mode = rlc_mode::am; - req.drbs_to_setup.back().qos_info.drb_qos.qos_characteristics.non_dyn_5qi.emplace().five_qi = uint_to_five_qi(9); - req.drbs_to_setup.back().uluptnl_info_list.resize(1); - req.drbs_to_setup.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); - req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); + auto& drb_to_setup = req.drbs_to_setup.emplace_back(); + drb_to_setup.drb_id = drb_id; + drb_to_setup.mode = rlc_mode::am; + drb_to_setup.qos_info.drb_qos.qos_characteristics = non_dyn_5qi_descriptor_t{uint_to_five_qi(9)}; + drb_to_setup.uluptnl_info_list.resize(1); + drb_to_setup.uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); + drb_to_setup.uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); } for (drb_id_t drb_id : drbs_to_mod) { diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 1133870822..ecc52ace7a 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -412,7 +412,7 @@ TEST_F(ue_config_tester, old_bearer.drb_id = drb_id_t::drb1; auto& old_drb = test_ue->reestablished_cfg_pending->drbs.emplace_back(); old_drb.drb_id = drb_id_t::drb1; - old_drb.qos.qos_characteristics.non_dyn_5qi.emplace().five_qi = uint_to_five_qi(9); + old_drb.qos.qos_characteristics.get_nondyn_5qi().five_qi = uint_to_five_qi(9); // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 37e935aa52..a8d36098c7 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -115,7 +115,7 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set qos_flow_info.qos_flow_id = uint_to_qos_flow_id(8); non_dyn_5qi_descriptor_t non_dyn_5qi; non_dyn_5qi.five_qi = uint_to_five_qi(8); - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.may_trigger_preemption = false; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.is_preemptable = false; diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index f9f588374e..ab591afa99 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -232,11 +232,11 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // qos flow level qos params // qos characteristics non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = uint_to_five_qi(8); - non_dyn_5qi.qos_prio_level = uint_to_qos_prio_level(1); - non_dyn_5qi.averaging_win = 3; - non_dyn_5qi.max_data_burst_volume = 1000; - drbs_to_be_setup_mod_item.qos_info.drb_qos.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + non_dyn_5qi.five_qi = uint_to_five_qi(8); + non_dyn_5qi.qos_prio_level = uint_to_qos_prio_level(1); + non_dyn_5qi.averaging_win = 3; + non_dyn_5qi.max_data_burst_volume = 1000; + drbs_to_be_setup_mod_item.qos_info.drb_qos.qos_characteristics = non_dyn_5qi; // ng ran alloc retention prio drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = 1; @@ -266,7 +266,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi flow_mapped_to_drb flows_mapped_to_drb_item; flows_mapped_to_drb_item.qos_flow_id = uint_to_qos_flow_id(1); // qos characteristics - flows_mapped_to_drb_item.qos_flow_level_qos_params.qos_characteristics.non_dyn_5qi = non_dyn_5qi; + flows_mapped_to_drb_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; // ng ran alloc retention prio flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 1; flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.may_trigger_preemption = false; diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp index ac049e3745..43cc2155be 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp @@ -145,13 +145,11 @@ srsran::srs_cu_cp::create_ue_context_setup_request(const std::initializer_listqos_flow_setup_request_list.push_back(qos_flow_setup_req_item); - } + qos_flow_setup_request_item_s qos_flow_setup_req_item; + qos_flow_setup_req_item.qos_flow_id = qos_flow_id_to_uint(qos_flow_test_item.qos_flow_id); + + // Add QoS Characteristics + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics.set_non_dyn5qi(); + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi = + qos_flow_test_item.five_qi; + + // Add Allocation and Retention Priority + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.prio_level_arp = 8; + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_cap = + pre_emption_cap_opts::shall_not_trigger_pre_emption; + qos_flow_setup_req_item.qos_flow_level_qos_params.alloc_and_retention_prio.pre_emption_vulnerability = + pre_emption_vulnerability_opts::not_pre_emptable; + + asn1_setup_req_transfer->qos_flow_setup_request_list.push_back(qos_flow_setup_req_item); } } pdu_session_res_item.pdu_session_res_setup_request_transfer = pack_into_pdu(asn1_setup_req_transfer); diff --git a/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp b/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp index 9104042195..a2d86f3ba3 100644 --- a/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp +++ b/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp @@ -12,8 +12,6 @@ #include "lib/scheduler/support/mcs_tbs_calculator.h" #include "lib/scheduler/support/sch_pdu_builder.h" #include "tests/unittests/scheduler/test_utils/config_generators.h" -#include "srsran/ran/pdsch/dlsch_info.h" -#include "srsran/ran/pusch/ulsch_info.h" #include "srsran/ran/sch/tbs_calculator.h" #include "srsran/ran/uci/uci_mapping.h" #include "srsran/support/test_utils.h" From 51b2bc4282cac1b60a7db052719cd9a00860992b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 8 Aug 2024 22:23:23 +0200 Subject: [PATCH 218/407] ran: rename qos descriptor types --- include/srsran/e1ap/common/e1ap_types.h | 2 +- include/srsran/ran/cu_types.h | 2 +- include/srsran/ran/qos/five_qi_qos_mapping.h | 6 +-- include/srsran/ran/qos/qos_parameters.h | 31 +++++++------ .../srsran/scheduler/scheduler_configurator.h | 2 +- .../routines/pdu_session_routine_helpers.cpp | 5 +-- .../up_resource_manager_helpers.cpp | 8 ++-- lib/cu_up/cu_up_manager_impl.cpp | 6 +-- lib/cu_up/pdu_session_manager_impl.cpp | 5 +-- lib/cu_up/qos_flow_context.h | 2 +- lib/du_manager/du_ue/du_bearer.h | 4 +- .../procedures/ue_configuration_procedure.cpp | 4 +- .../du_bearer_resource_manager.cpp | 4 +- lib/e1ap/common/e1ap_asn1_converters.h | 8 ++-- lib/e1ap/common/e1ap_asn1_helpers.h | 9 ++-- lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h | 6 +-- lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h | 14 +++--- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 12 ++--- .../procedures/f1ap_du_ue_context_common.cpp | 4 +- lib/ngap/ngap_asn1_helpers.h | 16 +++---- lib/ran/qos/five_qi_qos_mapping.cpp | 44 +++++++++---------- tests/unittests/cu_cp/cu_cp_test_messages.cpp | 10 ++--- .../cu_up/pdu_session_manager_test.h | 8 ++-- .../du_manager/du_manager_test_helpers.cpp | 8 ++-- .../du_manager/du_ue/du_bearer_test.cpp | 2 +- .../procedures/ue_configuration_test.cpp | 2 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 4 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 14 +++--- 28 files changed, 121 insertions(+), 121 deletions(-) diff --git a/include/srsran/e1ap/common/e1ap_types.h b/include/srsran/e1ap/common/e1ap_types.h index 759d9b1d56..3542e24514 100644 --- a/include/srsran/e1ap/common/e1ap_types.h +++ b/include/srsran/e1ap/common/e1ap_types.h @@ -74,7 +74,7 @@ struct e1ap_gbr_qos_flow_info { }; struct e1ap_qos_flow_level_qos_params { - qos_characteristics_t qos_characteristics; + qos_characteristics qos_desc; alloc_and_retention_priority ng_ran_alloc_retention; std::optional gbr_qos_flow_info; std::optional reflective_qos_attribute; diff --git a/include/srsran/ran/cu_types.h b/include/srsran/ran/cu_types.h index ea68e8b69f..8194c4116d 100644 --- a/include/srsran/ran/cu_types.h +++ b/include/srsran/ran/cu_types.h @@ -67,7 +67,7 @@ struct nr_cgi_support_item_t { }; struct ng_ran_qos_support_item_t { - non_dyn_5qi_descriptor_t non_dyn_5qi_descriptor; + non_dyn_5qi_descriptor non_dyn_5qi_desc; }; struct supported_plmns_item_t { diff --git a/include/srsran/ran/qos/five_qi_qos_mapping.h b/include/srsran/ran/qos/five_qi_qos_mapping.h index c6f384a0f8..eb611f4577 100644 --- a/include/srsran/ran/qos/five_qi_qos_mapping.h +++ b/include/srsran/ran/qos/five_qi_qos_mapping.h @@ -20,8 +20,8 @@ namespace srsran { /// non-GBR. See TS 23.501, clause 5.7.3.2 Resource Type. enum class qos_flow_resource_type { gbr, non_gbr, delay_critical_gbr }; -/// \brief Represents 5G QoS characteristics associated with 5QI. -struct qos_characteristics { +/// \brief Represents 5G QoS characteristics associated with a standardized 5QI, as per TS 23.501 5.7.4-1. +struct standardized_qos_characteristics { qos_flow_resource_type res_type; /// The Priority Level associated with 5G QoS characteristics indicates a priority in scheduling resources among QoS /// Flows. The lowest Priority Level value corresponds to the highest priority. See TS 23.501, clause 5.7.3.3. @@ -45,6 +45,6 @@ struct qos_characteristics { /// \param[in] nof_layers Number of layers. /// \return The standardized 5QI to QoS characteristics mapping from TS 23.501, table 5.7.4-1. Returns nullptr if the /// 5QI is not present in the table. -const qos_characteristics* get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi); +const standardized_qos_characteristics* get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi); } // namespace srsran diff --git a/include/srsran/ran/qos/qos_parameters.h b/include/srsran/ran/qos/qos_parameters.h index 4d156df064..8636434386 100644 --- a/include/srsran/ran/qos/qos_parameters.h +++ b/include/srsran/ran/qos/qos_parameters.h @@ -19,7 +19,7 @@ namespace srsran { -struct dyn_5qi_descriptor_t { +struct dyn_5qi_descriptor { qos_prio_level_t qos_prio_level; uint16_t packet_delay_budget; packet_error_rate_t per; @@ -31,7 +31,7 @@ struct dyn_5qi_descriptor_t { std::optional max_data_burst_volume; }; -struct non_dyn_5qi_descriptor_t { +struct non_dyn_5qi_descriptor { /// Standardized 5QI. Must contain one of the 5QIs in TS23.501, Table 5.7.4-1. The default is a non-GBR 5QI. five_qi_t five_qi = uint_to_five_qi(9); /// Priority level, in case the default priority level specified in TS23.501, Table 5.7.4-1 is not used. @@ -39,17 +39,19 @@ struct non_dyn_5qi_descriptor_t { /// Averaging Window, in case the default value specified in TS23.501, Table 5.7.4-1 is not used. std::optional averaging_win; /// \brief Maximum Data Burst Volume, in case the default value specified in TS23.501, Table 5.7.4-1 is not used. - // This value should only be used in delay-critical GBR DRBs. + /// This value should only be used in delay-critical GBR DRBs. std::optional max_data_burst_volume; }; -struct qos_characteristics_t { - qos_characteristics_t() : choice(non_dyn_5qi_descriptor_t{}) {} - qos_characteristics_t(const non_dyn_5qi_descriptor_t& val) : choice(val) {} - qos_characteristics_t(const dyn_5qi_descriptor_t& val) : choice(val) {} +/// QoS Parameters of either a dynamic or non-dynamic 5QI. +struct qos_characteristics { + qos_characteristics() : choice(non_dyn_5qi_descriptor{}) {} + qos_characteristics(const non_dyn_5qi_descriptor& val) : choice(val) {} + qos_characteristics(const dyn_5qi_descriptor& val) : choice(val) {} - bool is_dyn_5qi() const { return std::holds_alternative(choice); } + bool is_dyn_5qi() const { return std::holds_alternative(choice); } + /// Retrieves the 5QI associated with the QoS characteristics. five_qi_t get_5qi() const { if (is_dyn_5qi()) { @@ -58,13 +60,13 @@ struct qos_characteristics_t { return get_nondyn_5qi().five_qi; } - dyn_5qi_descriptor_t& get_dyn_5qi() { return std::get(choice); } - const dyn_5qi_descriptor_t& get_dyn_5qi() const { return std::get(choice); } - non_dyn_5qi_descriptor_t& get_nondyn_5qi() { return std::get(choice); } - const non_dyn_5qi_descriptor_t& get_nondyn_5qi() const { return std::get(choice); } + dyn_5qi_descriptor& get_dyn_5qi() { return std::get(choice); } + const dyn_5qi_descriptor& get_dyn_5qi() const { return std::get(choice); } + non_dyn_5qi_descriptor& get_nondyn_5qi() { return std::get(choice); } + const non_dyn_5qi_descriptor& get_nondyn_5qi() const { return std::get(choice); } private: - std::variant choice; + std::variant choice; }; /// \brief QoS parameters for a GBR QoS flow or GBR bearer for downlink and uplink. See TS 38.473, clause 9.3.1.46. @@ -93,7 +95,8 @@ struct alloc_and_retention_priority { }; struct qos_flow_level_qos_parameters { - qos_characteristics_t qos_characteristics; + /// QoS Descriptor of a dynamic or non-dynamic 5QI. + qos_characteristics qos_desc; alloc_and_retention_priority alloc_retention_prio; /// This parameter applies to GBR flows only. See TS 38.473, clause 9.3.1.45. std::optional gbr_qos_info; diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index 2f50d289a5..b459d004d9 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -123,7 +123,7 @@ struct sched_drb_info { /// Single Network Slice Selection Assistance Information (S-NSSAI). s_nssai_t s_nssai; /// QoS characteristics associated with the logical channel. - qos_characteristics qos_info; + standardized_qos_characteristics qos_info; /// QoS information present only for GBR QoS flows. std::optional gbr_qos_info; }; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index a431730f54..3a54399faf 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -32,8 +32,7 @@ void srsran::srs_cu_cp::fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_it { e1ap_qos_item.qos_flow_id = request_item.qos_flow_id; - e1ap_qos_item.qos_flow_level_qos_params.qos_characteristics = - request_item.qos_flow_level_qos_params.qos_characteristics; + e1ap_qos_item.qos_flow_level_qos_params.qos_desc = request_item.qos_flow_level_qos_params.qos_desc; e1ap_qos_item.qos_flow_level_qos_params.ng_ran_alloc_retention = request_item.qos_flow_level_qos_params.alloc_retention_prio; @@ -190,7 +189,7 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drb_to_setup& drb_setup_mod_item, // Requ drb_setup_mod_item.drb_id = drb_id; // QoS config. - drb_setup_mod_item.qos_info.drb_qos.qos_characteristics = next_drb_config.qos_params.qos_characteristics; + drb_setup_mod_item.qos_info.drb_qos.qos_desc = next_drb_config.qos_params.qos_desc; drb_setup_mod_item.qos_info.drb_qos.alloc_retention_prio = next_drb_config.qos_params.alloc_retention_prio; // S-NSSAI diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp index 85f8bfae65..a401b03a3b 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp @@ -222,8 +222,8 @@ drb_id_t allocate_qos_flow(up_pdu_session_context_update& new_session_contex // Fill QoS (TODO: derive QoS params correctly) auto& qos_params = drb_ctx.qos_params; - qos_params.qos_characteristics = non_dyn_5qi_descriptor_t{}; - auto& non_dyn_5qi = qos_params.qos_characteristics.get_nondyn_5qi(); + qos_params.qos_desc = non_dyn_5qi_descriptor{}; + auto& non_dyn_5qi = qos_params.qos_desc.get_nondyn_5qi(); non_dyn_5qi.five_qi = five_qi; qos_params.alloc_retention_prio.prio_level_arp = 8; qos_params.alloc_retention_prio.may_trigger_preemption = false; @@ -269,7 +269,7 @@ up_config_update srsran::srs_cu_cp::calculate_update( logger.debug("Allocated {} to {} with {}", flow_item.qos_flow_id, drb_id, - new_ctxt.drb_to_add.at(drb_id).qos_params.qos_characteristics.get_5qi()); + new_ctxt.drb_to_add.at(drb_id).qos_params.qos_desc.get_5qi()); } config.pdu_sessions_to_setup_list.emplace(new_ctxt.id, new_ctxt); } @@ -285,7 +285,7 @@ five_qi_t srsran::srs_cu_cp::get_five_qi(const cu_cp_qos_flow_add_or_mod_item& q five_qi_t five_qi = five_qi_t::invalid; const auto& qos_params = qos_flow.qos_flow_level_qos_params; - five_qi = qos_params.qos_characteristics.get_5qi(); + five_qi = qos_params.qos_desc.get_5qi(); if (five_qi == five_qi_t::invalid) { logger.warning("Dynamic 5QI without 5QI not supported"); return five_qi_t::invalid; diff --git a/lib/cu_up/cu_up_manager_impl.cpp b/lib/cu_up/cu_up_manager_impl.cpp index 24ab4dcb86..b7e4975225 100644 --- a/lib/cu_up/cu_up_manager_impl.cpp +++ b/lib/cu_up/cu_up_manager_impl.cpp @@ -233,9 +233,9 @@ async_task cu_up_manager_impl::enable drb_to_setup.pdcp_cfg.discard_timer = pdcp_discard_timer::infinity; drb_to_setup.pdcp_cfg.t_reordering_timer = pdcp_t_reordering::ms200; - e1ap_qos_flow_qos_param_item qos_item = {}; - qos_item.qos_flow_id = uint_to_qos_flow_id(0x01); - qos_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi_descriptor_t{uint_to_five_qi(9), {}, {}, {}}; + e1ap_qos_flow_qos_param_item qos_item = {}; + qos_item.qos_flow_id = uint_to_qos_flow_id(0x01); + qos_item.qos_flow_level_qos_params.qos_desc = non_dyn_5qi_descriptor{uint_to_five_qi(9), {}, {}, {}}; drb_to_setup.qos_flow_info_to_be_setup.emplace(qos_item.qos_flow_id, qos_item); pdu_session.drb_to_setup_list_ng_ran.emplace(drb_to_setup.drb_id, drb_to_setup); diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index b906430908..b1465961aa 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -189,8 +189,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& if (drb_to_setup.qos_flow_info_to_be_setup.empty()) { return drb_result; } - five_qi_t five_qi = - drb_to_setup.qos_flow_info_to_be_setup.begin()->qos_flow_level_qos_params.qos_characteristics.get_5qi(); + five_qi_t five_qi = drb_to_setup.qos_flow_info_to_be_setup.begin()->qos_flow_level_qos_params.qos_desc.get_5qi(); if (qos_cfg.find(five_qi) == qos_cfg.end()) { drb_result.cause = e1ap_cause_radio_network_t::not_supported_5qi_value; return drb_result; @@ -210,7 +209,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& flow_result.qos_flow_id = qos_flow_info.qos_flow_id; if (!new_session.sdap->is_mapped(qos_flow_info.qos_flow_id) && - qos_flow_info.qos_flow_level_qos_params.qos_characteristics.get_5qi() == five_qi) { + qos_flow_info.qos_flow_level_qos_params.qos_desc.get_5qi() == five_qi) { // create QoS flow context const auto& qos_flow = qos_flow_info; new_drb->qos_flows[qos_flow.qos_flow_id] = std::make_unique(qos_flow); diff --git a/lib/cu_up/qos_flow_context.h b/lib/cu_up/qos_flow_context.h index 798782ee71..d6986d1551 100644 --- a/lib/cu_up/qos_flow_context.h +++ b/lib/cu_up/qos_flow_context.h @@ -21,7 +21,7 @@ namespace srs_cu_up { struct qos_flow_context { qos_flow_context(const e1ap_qos_flow_qos_param_item& flow) : qos_flow_id(flow.qos_flow_id) { - const auto& qos_params = flow.qos_flow_level_qos_params.qos_characteristics; + const auto& qos_params = flow.qos_flow_level_qos_params.qos_desc; five_qi = qos_params.get_5qi(); srsran_assert(not qos_params.is_dyn_5qi(), "Dynamic 5QI not supported."); srsran_assert(five_qi != five_qi_t::invalid, "FiveQI must be set."); diff --git a/lib/du_manager/du_ue/du_bearer.h b/lib/du_manager/du_ue/du_bearer.h index 1ecff5fd97..dbfe4a06df 100644 --- a/lib/du_manager/du_ue/du_bearer.h +++ b/lib/du_manager/du_ue/du_bearer.h @@ -107,7 +107,7 @@ struct du_ue_drb { /// Single Network Slice Selection Assistance Information (S-NSSAI). s_nssai_t s_nssai; /// QoS characteristics to be met by the DRB. - qos_characteristics qos_info; + standardized_qos_characteristics qos_info; /// QoS information present only for GBR QoS flows. std::optional gbr_qos_info; @@ -128,7 +128,7 @@ struct drb_creation_info { gtpu_teid_pool& teid_pool; const du_manager_params& du_params; rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier; - const qos_characteristics& qos_info; + const standardized_qos_characteristics& qos_info; std::optional gbr_qos_info; s_nssai_t s_nssai; }; diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index e013db4747..ee6baa3f39 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -153,7 +153,7 @@ void ue_configuration_procedure::update_ue_context() ue->resources->drbs.end(), [&drbtoadd](const drb_upper_layer_config& drb) { return drb.drb_id == drbtoadd.drb_id; }); srsran_sanity_check(drb_qos_it != ue->resources->drbs.end(), "The bearer config should be created at this point"); - five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_5qi(); + five_qi_t fiveqi = drb_qos_it->qos.qos_desc.get_5qi(); // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, @@ -200,7 +200,7 @@ void ue_configuration_procedure::update_ue_context() if (drb_it == ue->bearers.drbs().end()) { // >> It's a DRB modification after RRC Reestablishment. We need to create a new DRB instance. - five_qi_t fiveqi = drb_qos_it->qos.qos_characteristics.get_5qi(); + five_qi_t fiveqi = drb_qos_it->qos.qos_desc.get_5qi(); // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp index 0e430a5971..ee7e66003f 100644 --- a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp @@ -59,7 +59,7 @@ static error_type validate_drb_setup_request(const f1ap_drb_to_setu const std::map& qos_config) { // Validate QOS config. - five_qi_t fiveqi = drb.qos_info.drb_qos.qos_characteristics.get_5qi(); + five_qi_t fiveqi = drb.qos_info.drb_qos.qos_desc.get_5qi(); auto qos_it = qos_config.find(fiveqi); if (qos_it == qos_config.end()) { return make_unexpected(fmt::format("No {} 5QI configured", fiveqi)); @@ -224,7 +224,7 @@ std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_conf } // Get QoS Config from 5QI - five_qi_t fiveqi = drb_to_setup.qos_info.drb_qos.qos_characteristics.get_5qi(); + five_qi_t fiveqi = drb_to_setup.qos_info.drb_qos.qos_desc.get_5qi(); const du_qos_config& qos = qos_config.at(fiveqi); // Create new DRB QoS Flow. diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index 309b162f78..fe21556dc5 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -1099,7 +1099,7 @@ inline void e1ap_asn1_to_flow_map_info(slotted_id_vectordrb_qos.qos_characteristics.non_dyn_5qi().five_qi); drb_obj.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = asn1_drb_info->drb_qos.ngra_nalloc_retention_prio.prio_level; diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index da481ada82..a4654cecdf 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -288,23 +288,23 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re // qosFlowLevelQosParameters if (asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.type() == asn1::ngap::qos_characteristics_c::types::dyn5qi) { - dyn_5qi_descriptor_t dyn_5qi = {}; + dyn_5qi_descriptor dyn_5qi = {}; if (asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.dyn5qi().five_qi_present) { dyn_5qi.five_qi = uint_to_five_qi(asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.dyn5qi().five_qi); } // TODO: Add optional values - qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics = dyn_5qi; + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_desc = dyn_5qi; // TODO: Add optional values } else if (asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.type() == asn1::ngap::qos_characteristics_c::types::non_dyn5qi) { - non_dyn_5qi_descriptor_t non_dyn_5qi = {}; + non_dyn_5qi_descriptor non_dyn_5qi = {}; non_dyn_5qi.five_qi = uint_to_five_qi(asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi); - qos_flow_setup_req_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + qos_flow_setup_req_item.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; // TODO: Add optional values } @@ -590,23 +590,23 @@ inline bool fill_cu_cp_pdu_session_resource_modify_item_base( if (asn1_flow_item.qos_flow_level_qos_params_present) { if (asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.type() == asn1::ngap::qos_characteristics_c::types::dyn5qi) { - dyn_5qi_descriptor_t dyn_5qi = {}; + dyn_5qi_descriptor dyn_5qi = {}; if (asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.dyn5qi().five_qi_present) { dyn_5qi.five_qi = uint_to_five_qi(asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.dyn5qi().five_qi); } // TODO: Add optional values - qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics = dyn_5qi; + qos_flow_add_item.qos_flow_level_qos_params.qos_desc = dyn_5qi; // TODO: Add optional values } else if (asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.type() == asn1::ngap::qos_characteristics_c::types::non_dyn5qi) { - non_dyn_5qi_descriptor_t non_dyn_5qi = {}; + non_dyn_5qi_descriptor non_dyn_5qi = {}; non_dyn_5qi.five_qi = uint_to_five_qi(asn1_flow_item.qos_flow_level_qos_params.qos_characteristics.non_dyn5qi().five_qi); - qos_flow_add_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + qos_flow_add_item.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; // TODO: Add optional values } diff --git a/lib/ran/qos/five_qi_qos_mapping.cpp b/lib/ran/qos/five_qi_qos_mapping.cpp index b64e1705ae..c16c9dd6ac 100644 --- a/lib/ran/qos/five_qi_qos_mapping.cpp +++ b/lib/ran/qos/five_qi_qos_mapping.cpp @@ -14,58 +14,58 @@ using namespace srsran; /// \brief Standardized 5QI to QoS characteristics mapping as per TS 23.501, table 5.7.4-1. -static const std::unordered_map five_qi_to_qos_mapping = { +static const std::unordered_map five_qi_to_qos_mapping = { // clang-format off // GBR. {uint_to_five_qi(1), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, {uint_to_five_qi(2), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 40, 150, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 40, 150, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, {uint_to_five_qi(3), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 30, 50, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 30, 50, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, {uint_to_five_qi(4), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 50, 300, packet_error_rate_t::make(1e-6), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 50, 300, packet_error_rate_t::make(1e-6), 2000, std::nullopt}}, {uint_to_five_qi(65), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 7, 75, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 7, 75, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, {uint_to_five_qi(66), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 20, 100, packet_error_rate_t::make(1e-2), 2000, std::nullopt}}, {uint_to_five_qi(67), - qos_characteristics{srsran::qos_flow_resource_type::gbr, 15, 100, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::gbr, 15, 100, packet_error_rate_t::make(1e-3), 2000, std::nullopt}}, // Non-GBR. {uint_to_five_qi(5), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 10, 100, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 10, 100, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(6), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 60, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 60, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(7), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 70, 100, packet_error_rate_t::make(1e-3), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 70, 100, packet_error_rate_t::make(1e-3), std::nullopt, std::nullopt}}, {uint_to_five_qi(8), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 80, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 80, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(9), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 90, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 90, 300, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(69), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 5, 60, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 5, 60, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(70), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 55, 200, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 55, 200, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, {uint_to_five_qi(79), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 65, 50, packet_error_rate_t::make(1e-2), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 65, 50, packet_error_rate_t::make(1e-2), std::nullopt, std::nullopt}}, {uint_to_five_qi(80), - qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 68, 10, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::non_gbr, 68, 10, packet_error_rate_t::make(1e-6), std::nullopt, std::nullopt}}, // Delay Critical GBR. {uint_to_five_qi(82), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 19, 10, packet_error_rate_t::make(1e-4), 2000, 255}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 19, 10, packet_error_rate_t::make(1e-4), 2000, 255}}, {uint_to_five_qi(83), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 22, 10, packet_error_rate_t::make(1e-4), 2000, 1354}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 22, 10, packet_error_rate_t::make(1e-4), 2000, 1354}}, {uint_to_five_qi(84), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 24, 30, packet_error_rate_t::make(1e-5), 2000, 1354}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 24, 30, packet_error_rate_t::make(1e-5), 2000, 1354}}, {uint_to_five_qi(85), - qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 21, 5, packet_error_rate_t::make(1e-5), 2000, 255}}, + standardized_qos_characteristics{srsran::qos_flow_resource_type::delay_critical_gbr, 21, 5, packet_error_rate_t::make(1e-5), 2000, 255}}, // clang-format on }; -const qos_characteristics* srsran::get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi) +const standardized_qos_characteristics* srsran::get_5qi_to_qos_characteristics_mapping(five_qi_t five_qi) { const auto qos_char = five_qi_to_qos_mapping.find(five_qi); return qos_char != five_qi_to_qos_mapping.end() ? &qos_char->second : nullptr; diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.cpp b/tests/unittests/cu_cp/cu_cp_test_messages.cpp index 48eb63d021..f43c9e012a 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_messages.cpp @@ -59,9 +59,9 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(ue_index_t ue_index, qos_flow_setup_request_item qos_item; qos_item.qos_flow_id = uint_to_qos_flow_id(i + k + 1); - non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = uint_to_five_qi(9); // all with same FiveQI - qos_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + non_dyn_5qi_descriptor non_dyn_5qi; + non_dyn_5qi.five_qi = uint_to_five_qi(9); // all with same FiveQI + qos_item.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; qos_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 8; @@ -103,9 +103,9 @@ srsran::srs_cu_cp::generate_pdu_session_resource_modification(ue_index_t ue_inde cu_cp_qos_flow_add_or_mod_item qos_item; qos_item.qos_flow_id = uint_to_qos_flow_id(qfi); { - non_dyn_5qi_descriptor_t non_dyn_5qi; + non_dyn_5qi_descriptor non_dyn_5qi; non_dyn_5qi.five_qi = uint_to_five_qi(7); - qos_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + qos_item.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; qos_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 8; } diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index a3451f7573..d2eee5c716 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -156,9 +156,9 @@ generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qo e1ap_qos_flow_qos_param_item qos_flow_info; qos_flow_info.qos_flow_id = qfi; - non_dyn_5qi_descriptor_t non_dyn_5qi; + non_dyn_5qi_descriptor non_dyn_5qi; non_dyn_5qi.five_qi = five_qi; - qos_flow_info.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); @@ -220,9 +220,9 @@ generate_pdu_session_res_to_modify_item_to_setup_drb(pdu_session_id_t for (const auto& qfi : qfi_list) { e1ap_qos_flow_qos_param_item qos_flow_info; qos_flow_info.qos_flow_id = qfi; - non_dyn_5qi_descriptor_t non_dyn_5qi; + non_dyn_5qi_descriptor non_dyn_5qi; non_dyn_5qi.five_qi = five_qi; - qos_flow_info.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; drb_to_setup_item.qos_flow_info_to_be_setup.emplace(qos_flow_info.qos_flow_id, qos_flow_info); } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index 95d95b5586..bf61d10eeb 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -90,10 +90,10 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t } for (drb_id_t drb_id : drbs_to_add) { - auto& drb_to_setup = req.drbs_to_setup.emplace_back(); - drb_to_setup.drb_id = drb_id; - drb_to_setup.mode = rlc_mode::am; - drb_to_setup.qos_info.drb_qos.qos_characteristics = non_dyn_5qi_descriptor_t{uint_to_five_qi(9)}; + auto& drb_to_setup = req.drbs_to_setup.emplace_back(); + drb_to_setup.drb_id = drb_id; + drb_to_setup.mode = rlc_mode::am; + drb_to_setup.qos_info.drb_qos.qos_desc = non_dyn_5qi_descriptor{uint_to_five_qi(9)}; drb_to_setup.uluptnl_info_list.resize(1); drb_to_setup.uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); drb_to_setup.uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); diff --git a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp index 797189ff01..976689651d 100644 --- a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp +++ b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp @@ -74,7 +74,7 @@ class du_ue_bearer_manager_test : public ::testing::Test teid_pool, du_mng->params, rlf_notifier, - qos_characteristics{}, + standardized_qos_characteristics{}, std::nullopt, dummy_slice_info}); } diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index ecc52ace7a..a18b236eb0 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -412,7 +412,7 @@ TEST_F(ue_config_tester, old_bearer.drb_id = drb_id_t::drb1; auto& old_drb = test_ue->reestablished_cfg_pending->drbs.emplace_back(); old_drb.drb_id = drb_id_t::drb1; - old_drb.qos.qos_characteristics.get_nondyn_5qi().five_qi = uint_to_five_qi(9); + old_drb.qos.qos_desc.get_nondyn_5qi().five_qi = uint_to_five_qi(9); // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index a8d36098c7..8fc05c31cd 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -113,9 +113,9 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set e1ap_qos_flow_qos_param_item qos_flow_info; qos_flow_info.qos_flow_id = uint_to_qos_flow_id(8); - non_dyn_5qi_descriptor_t non_dyn_5qi; + non_dyn_5qi_descriptor non_dyn_5qi; non_dyn_5qi.five_qi = uint_to_five_qi(8); - qos_flow_info.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + qos_flow_info.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.prio_level_arp = 1; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.may_trigger_preemption = false; qos_flow_info.qos_flow_level_qos_params.ng_ran_alloc_retention.is_preemptable = false; diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index ab591afa99..49b982a271 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -231,12 +231,12 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // drb qos // qos flow level qos params // qos characteristics - non_dyn_5qi_descriptor_t non_dyn_5qi; - non_dyn_5qi.five_qi = uint_to_five_qi(8); - non_dyn_5qi.qos_prio_level = uint_to_qos_prio_level(1); - non_dyn_5qi.averaging_win = 3; - non_dyn_5qi.max_data_burst_volume = 1000; - drbs_to_be_setup_mod_item.qos_info.drb_qos.qos_characteristics = non_dyn_5qi; + non_dyn_5qi_descriptor non_dyn_5qi; + non_dyn_5qi.five_qi = uint_to_five_qi(8); + non_dyn_5qi.qos_prio_level = uint_to_qos_prio_level(1); + non_dyn_5qi.averaging_win = 3; + non_dyn_5qi.max_data_burst_volume = 1000; + drbs_to_be_setup_mod_item.qos_info.drb_qos.qos_desc = non_dyn_5qi; // ng ran alloc retention prio drbs_to_be_setup_mod_item.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = 1; @@ -266,7 +266,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi flow_mapped_to_drb flows_mapped_to_drb_item; flows_mapped_to_drb_item.qos_flow_id = uint_to_qos_flow_id(1); // qos characteristics - flows_mapped_to_drb_item.qos_flow_level_qos_params.qos_characteristics = non_dyn_5qi; + flows_mapped_to_drb_item.qos_flow_level_qos_params.qos_desc = non_dyn_5qi; // ng ran alloc retention prio flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.prio_level_arp = 1; flows_mapped_to_drb_item.qos_flow_level_qos_params.alloc_retention_prio.may_trigger_preemption = false; From 9daf9759ab6e0e13d552ae41fc8368a6e2896a4c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 9 Aug 2024 10:00:31 +0200 Subject: [PATCH 219/407] du_manager: remove uneeded fields from du_ue_drb --- .../du_high/du_high_config_translators.cpp | 2 +- include/srsran/ran/qos/qos_parameters.h | 2 +- include/srsran/ran/rrm.h | 3 +- .../converters/rlc_config_helpers.cpp | 9 ++-- .../converters/rlc_config_helpers.h | 2 + .../scheduler_configuration_helpers.cpp | 41 +++++++++---------- .../scheduler_configuration_helpers.h | 6 ++- lib/du_manager/du_ue/du_bearer.cpp | 16 +++----- lib/du_manager/du_ue/du_bearer.h | 35 +++++----------- lib/du_manager/du_ue/du_ue_bearer_manager.cpp | 9 +--- lib/du_manager/du_ue/du_ue_bearer_manager.h | 2 +- .../procedures/ue_configuration_procedure.cpp | 22 +++------- .../procedures/ue_creation_procedure.cpp | 27 ++++++------ .../du_ran_resource_manager.h | 2 +- .../e2sm_rc_control_action_du_executor.cpp | 4 +- .../du_ran_resource_manager_test.cpp | 2 +- .../du_manager/du_ue/du_bearer_test.cpp | 6 +-- .../slicing/slice_scheduler_test.cpp | 6 +-- 18 files changed, 82 insertions(+), 114 deletions(-) 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 29979ecd8f..ba750dc51e 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 @@ -687,7 +687,7 @@ srsran::generate_du_slicing_rrm_policy_config(span for (const auto& cfg : slice_cfg) { rrm_policy_cfgs.emplace_back(); rrm_policy_cfgs.back().rrc_member.s_nssai = cfg.s_nssai; - rrm_policy_cfgs.back().rrc_member.plmn_id = plmn; + rrm_policy_cfgs.back().rrc_member.plmn_id = plmn_identity::parse(plmn).value(); rrm_policy_cfgs.back().min_prb = (nof_cell_crbs * cfg.sched_cfg.min_prb_policy_ratio) / 100; rrm_policy_cfgs.back().max_prb = (nof_cell_crbs * cfg.sched_cfg.max_prb_policy_ratio) / 100; } diff --git a/include/srsran/ran/qos/qos_parameters.h b/include/srsran/ran/qos/qos_parameters.h index 8636434386..3b375040f3 100644 --- a/include/srsran/ran/qos/qos_parameters.h +++ b/include/srsran/ran/qos/qos_parameters.h @@ -10,8 +10,8 @@ #pragma once -#include "five_qi_qos_mapping.h" #include "srsran/ran/qos/five_qi.h" +#include "srsran/ran/qos/five_qi_qos_mapping.h" #include "srsran/ran/qos/packet_error_rate.h" #include "srsran/ran/qos/qos_prio_level.h" #include diff --git a/include/srsran/ran/rrm.h b/include/srsran/ran/rrm.h index bda6b22eee..854a63c709 100644 --- a/include/srsran/ran/rrm.h +++ b/include/srsran/ran/rrm.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/ran/plmn_identity.h" #include "srsran/ran/s_nssai.h" namespace srsran { @@ -17,7 +18,7 @@ namespace srsran { /// Identifier of a RRM Policy Member. /// \remark See O-RAN.WG3.E2SM-RC-R003-v3.00 Section 8.4.3.6 struct rrm_policy_member { - std::string plmn_id; + plmn_identity plmn_id = plmn_identity::test_value(); /// Single Network Slice Selection Assistance Information (S-NSSAI). s_nssai_t s_nssai; diff --git a/lib/du_manager/converters/rlc_config_helpers.cpp b/lib/du_manager/converters/rlc_config_helpers.cpp index 930f763440..1246b62665 100644 --- a/lib/du_manager/converters/rlc_config_helpers.cpp +++ b/lib/du_manager/converters/rlc_config_helpers.cpp @@ -19,13 +19,14 @@ static void fill_rlc_entity_creation_message_common(rlc_entity_creation_message& du_ue_index_t ue_index, du_cell_index_t pcell_index, Bearer& bearer, + const rlc_config& rlc_cfg, const du_manager_params::service_params& du_services, rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier, rlc_pcap& pcap_writer) { msg.gnb_du_id = du_id; msg.ue_index = ue_index; - msg.config = bearer.rlc_cfg; + msg.config = rlc_cfg; msg.rx_upper_dn = &bearer.connector.rlc_rx_sdu_notif; msg.tx_upper_dn = &bearer.connector.rlc_tx_data_notif; msg.tx_upper_cn = &rlc_rlf_notifier; @@ -42,13 +43,14 @@ srsran::srs_du::make_rlc_entity_creation_message(gnb_du_id_t du_ue_index_t ue_index, du_cell_index_t pcell_index, du_ue_srb& bearer, + const rlc_config& rlc_cfg, const du_manager_params::service_params& du_services, rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier, rlc_pcap& pcap_writer) { rlc_entity_creation_message msg; fill_rlc_entity_creation_message_common( - msg, gnb_du_id, ue_index, pcell_index, bearer, du_services, rlc_rlf_notifier, pcap_writer); + msg, gnb_du_id, ue_index, pcell_index, bearer, rlc_cfg, du_services, rlc_rlf_notifier, pcap_writer); msg.rb_id = bearer.srb_id; return msg; } @@ -59,6 +61,7 @@ srsran::srs_du::make_rlc_entity_creation_message(gnb_du_id_t du_ue_index_t ue_index, du_cell_index_t pcell_index, du_ue_drb& bearer, + const rlc_config& rlc_cfg, const du_manager_params::service_params& du_services, rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier, rlc_metrics_notifier* rlc_metrics_notifier_, @@ -66,7 +69,7 @@ srsran::srs_du::make_rlc_entity_creation_message(gnb_du_id_t { rlc_entity_creation_message msg; fill_rlc_entity_creation_message_common( - msg, gnb_du_id, ue_index, pcell_index, bearer, du_services, rlc_rlf_notifier, pcap_writer); + msg, gnb_du_id, ue_index, pcell_index, bearer, rlc_cfg, du_services, rlc_rlf_notifier, pcap_writer); msg.rb_id = bearer.drb_id; msg.rlc_metrics_notif = rlc_metrics_notifier_; return msg; diff --git a/lib/du_manager/converters/rlc_config_helpers.h b/lib/du_manager/converters/rlc_config_helpers.h index 952278def7..2cc85d275e 100644 --- a/lib/du_manager/converters/rlc_config_helpers.h +++ b/lib/du_manager/converters/rlc_config_helpers.h @@ -40,6 +40,7 @@ rlc_entity_creation_message make_rlc_entity_creation_message(gnb_du_id_t du_ue_index_t ue_index, du_cell_index_t pcell_index, du_ue_srb& bearer, + const rlc_config& rlc_cfg, const du_manager_params::service_params& du_services, rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier, rlc_pcap& rlc_pcap); @@ -49,6 +50,7 @@ rlc_entity_creation_message make_rlc_entity_creation_message(gnb_du_id_t du_ue_index_t ue_index, du_cell_index_t pcell_index, du_ue_drb& bearer, + const rlc_config& rlc_cfg, const du_manager_params::service_params& du_services, rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier, rlc_metrics_notifier* rlc_metrics_notif, diff --git a/lib/du_manager/converters/scheduler_configuration_helpers.cpp b/lib/du_manager/converters/scheduler_configuration_helpers.cpp index 2d4d921421..73ba852f4e 100644 --- a/lib/du_manager/converters/scheduler_configuration_helpers.cpp +++ b/lib/du_manager/converters/scheduler_configuration_helpers.cpp @@ -75,40 +75,39 @@ srsran::srs_du::make_sched_cell_config_req(du_cell_index_t cell_index, return sched_req; } -sched_ue_config_request srsran::srs_du::create_scheduler_ue_config_request(const du_ue& ue_ctx) +sched_ue_config_request srsran::srs_du::create_scheduler_ue_config_request(const du_ue_context& ue_ctx, + const du_ue_resource_config& ue_res_cfg) { sched_ue_config_request sched_cfg; sched_cfg.cells.emplace(); sched_cfg.cells->resize(1); - (*sched_cfg.cells)[0] = ue_ctx.resources->cell_group.cells[0]; - sched_cfg.sched_request_config_list = ue_ctx.resources->cell_group.mcg_cfg.scheduling_request_config; + (*sched_cfg.cells)[0] = ue_res_cfg.cell_group.cells[0]; + sched_cfg.sched_request_config_list = ue_res_cfg.cell_group.mcg_cfg.scheduling_request_config; // Add SRB and DRB logical channels. sched_cfg.lc_config_list.emplace(); - for (const du_ue_srb& bearer : ue_ctx.bearers.srbs()) { - sched_cfg.lc_config_list->emplace_back(config_helpers::create_default_logical_channel_config(bearer.lcid())); - auto& sched_lc_ch = sched_cfg.lc_config_list->back(); + for (const auto& bearer : ue_res_cfg.cell_group.rlc_bearers) { + auto& sched_lc_ch = + sched_cfg.lc_config_list->emplace_back(config_helpers::create_default_logical_channel_config(bearer.lcid)); sched_lc_ch.priority = bearer.mac_cfg.priority; sched_lc_ch.lc_group = bearer.mac_cfg.lcg_id; sched_lc_ch.lc_sr_mask = bearer.mac_cfg.lc_sr_mask; sched_lc_ch.lc_sr_delay_timer_applied = bearer.mac_cfg.lc_sr_delay_applied; sched_lc_ch.sr_id.emplace(bearer.mac_cfg.sr_id); - } - for (const auto& bearer : ue_ctx.bearers.drbs()) { - sched_cfg.lc_config_list->emplace_back(config_helpers::create_default_logical_channel_config(bearer.second->lcid)); - auto& sched_lc_ch = sched_cfg.lc_config_list->back(); - sched_lc_ch.priority = bearer.second->mac_cfg.priority; - sched_lc_ch.lc_group = bearer.second->mac_cfg.lcg_id; - sched_lc_ch.lc_sr_mask = bearer.second->mac_cfg.lc_sr_mask; - sched_lc_ch.lc_sr_delay_timer_applied = bearer.second->mac_cfg.lc_sr_delay_applied; - sched_lc_ch.sr_id.emplace(bearer.second->mac_cfg.sr_id); - sched_lc_ch.rrm_policy.s_nssai = bearer.second->s_nssai; - sched_lc_ch.rrm_policy.plmn_id = ue_ctx.nr_cgi.plmn_id.to_string(); + if (bearer.drb_id.has_value()) { + // DRB case + auto& drb_cfg = *std::find_if(ue_res_cfg.drbs.begin(), ue_res_cfg.drbs.end(), [&bearer](const auto& drb) { + return drb.drb_id == bearer.drb_id.value(); + }); + sched_lc_ch.rrm_policy.s_nssai = drb_cfg.s_nssai; + sched_lc_ch.rrm_policy.plmn_id = ue_ctx.nr_cgi.plmn_id; - sched_cfg.drb_info_list.emplace_back(sched_drb_info{.lcid = bearer.second->lcid, - .s_nssai = bearer.second->s_nssai, - .qos_info = bearer.second->qos_info, - .gbr_qos_info = bearer.second->gbr_qos_info}); + sched_cfg.drb_info_list.emplace_back( + sched_drb_info{.lcid = bearer.lcid, + .s_nssai = drb_cfg.s_nssai, + .qos_info = *get_5qi_to_qos_characteristics_mapping(drb_cfg.qos.qos_desc.get_5qi()), + .gbr_qos_info = drb_cfg.qos.gbr_qos_info}); + } } return sched_cfg; diff --git a/lib/du_manager/converters/scheduler_configuration_helpers.h b/lib/du_manager/converters/scheduler_configuration_helpers.h index 5c8b66eb2f..3f71645621 100644 --- a/lib/du_manager/converters/scheduler_configuration_helpers.h +++ b/lib/du_manager/converters/scheduler_configuration_helpers.h @@ -19,7 +19,8 @@ struct du_cell_config; namespace srs_du { -class du_ue; +struct du_ue_context; +struct du_ue_resource_config; /// Derives Scheduler Cell Configuration from DU Cell Configuration. sched_cell_configuration_request_message make_sched_cell_config_req(du_cell_index_t cell_index, @@ -27,7 +28,8 @@ sched_cell_configuration_request_message make_sched_cell_config_req(du_cell_inde span si_payload_sizes); // Create scheduler UE Configuration Request based on DU UE configuration context. -sched_ue_config_request create_scheduler_ue_config_request(const du_ue& u); +sched_ue_config_request create_scheduler_ue_config_request(const du_ue_context& ue_ctx, + const du_ue_resource_config& ue_res_cfg); } // namespace srs_du } // namespace srsran diff --git a/lib/du_manager/du_ue/du_bearer.cpp b/lib/du_manager/du_ue/du_bearer.cpp index e779f64889..a8dcc2f8ef 100644 --- a/lib/du_manager/du_ue/du_bearer.cpp +++ b/lib/du_manager/du_ue/du_bearer.cpp @@ -137,22 +137,15 @@ std::unique_ptr srsran::srs_du::create_drb(const drb_creation_info& d std::unique_ptr drb = std::make_unique(); // > Setup DRB config - drb->drb_id = drb_info.drb_id; - drb->lcid = drb_info.lcid; - drb->rlc_cfg = drb_info.rlc_cfg; - drb->f1u_cfg = drb_info.f1u_cfg; - drb->mac_cfg = drb_info.mac_cfg; - drb->qos_info = drb_info.qos_info; - drb->gbr_qos_info = drb_info.gbr_qos_info; - drb->s_nssai = drb_info.s_nssai; - + drb->drb_id = drb_info.drb_id; + drb->lcid = drb_info.lcid; drb->uluptnl_info_list.assign(drb_info.uluptnl_info_list.begin(), drb_info.uluptnl_info_list.end()); drb->dluptnl_info_list.assign(dluptnl_info_list.begin(), dluptnl_info_list.end()); drb->f1u_gw_bearer = drb_info.du_params.f1u.f1u_gw.create_du_bearer( ue_index, drb->drb_id, - drb->f1u_cfg, + drb_info.f1u_cfg, drb->dluptnl_info_list[0], drb->uluptnl_info_list[0], drb->connector.f1u_gateway_nru_rx_notif, @@ -167,7 +160,7 @@ std::unique_ptr srsran::srs_du::create_drb(const drb_creation_info& d srsran::srs_du::f1u_bearer_creation_message f1u_msg = {}; f1u_msg.ue_index = ue_index; f1u_msg.drb_id = drb->drb_id; - f1u_msg.config = drb->f1u_cfg; + f1u_msg.config = drb_info.f1u_cfg; f1u_msg.dl_tnl_info = drb->dluptnl_info_list[0]; f1u_msg.rx_sdu_notifier = &drb->connector.f1u_rx_sdu_notif; f1u_msg.tx_pdu_notifier = drb->f1u_gw_bearer.get(); @@ -187,6 +180,7 @@ std::unique_ptr srsran::srs_du::create_drb(const drb_creation_info& d ue_index, drb_info.pcell_index, *drb, + drb_info.rlc_cfg, drb_info.du_params.services, drb_info.rlc_rlf_notifier, drb_info.du_params.rlc.rlc_metrics_notif, diff --git a/lib/du_manager/du_ue/du_bearer.h b/lib/du_manager/du_ue/du_bearer.h index dbfe4a06df..d5c9d8352a 100644 --- a/lib/du_manager/du_ue/du_bearer.h +++ b/lib/du_manager/du_ue/du_bearer.h @@ -79,8 +79,6 @@ struct du_drb_connector { /// layers. struct du_ue_srb { srb_id_t srb_id; - rlc_config rlc_cfg; - mac_lc_config mac_cfg; std::unique_ptr rlc_bearer; du_srb_connector connector; @@ -97,19 +95,10 @@ struct du_ue_drb { lcid_t lcid; std::vector uluptnl_info_list; std::vector dluptnl_info_list; - rlc_config rlc_cfg; - mac_lc_config mac_cfg; - f1u_config f1u_cfg; std::unique_ptr f1u_gw_bearer; std::unique_ptr drb_f1u; std::unique_ptr rlc_bearer; du_drb_connector connector; - /// Single Network Slice Selection Assistance Information (S-NSSAI). - s_nssai_t s_nssai; - /// QoS characteristics to be met by the DRB. - standardized_qos_characteristics qos_info; - /// QoS information present only for GBR QoS flows. - std::optional gbr_qos_info; /// \brief Stops DRB by disconnecting MAC, RLC and F1-U notifiers and stopping the RLC timers. void stop(); @@ -117,20 +106,16 @@ struct du_ue_drb { /// Holds information needed to create a DRB in the DU. struct drb_creation_info { - du_ue_index_t ue_index; - du_cell_index_t pcell_index; - drb_id_t drb_id; - lcid_t lcid; - const rlc_config& rlc_cfg; - const mac_lc_config& mac_cfg; - const f1u_config& f1u_cfg; - span uluptnl_info_list; - gtpu_teid_pool& teid_pool; - const du_manager_params& du_params; - rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier; - const standardized_qos_characteristics& qos_info; - std::optional gbr_qos_info; - s_nssai_t s_nssai; + du_ue_index_t ue_index; + du_cell_index_t pcell_index; + drb_id_t drb_id; + lcid_t lcid; + const rlc_config& rlc_cfg; + const f1u_config& f1u_cfg; + span uluptnl_info_list; + gtpu_teid_pool& teid_pool; + const du_manager_params& du_params; + rlc_tx_upper_layer_control_notifier& rlc_rlf_notifier; }; /// \brief Creates a DRB instance for the whole DU. diff --git a/lib/du_manager/du_ue/du_ue_bearer_manager.cpp b/lib/du_manager/du_ue/du_ue_bearer_manager.cpp index 0cbd34133d..5376849663 100644 --- a/lib/du_manager/du_ue/du_ue_bearer_manager.cpp +++ b/lib/du_manager/du_ue/du_ue_bearer_manager.cpp @@ -13,16 +13,11 @@ using namespace srsran; using namespace srs_du; -du_ue_srb& -du_ue_bearer_manager::add_srb(srb_id_t srb_id, const rlc_config& rlc_cfg, std::optional mac_cfg) +du_ue_srb& du_ue_bearer_manager::add_srb(srb_id_t srb_id) { srsran_assert(not srbs().contains(srb_id), "SRB-Id={} already exists", srb_id); srbs_.emplace(srb_id); - srbs_[srb_id].srb_id = srb_id; - srbs_[srb_id].rlc_cfg = rlc_cfg; - if (mac_cfg.has_value()) { - srbs_[srb_id].mac_cfg = *mac_cfg; - } + srbs_[srb_id].srb_id = srb_id; return srbs_[srb_id]; } diff --git a/lib/du_manager/du_ue/du_ue_bearer_manager.h b/lib/du_manager/du_ue/du_ue_bearer_manager.h index 3f8b5b91c8..938a059393 100644 --- a/lib/du_manager/du_ue/du_ue_bearer_manager.h +++ b/lib/du_manager/du_ue/du_ue_bearer_manager.h @@ -20,7 +20,7 @@ class du_ue_bearer_manager { public: /// Add new SRB with specified SRB-Id and configuration. - du_ue_srb& add_srb(srb_id_t srb_id, const rlc_config& rlc_cfg, std::optional mac_cfg = {}); + du_ue_srb& add_srb(srb_id_t srb_id); /// Add new bearer to list of bearers. void add_drb(std::unique_ptr drb); diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index ee6baa3f39..873c34d991 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -45,7 +45,7 @@ void ue_configuration_procedure::operator()(coro_contextresources.value(); ue_res_cfg_resp = ue->resources.update(ue->pcell_index, request, ue->reestablished_cfg_pending.get()); - if (ue_res_cfg_resp.release_required()) { + if (ue_res_cfg_resp.failed()) { proc_logger.log_proc_failure("Failed to allocate DU UE resources"); CORO_EARLY_RETURN(make_ue_config_failure()); } @@ -88,13 +88,14 @@ void ue_configuration_procedure::update_ue_context() srbs_added.push_back(srbid); // >> Create SRB bearer. - du_ue_srb& srb = ue->bearers.add_srb(srbid, bearer.rlc_cfg); + du_ue_srb& srb = ue->bearers.add_srb(srbid); // >> Create RLC SRB entity. srb.rlc_bearer = create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, ue->ue_index, ue->pcell_index, srb, + bearer.rlc_cfg, du_params.services, ue->get_rlc_rlf_notifier(), du_params.rlc.pcap_writer)); @@ -153,7 +154,6 @@ void ue_configuration_procedure::update_ue_context() ue->resources->drbs.end(), [&drbtoadd](const drb_upper_layer_config& drb) { return drb.drb_id == drbtoadd.drb_id; }); srsran_sanity_check(drb_qos_it != ue->resources->drbs.end(), "The bearer config should be created at this point"); - five_qi_t fiveqi = drb_qos_it->qos.qos_desc.get_5qi(); // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, @@ -161,15 +161,11 @@ void ue_configuration_procedure::update_ue_context() drbtoadd.drb_id, it->lcid, it->rlc_cfg, - it->mac_cfg, drb_qos_it->f1u, drbtoadd.uluptnl_info_list, ue_mng.get_f1u_teid_pool(), du_params, - ue->get_rlc_rlf_notifier(), - *get_5qi_to_qos_characteristics_mapping(fiveqi), - drb_qos_it->qos.gbr_qos_info, - drb_qos_it->s_nssai}); + ue->get_rlc_rlf_notifier()}); if (drb == nullptr) { ue_res_cfg_resp.failed_drbs.push_back(drbtoadd.drb_id); proc_logger.log_proc_warning("Failed to create {}. Cause: Failed to allocate DU UE resources.", drbtoadd.drb_id); @@ -200,23 +196,17 @@ void ue_configuration_procedure::update_ue_context() if (drb_it == ue->bearers.drbs().end()) { // >> It's a DRB modification after RRC Reestablishment. We need to create a new DRB instance. - five_qi_t fiveqi = drb_qos_it->qos.qos_desc.get_5qi(); - // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, ue->pcell_index, drbtomod.drb_id, it->lcid, it->rlc_cfg, - it->mac_cfg, drb_qos_it->f1u, drbtomod.uluptnl_info_list, ue_mng.get_f1u_teid_pool(), du_params, - ue->get_rlc_rlf_notifier(), - *get_5qi_to_qos_characteristics_mapping(fiveqi), - drb_qos_it->qos.gbr_qos_info, - drb_qos_it->s_nssai}); + ue->get_rlc_rlf_notifier()}); if (drb == nullptr) { proc_logger.log_proc_warning("Failed to create {}. Cause: Failed to allocate DU UE resources.", drbtomod.drb_id); @@ -293,7 +283,7 @@ async_task ue_configuration_procedure::update_m } // Create Scheduler UE Reconfig Request that will be embedded in the mac configuration request. - mac_ue_reconf_req.sched_cfg = create_scheduler_ue_config_request(*ue); + mac_ue_reconf_req.sched_cfg = create_scheduler_ue_config_request(*ue, *ue->resources); return du_params.mac.ue_cfg.handle_ue_reconfiguration_request(mac_ue_reconf_req); } diff --git a/lib/du_manager/procedures/ue_creation_procedure.cpp b/lib/du_manager/procedures/ue_creation_procedure.cpp index 14d7774d67..a5fb266732 100644 --- a/lib/du_manager/procedures/ue_creation_procedure.cpp +++ b/lib/du_manager/procedures/ue_creation_procedure.cpp @@ -140,17 +140,15 @@ bool ue_creation_procedure::setup_du_ue_resources() f1_req.srbs_to_setup.resize(1); f1_req.srbs_to_setup[0] = srb_id_t::srb1; du_ue_resource_update_response resp = ue_ctx->resources.update(req.pcell_index, f1_req); - if (resp.release_required()) { + if (resp.failed()) { proc_logger.log_proc_failure("Unable to setup DU UE PCell and SRB resources. Cause: {}", resp.procedure_error.error().data()); return false; } // Create DU UE SRB0 and SRB1. - ue_ctx->bearers.add_srb(srb_id_t::srb0, make_default_srb0_rlc_config()); - ue_ctx->bearers.add_srb(srb_id_t::srb1, - ue_ctx->resources->cell_group.rlc_bearers[0].rlc_cfg, - ue_ctx->resources->cell_group.rlc_bearers[0].mac_cfg); + ue_ctx->bearers.add_srb(srb_id_t::srb0); + ue_ctx->bearers.add_srb(srb_id_t::srb1); return true; } @@ -163,19 +161,22 @@ void ue_creation_procedure::create_rlc_srbs() ue_ctx->ue_index, ue_ctx->pcell_index, srb0, + make_default_srb0_rlc_config(), du_params.services, ue_ctx->get_rlc_rlf_notifier(), du_params.rlc.pcap_writer)); // Create SRB1 RLC entity. du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; - srb1.rlc_bearer = create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, - ue_ctx->ue_index, - ue_ctx->pcell_index, - srb1, - du_params.services, - ue_ctx->get_rlc_rlf_notifier(), - du_params.rlc.pcap_writer)); + srb1.rlc_bearer = + create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, + ue_ctx->ue_index, + ue_ctx->pcell_index, + srb1, + ue_ctx->resources->cell_group.rlc_bearers[0].rlc_cfg, + du_params.services, + ue_ctx->get_rlc_rlf_notifier(), + du_params.rlc.pcap_writer)); } async_task ue_creation_procedure::create_mac_ue() @@ -205,7 +206,7 @@ async_task ue_creation_procedure::create_mac_ue() mac_ue_create_msg.ul_ccch_msg = not req.ul_ccch_msg.empty() ? &req.ul_ccch_msg : nullptr; // Create Scheduler UE Config Request that will be embedded in the mac UE creation request. - mac_ue_create_msg.sched_cfg = create_scheduler_ue_config_request(*ue_ctx); + mac_ue_create_msg.sched_cfg = create_scheduler_ue_config_request(*ue_ctx, *ue_ctx->resources); // Request MAC to create new UE. return du_params.mac.ue_cfg.handle_ue_create_request(mac_ue_create_msg); diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h index 71f9f05c05..4ef2b43bfe 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h @@ -24,7 +24,7 @@ struct du_ue_resource_update_response { std::vector failed_drbs; std::vector failed_scells; - bool release_required() const { return not procedure_error.has_value(); } + bool failed() const { return not procedure_error.has_value(); } }; /// \brief This class manages the PHY (e.g. RB and symbols used for PUCCH), MAC (e.g. LCIDs) and RLC resources used diff --git a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp index cd69e67718..d159b8941d 100644 --- a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp +++ b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp @@ -104,8 +104,8 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value(co if (action_params[ran_param_id] == "PLMN Identity") { control_config_params cur_control_params = {}; cur_control_params.rrm_policy_group.emplace(); - cur_control_params.rrm_policy_group.value().pol_member.plmn_id.append( - ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_string()); + cur_control_params.rrm_policy_group.value().pol_member.plmn_id = + plmn_identity::parse(ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_string()).value(); ctrl_cfg.param_list.push_back(cur_control_params); } else if (action_params[ran_param_id] == "SST") { if (ctrl_cfg.param_list.size()) { diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index c81d6e33d2..cb602048cb 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -188,7 +188,7 @@ TEST_P(du_ran_resource_manager_tester, when_srb1_is_added_then_ue_resource_confi ue_ran_resource_configurator& ue_res = create_ue(ue_idx1); auto resp = ue_res.update(to_du_cell_index(0), srb1_creation_req(ue_idx1)); - ASSERT_FALSE(resp.release_required()); + ASSERT_FALSE(resp.failed()); ASSERT_EQ(ue_res->cell_group.rlc_bearers.size(), 1); ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].lcid, srsran::LCID_SRB1); ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].rlc_cfg.mode, rlc_mode::am); diff --git a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp index 976689651d..d7eefa2e66 100644 --- a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp +++ b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp @@ -68,15 +68,11 @@ class du_ue_bearer_manager_test : public ::testing::Test drb_id, lcid, rlc_config{}, - mac_lc_config{}, f1u_config{}, ul_tnls, teid_pool, du_mng->params, - rlf_notifier, - standardized_qos_characteristics{}, - std::nullopt, - dummy_slice_info}); + rlf_notifier}); } }; diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 0fc1d5f5a1..88d3a9cfeb 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -250,8 +250,8 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test constexpr static ran_slice_id_t drb1_slice_id{2}; rb_ratio_slice_scheduler_test() : - slice_scheduler_test( - {{{"00101", s_nssai_t{1}}, MIN_SLICE_RB, MAX_SLICE_RB}, {{"00101", s_nssai_t{2}}, MIN_SLICE_RB, MAX_SLICE_RB}}) + slice_scheduler_test({{{plmn_identity::test_value(), s_nssai_t{1}}, MIN_SLICE_RB, MAX_SLICE_RB}, + {{plmn_identity::test_value(), s_nssai_t{2}}, MIN_SLICE_RB, MAX_SLICE_RB}}) { } @@ -264,7 +264,7 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test req.crnti = to_rnti(0x4601 + ue_idx); req.starts_in_fallback = false; if (lc_cfgs.size() == 0) { - (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.plmn_id = "00101"; + (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.plmn_id = plmn_identity::test_value(); (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.s_nssai = s_nssai_t{1}; } else { *req.cfg.lc_config_list = lc_cfgs; From b18e8919af8c8bf0fbb98cd5d3ad5677392d94db Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 9 Aug 2024 10:37:11 +0200 Subject: [PATCH 220/407] ran: add operator== to DRB types --- include/srsran/f1u/du/f1u_config.h | 6 ++++ include/srsran/ran/qos/packet_error_rate.h | 5 +++ include/srsran/ran/qos/qos_parameters.h | 35 +++++++++++++++++++ .../du_ue_resource_config.h | 8 ++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/include/srsran/f1u/du/f1u_config.h b/include/srsran/f1u/du/f1u_config.h index b5b3b2a7bc..7982b5fc29 100644 --- a/include/srsran/f1u/du/f1u_config.h +++ b/include/srsran/f1u/du/f1u_config.h @@ -21,6 +21,12 @@ struct f1u_config { uint32_t t_notify; ///< Timer used for periodic transmission of uplink notifications uint32_t rlc_queue_bytes_limit; ///< RLC queue limit in bytes. Used for initial report of buffer space to the CU-UP. bool warn_on_drop = true; ///< Log a warning instead of an info message whenever a PDU is dropped + + bool operator==(const f1u_config& other) const + { + return t_notify == other.t_notify and rlc_queue_bytes_limit == other.rlc_queue_bytes_limit and + warn_on_drop == other.warn_on_drop; + } }; } // namespace srsran::srs_du diff --git a/include/srsran/ran/qos/packet_error_rate.h b/include/srsran/ran/qos/packet_error_rate.h index 4f82a433fc..4ba37d49c4 100644 --- a/include/srsran/ran/qos/packet_error_rate.h +++ b/include/srsran/ran/qos/packet_error_rate.h @@ -37,6 +37,11 @@ struct packet_error_rate_t { } double to_double() const { return static_cast(scalar) * std::pow(10, -static_cast(exponent)); } + + bool operator==(const packet_error_rate_t& other) const + { + return scalar == other.scalar and exponent == other.exponent; + } }; } // namespace srsran \ No newline at end of file diff --git a/include/srsran/ran/qos/qos_parameters.h b/include/srsran/ran/qos/qos_parameters.h index 3b375040f3..2edec05b22 100644 --- a/include/srsran/ran/qos/qos_parameters.h +++ b/include/srsran/ran/qos/qos_parameters.h @@ -29,6 +29,13 @@ struct dyn_5qi_descriptor { std::optional averaging_win; /// This parameter should be present if the GBR QoS Flow information is set. std::optional max_data_burst_volume; + + bool operator==(const dyn_5qi_descriptor& other) const + { + return qos_prio_level == other.qos_prio_level and packet_delay_budget == other.packet_delay_budget and + per == other.per and five_qi == other.five_qi and is_delay_critical == other.is_delay_critical and + averaging_win == other.averaging_win and max_data_burst_volume == other.max_data_burst_volume; + } }; struct non_dyn_5qi_descriptor { @@ -41,6 +48,12 @@ struct non_dyn_5qi_descriptor { /// \brief Maximum Data Burst Volume, in case the default value specified in TS23.501, Table 5.7.4-1 is not used. /// This value should only be used in delay-critical GBR DRBs. std::optional max_data_burst_volume; + + bool operator==(const non_dyn_5qi_descriptor& other) const + { + return five_qi == other.five_qi and qos_prio_level == other.qos_prio_level and + averaging_win == other.averaging_win and max_data_burst_volume == other.max_data_burst_volume; + } }; /// QoS Parameters of either a dynamic or non-dynamic 5QI. @@ -65,6 +78,8 @@ struct qos_characteristics { non_dyn_5qi_descriptor& get_nondyn_5qi() { return std::get(choice); } const non_dyn_5qi_descriptor& get_nondyn_5qi() const { return std::get(choice); } + bool operator==(const qos_characteristics& other) const { return choice == other.choice; } + private: std::variant choice; }; @@ -85,6 +100,13 @@ struct gbr_qos_flow_information { /// Indicates the maximum rate for lost packets that can be tolerated in the UL. Expressed in ratio of lost packets /// per number of packets sent, expressed in tenth of percent.Values {0,...,1000}. std::optional max_packet_loss_rate_ul; + + bool operator==(const gbr_qos_flow_information& other) const + { + return max_br_dl == other.max_br_dl and max_br_ul == other.max_br_ul and gbr_dl == other.gbr_dl and + max_packet_loss_rate_dl == other.max_packet_loss_rate_dl and + max_packet_loss_rate_ul == other.max_packet_loss_rate_ul; + } }; struct alloc_and_retention_priority { @@ -92,6 +114,12 @@ struct alloc_and_retention_priority { uint8_t prio_level_arp = 15; bool may_trigger_preemption = false; bool is_preemptable = false; + + bool operator==(const alloc_and_retention_priority& other) const + { + return prio_level_arp == other.prio_level_arp and may_trigger_preemption == other.may_trigger_preemption and + is_preemptable == other.is_preemptable; + } }; struct qos_flow_level_qos_parameters { @@ -103,6 +131,13 @@ struct qos_flow_level_qos_parameters { bool add_qos_flow_info = false; /// This parameter applies to non-GBR flows only. See TS 23.501. bool reflective_qos_attribute_subject_to = false; + + bool operator==(const qos_flow_level_qos_parameters& other) const + { + return qos_desc == other.qos_desc and alloc_retention_prio == other.alloc_retention_prio and + gbr_qos_info == other.gbr_qos_info and add_qos_flow_info == other.add_qos_flow_info and + reflective_qos_attribute_subject_to == other.reflective_qos_attribute_subject_to; + } }; } // namespace srsran \ No newline at end of file diff --git a/lib/du_manager/ran_resource_management/du_ue_resource_config.h b/lib/du_manager/ran_resource_management/du_ue_resource_config.h index 018926cbf8..dcb9b22c01 100644 --- a/lib/du_manager/ran_resource_management/du_ue_resource_config.h +++ b/lib/du_manager/ran_resource_management/du_ue_resource_config.h @@ -35,7 +35,13 @@ struct drb_upper_layer_config { pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; s_nssai_t s_nssai; qos_flow_level_qos_parameters qos; - srs_du::f1u_config f1u; + f1u_config f1u; + + bool operator==(const drb_upper_layer_config& other) const + { + return drb_id == other.drb_id and pdcp_sn_len == other.pdcp_sn_len and s_nssai == other.s_nssai and + qos == other.qos and f1u == other.f1u; + } }; /// Snapshot of the DU resources taken by a UE at a given instant. From 936f91986ce2b3abfa0afe275a51ca4d895beb1b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 9 Aug 2024 15:53:15 +0200 Subject: [PATCH 221/407] du_manager: merge different DU bearer configs into one --- .../converters/asn1_rrc_config_helpers.cpp | 53 +++-- .../converters/asn1_rrc_config_helpers.h | 6 +- .../scheduler_configuration_helpers.cpp | 44 ++-- .../procedures/ue_configuration_procedure.cpp | 51 ++-- .../procedures/ue_creation_procedure.cpp | 19 +- .../du_bearer_resource_manager.cpp | 111 +++------ .../du_ue_resource_config.h | 19 +- .../du_manager/du_manager_test_helpers.cpp | 9 +- .../du_ran_resource_manager_test.cpp | 9 +- .../mac_cell_group_config_converter_test.cpp | 66 +++--- .../du_manager_procedure_test_helpers.cpp | 50 ++-- .../procedures/ue_configuration_test.cpp | 46 ++-- .../serving_cell_config_converter_test.cpp | 223 +++++++++--------- 13 files changed, 337 insertions(+), 369 deletions(-) diff --git a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp index bbec021b2c..4c934ecf90 100644 --- a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp +++ b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp @@ -2996,37 +2996,62 @@ static bool calculate_mac_cell_group_config_diff(asn1::rrc_nr::mac_cell_group_cf return out.sched_request_cfg_present || out.bsr_cfg_present || out.tag_cfg_present || out.phr_cfg_present; } +static static_vector fill_rlc_bearers(const du_ue_resource_config& res) +{ + static_vector list; + for (const auto& srb : res.srbs) { + if (srb.srb_id == srb_id_t::srb0) { + continue; + } + rlc_bearer_config& bearer = list.emplace_back(); + bearer.lcid = srb_id_to_lcid(srb.srb_id); + bearer.rlc_cfg = srb.rlc_cfg; + bearer.mac_cfg = srb.mac_cfg; + } + for (const auto& drb : res.drbs) { + rlc_bearer_config& bearer = list.emplace_back(); + bearer.lcid = drb.lcid; + bearer.drb_id = drb.drb_id; + bearer.rlc_cfg = drb.rlc_cfg; + bearer.mac_cfg = drb.mac_cfg; + } + return list; +} + void srsran::srs_du::calculate_cell_group_config_diff(asn1::rrc_nr::cell_group_cfg_s& out, - const cell_group_config& src, - const cell_group_config& dest) + const du_ue_resource_config& src, + const du_ue_resource_config& dest) { + static_vector src_bearers = fill_rlc_bearers(src); + static_vector dest_bearers = fill_rlc_bearers(dest); + calculate_addmodremlist_diff( out.rlc_bearer_to_add_mod_list, out.rlc_bearer_to_release_list, - src.rlc_bearers, - dest.rlc_bearers, + src_bearers, + dest_bearers, [](const rlc_bearer_config& b) { return make_asn1_rrc_rlc_bearer(b); }, [](const rlc_bearer_config& b) { return (uint8_t)b.lcid; }); - if (dest.cells.contains(0)) { - out.sp_cell_cfg.sp_cell_cfg_ded_present = - calculate_serving_cell_config_diff(out.sp_cell_cfg.sp_cell_cfg_ded, - src.cells.contains(0) ? src.cells[0].serv_cell_cfg : serving_cell_config{}, - dest.cells[0].serv_cell_cfg); + if (dest.cell_group.cells.contains(0)) { + out.sp_cell_cfg.sp_cell_cfg_ded_present = calculate_serving_cell_config_diff( + out.sp_cell_cfg.sp_cell_cfg_ded, + src.cell_group.cells.contains(0) ? src.cell_group.cells[0].serv_cell_cfg : serving_cell_config{}, + dest.cell_group.cells[0].serv_cell_cfg); out.sp_cell_cfg_present = out.sp_cell_cfg.sp_cell_cfg_ded_present; } out.mac_cell_group_cfg_present = - calculate_mac_cell_group_config_diff(out.mac_cell_group_cfg, src.mcg_cfg, dest.mcg_cfg); + calculate_mac_cell_group_config_diff(out.mac_cell_group_cfg, src.cell_group.mcg_cfg, dest.cell_group.mcg_cfg); out.phys_cell_group_cfg_present = true; - if (dest.pcg_cfg.p_nr_fr1.has_value()) { + if (dest.cell_group.pcg_cfg.p_nr_fr1.has_value()) { out.phys_cell_group_cfg.p_nr_fr1_present = true; - out.phys_cell_group_cfg.p_nr_fr1 = dest.pcg_cfg.p_nr_fr1.value(); + out.phys_cell_group_cfg.p_nr_fr1 = dest.cell_group.pcg_cfg.p_nr_fr1.value(); } out.phys_cell_group_cfg.pdsch_harq_ack_codebook.value = - dest.pcg_cfg.pdsch_harq_codebook == pdsch_harq_ack_codebook::dynamic + dest.cell_group.pcg_cfg.pdsch_harq_codebook == pdsch_harq_ack_codebook::dynamic ? phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dyn : asn1::rrc_nr::phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::semi_static; } @@ -3065,7 +3090,7 @@ static ssb_mtc_s make_ssb_mtc(const du_cell_config& du_cell_cfg) bool srsran::srs_du::calculate_reconfig_with_sync_diff(asn1::rrc_nr::recfg_with_sync_s& out, const du_cell_config& du_cell_cfg, - const cell_group_config& dest, + const du_ue_resource_config& dest, const asn1::rrc_nr::ho_prep_info_s& ho_prep_info, rnti_t rnti) { diff --git a/lib/du_manager/converters/asn1_rrc_config_helpers.h b/lib/du_manager/converters/asn1_rrc_config_helpers.h index 9a5b618e90..094999e20b 100644 --- a/lib/du_manager/converters/asn1_rrc_config_helpers.h +++ b/lib/du_manager/converters/asn1_rrc_config_helpers.h @@ -57,13 +57,13 @@ asn1::rrc_nr::tag_s make_asn1_rrc_tag_config(const tag& cfg); /// \param[in] src Previous cell group configuration of UE. /// \param[in] dest Next cell group configuration of UE. void calculate_cell_group_config_diff(asn1::rrc_nr::cell_group_cfg_s& out, - const cell_group_config& src, - const cell_group_config& dest); + const du_ue_resource_config& src, + const du_ue_resource_config& dest); /// Compute ReconfigurationWithSync field. This is used, for instance, during handover. bool calculate_reconfig_with_sync_diff(asn1::rrc_nr::recfg_with_sync_s& out, const du_cell_config& du_cell_cfg, - const cell_group_config& dest, + const du_ue_resource_config& dest, const asn1::rrc_nr::ho_prep_info_s& ho_prep_info, rnti_t rnti); diff --git a/lib/du_manager/converters/scheduler_configuration_helpers.cpp b/lib/du_manager/converters/scheduler_configuration_helpers.cpp index 73ba852f4e..f7adff134c 100644 --- a/lib/du_manager/converters/scheduler_configuration_helpers.cpp +++ b/lib/du_manager/converters/scheduler_configuration_helpers.cpp @@ -86,28 +86,30 @@ sched_ue_config_request srsran::srs_du::create_scheduler_ue_config_request(const sched_cfg.sched_request_config_list = ue_res_cfg.cell_group.mcg_cfg.scheduling_request_config; // Add SRB and DRB logical channels. sched_cfg.lc_config_list.emplace(); - for (const auto& bearer : ue_res_cfg.cell_group.rlc_bearers) { + for (const auto& srb : ue_res_cfg.srbs) { + auto& sched_lc_ch = sched_cfg.lc_config_list->emplace_back( + config_helpers::create_default_logical_channel_config(srb_id_to_lcid(srb.srb_id))); + sched_lc_ch.priority = srb.mac_cfg.priority; + sched_lc_ch.lc_group = srb.mac_cfg.lcg_id; + sched_lc_ch.lc_sr_mask = srb.mac_cfg.lc_sr_mask; + sched_lc_ch.lc_sr_delay_timer_applied = srb.mac_cfg.lc_sr_delay_applied; + sched_lc_ch.sr_id.emplace(srb.mac_cfg.sr_id); + } + for (const auto& drb : ue_res_cfg.drbs) { auto& sched_lc_ch = - sched_cfg.lc_config_list->emplace_back(config_helpers::create_default_logical_channel_config(bearer.lcid)); - sched_lc_ch.priority = bearer.mac_cfg.priority; - sched_lc_ch.lc_group = bearer.mac_cfg.lcg_id; - sched_lc_ch.lc_sr_mask = bearer.mac_cfg.lc_sr_mask; - sched_lc_ch.lc_sr_delay_timer_applied = bearer.mac_cfg.lc_sr_delay_applied; - sched_lc_ch.sr_id.emplace(bearer.mac_cfg.sr_id); - if (bearer.drb_id.has_value()) { - // DRB case - auto& drb_cfg = *std::find_if(ue_res_cfg.drbs.begin(), ue_res_cfg.drbs.end(), [&bearer](const auto& drb) { - return drb.drb_id == bearer.drb_id.value(); - }); - sched_lc_ch.rrm_policy.s_nssai = drb_cfg.s_nssai; - sched_lc_ch.rrm_policy.plmn_id = ue_ctx.nr_cgi.plmn_id; - - sched_cfg.drb_info_list.emplace_back( - sched_drb_info{.lcid = bearer.lcid, - .s_nssai = drb_cfg.s_nssai, - .qos_info = *get_5qi_to_qos_characteristics_mapping(drb_cfg.qos.qos_desc.get_5qi()), - .gbr_qos_info = drb_cfg.qos.gbr_qos_info}); - } + sched_cfg.lc_config_list->emplace_back(config_helpers::create_default_logical_channel_config(drb.lcid)); + sched_lc_ch.priority = drb.mac_cfg.priority; + sched_lc_ch.lc_group = drb.mac_cfg.lcg_id; + sched_lc_ch.lc_sr_mask = drb.mac_cfg.lc_sr_mask; + sched_lc_ch.lc_sr_delay_timer_applied = drb.mac_cfg.lc_sr_delay_applied; + sched_lc_ch.sr_id.emplace(drb.mac_cfg.sr_id); + sched_lc_ch.rrm_policy.s_nssai = drb.s_nssai; + sched_lc_ch.rrm_policy.plmn_id = ue_ctx.nr_cgi.plmn_id; + sched_cfg.drb_info_list.emplace_back( + sched_drb_info{.lcid = drb.lcid, + .s_nssai = drb.s_nssai, + .qos_info = *get_5qi_to_qos_characteristics_mapping(drb.qos.qos_desc.get_5qi()), + .gbr_qos_info = drb.qos.gbr_qos_info}); } return sched_cfg; diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 873c34d991..bb5111d78b 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -76,11 +76,8 @@ async_task ue_configuration_procedure::stop_drbs_to_rem() void ue_configuration_procedure::update_ue_context() { // > Create DU UE SRB objects. - for (const auto& bearer : ue->resources->cell_group.rlc_bearers) { - if (bearer.drb_id.has_value()) { - continue; - } - srb_id_t srbid = to_srb_id(bearer.lcid); + for (const auto& srb_cfg : ue->resources->srbs) { + srb_id_t srbid = srb_cfg.srb_id; if (ue->bearers.srbs().contains(srbid)) { // >> In case the SRB already exists, we ignore the request for its reconfiguration. continue; @@ -95,7 +92,7 @@ void ue_configuration_procedure::update_ue_context() ue->ue_index, ue->pcell_index, srb, - bearer.rlc_cfg, + srb_cfg.rlc_cfg, du_params.services, ue->get_rlc_rlf_notifier(), du_params.rlc.pcap_writer)); @@ -144,24 +141,15 @@ void ue_configuration_procedure::update_ue_context() } // Find the configurations for this DRB. - auto it = std::find_if(ue->resources->cell_group.rlc_bearers.begin(), - ue->resources->cell_group.rlc_bearers.end(), - [&drbtoadd](const rlc_bearer_config& e) { return e.drb_id == drbtoadd.drb_id; }); - srsran_sanity_check(it != ue->resources->cell_group.rlc_bearers.end(), - "The bearer config should be created at this point"); - auto drb_qos_it = - std::find_if(ue->resources->drbs.begin(), - ue->resources->drbs.end(), - [&drbtoadd](const drb_upper_layer_config& drb) { return drb.drb_id == drbtoadd.drb_id; }); - srsran_sanity_check(drb_qos_it != ue->resources->drbs.end(), "The bearer config should be created at this point"); + const du_ue_drb_config& drb_cfg = ue->resources->drbs[drbtoadd.drb_id]; // Create DU DRB instance. std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, ue->pcell_index, drbtoadd.drb_id, - it->lcid, - it->rlc_cfg, - drb_qos_it->f1u, + drb_cfg.lcid, + drb_cfg.rlc_cfg, + drb_cfg.f1u, drbtoadd.uluptnl_info_list, ue_mng.get_f1u_teid_pool(), du_params, @@ -183,14 +171,7 @@ void ue_configuration_procedure::update_ue_context() } // Find the RLC configuration for this DRB. - auto it = std::find_if(ue->resources->cell_group.rlc_bearers.begin(), - ue->resources->cell_group.rlc_bearers.end(), - [&drbtomod](const rlc_bearer_config& e) { return e.drb_id == drbtomod.drb_id; }); - srsran_assert(it != ue->resources->cell_group.rlc_bearers.end(), - "The bearer config should be created at this point"); - auto drb_qos_it = std::find_if(ue->resources->drbs.begin(), - ue->resources->drbs.end(), - [&drbtomod](const auto& drb) { return drb.drb_id == drbtomod.drb_id; }); + const du_ue_drb_config& drb_cfg = ue->resources->drbs[drbtomod.drb_id]; auto drb_it = ue->bearers.drbs().find(drbtomod.drb_id); if (drb_it == ue->bearers.drbs().end()) { @@ -200,9 +181,9 @@ void ue_configuration_procedure::update_ue_context() std::unique_ptr drb = create_drb(drb_creation_info{ue->ue_index, ue->pcell_index, drbtomod.drb_id, - it->lcid, - it->rlc_cfg, - drb_qos_it->f1u, + drb_cfg.lcid, + drb_cfg.rlc_cfg, + drb_cfg.f1u, drbtomod.uluptnl_info_list, ue_mng.get_f1u_teid_pool(), du_params, @@ -329,7 +310,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo // set to "RLCReestablish". ue->reestablished_cfg_pending = nullptr; - calculate_cell_group_config_diff(asn1_cell_group, cell_group_config{}, ue->resources->cell_group); + calculate_cell_group_config_diff(asn1_cell_group, du_ue_resource_config{}, ue->resources.value()); auto it = std::find_if(asn1_cell_group.rlc_bearer_to_add_mod_list.begin(), asn1_cell_group.rlc_bearer_to_add_mod_list.end(), [](const auto& b) { return b.lc_ch_id == LCID_SRB1; }); @@ -343,17 +324,17 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo } } else if (request.full_config_required) { // The CU requested a full configuration of the UE cellGroupConfig. - calculate_cell_group_config_diff(asn1_cell_group, {}, ue->resources->cell_group); + calculate_cell_group_config_diff(asn1_cell_group, {}, ue->resources.value()); resp.full_config_present = true; } else if (not request.source_cell_group_cfg.empty()) { // In case of source cell group configuration is passed, a delta configuration should be generated with it. // TODO: Apply diff using sourceCellGroup. For now, we use fullConfig. - calculate_cell_group_config_diff(asn1_cell_group, {}, ue->resources->cell_group); + calculate_cell_group_config_diff(asn1_cell_group, {}, ue->resources.value()); resp.full_config_present = true; } else { - calculate_cell_group_config_diff(asn1_cell_group, prev_ue_res_cfg.cell_group, ue->resources->cell_group); + calculate_cell_group_config_diff(asn1_cell_group, prev_ue_res_cfg, ue->resources.value()); } // Include reconfiguration with sync if HandoverPreparationInformation is included. @@ -370,7 +351,7 @@ f1ap_ue_context_update_response ue_configuration_procedure::make_ue_config_respo asn1_cell_group.sp_cell_cfg.recfg_with_sync_present = calculate_reconfig_with_sync_diff(asn1_cell_group.sp_cell_cfg.recfg_with_sync, du_params.ran.cells[0], - ue->resources->cell_group, + ue->resources.value(), ho_prep_info, ue->rnti); if (not asn1_cell_group.sp_cell_cfg.recfg_with_sync_present) { diff --git a/lib/du_manager/procedures/ue_creation_procedure.cpp b/lib/du_manager/procedures/ue_creation_procedure.cpp index a5fb266732..34379f1a9b 100644 --- a/lib/du_manager/procedures/ue_creation_procedure.cpp +++ b/lib/du_manager/procedures/ue_creation_procedure.cpp @@ -168,15 +168,14 @@ void ue_creation_procedure::create_rlc_srbs() // Create SRB1 RLC entity. du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; - srb1.rlc_bearer = - create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, - ue_ctx->ue_index, - ue_ctx->pcell_index, - srb1, - ue_ctx->resources->cell_group.rlc_bearers[0].rlc_cfg, - du_params.services, - ue_ctx->get_rlc_rlf_notifier(), - du_params.rlc.pcap_writer)); + srb1.rlc_bearer = create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, + ue_ctx->ue_index, + ue_ctx->pcell_index, + srb1, + ue_ctx->resources->srbs[srb_id_t::srb1].rlc_cfg, + du_params.services, + ue_ctx->get_rlc_rlf_notifier(), + du_params.rlc.pcap_writer)); } async_task ue_creation_procedure::create_mac_ue() @@ -233,7 +232,7 @@ f1ap_ue_creation_response ue_creation_procedure::create_f1ap_ue() // Pack SRB1 configuration that is going to be passed in the F1AP DU-to-CU-RRC-Container IE to the CU as per TS38.473, // Section 8.4.1.2. cell_group_cfg_s cell_group; - calculate_cell_group_config_diff(cell_group, {}, ue_ctx->resources->cell_group); + calculate_cell_group_config_diff(cell_group, {}, ue_ctx->resources.value()); { asn1::bit_ref bref{f1ap_msg.du_cu_rrc_container}; diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp index ee7e66003f..12062c60f2 100644 --- a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp @@ -29,13 +29,11 @@ static auto find_by_drb_id(drb_id_t drb_id, Vec&& bearers) } /// \brief Finds an unused LCID for DRBs given a list of UE configured RLC bearers. -static lcid_t find_empty_lcid(span rlc_bearers) +static lcid_t find_empty_lcid(const slotted_id_vector& drbs) { static_vector used_lcids; - for (const auto& bearer : rlc_bearers) { - if (bearer.drb_id.has_value()) { - used_lcids.push_back(bearer.lcid); - } + for (const auto& drb : drbs) { + used_lcids.push_back(drb.lcid); } std::sort(used_lcids.begin(), used_lcids.end()); if (used_lcids.empty() or used_lcids[0] > LCID_MIN_DRB) { @@ -54,8 +52,8 @@ static lcid_t find_empty_lcid(span rlc_bearers) return lcid; } -static error_type validate_drb_setup_request(const f1ap_drb_to_setup& drb, - span rlc_bearers, +static error_type validate_drb_setup_request(const f1ap_drb_to_setup& drb, + const slotted_id_vector& drb_list, const std::map& qos_config) { // Validate QOS config. @@ -80,20 +78,19 @@ static error_type validate_drb_setup_request(const f1ap_drb_to_setu } // Search for established DRB with matching DRB-Id. - auto prev_drb_it = find_by_drb_id(drb.drb_id, rlc_bearers); - if (prev_drb_it != rlc_bearers.end()) { + if (drb_list.contains(drb.drb_id)) { return make_unexpected("DRB-Id already exists"); } return {}; } -static error_type validate_drb_modification_request(const f1ap_drb_to_modify& drb, - span rlc_bearers) +static error_type +validate_drb_modification_request(const f1ap_drb_to_modify& drb, + const slotted_id_vector& drb_list) { // Search for established DRB with matching DRB-Id. - auto prev_drb_it = find_by_drb_id(drb.drb_id, rlc_bearers); - if (prev_drb_it == rlc_bearers.end()) { + if (not drb_list.contains(drb.drb_id)) { return make_unexpected("DRB-Id not found"); } @@ -107,29 +104,11 @@ static error_type validate_drb_modification_request(const f1ap_drb_ static void reestablish_context(du_ue_resource_config& new_ue_cfg, const du_ue_resource_config& old_ue_cfg) { - for (const rlc_bearer_config& old_bearer : old_ue_cfg.cell_group.rlc_bearers) { - auto it = std::find_if(new_ue_cfg.cell_group.rlc_bearers.begin(), - new_ue_cfg.cell_group.rlc_bearers.end(), - [&old_bearer](const rlc_bearer_config& item) { - return item.drb_id == old_bearer.drb_id and - (item.drb_id.has_value() or (item.lcid == old_bearer.lcid)); - }); - if (it == new_ue_cfg.cell_group.rlc_bearers.end()) { - // Bearer not found in new context. Add it. - new_ue_cfg.cell_group.rlc_bearers.push_back(old_bearer); - if (old_bearer.drb_id.has_value()) { - const drb_upper_layer_config& old_drb = *find_by_drb_id(old_bearer.drb_id.value(), old_ue_cfg.drbs); - new_ue_cfg.drbs.push_back(old_drb); - } - } else { - // Bearer already exists. Overwrite it. - *it = old_bearer; - if (old_bearer.drb_id.has_value()) { - const drb_upper_layer_config& old_drb = *find_by_drb_id(old_bearer.drb_id.value(), old_ue_cfg.drbs); - drb_upper_layer_config& new_drb = *find_by_drb_id(old_bearer.drb_id.value(), new_ue_cfg.drbs); - new_drb = old_drb; - } - } + for (const du_ue_srb_config& old_srb : old_ue_cfg.srbs) { + new_ue_cfg.srbs.emplace(old_srb.srb_id, old_srb); + } + for (const du_ue_drb_config& old_drb : old_ue_cfg.drbs) { + new_ue_cfg.drbs.emplace(old_drb.drb_id, old_drb); } } @@ -166,15 +145,6 @@ du_bearer_resource_manager::update(du_ue_resource_config& u // Modify DRBs. resp.drbs_failed_to_mod = modify_drbs(ue_cfg, upd_req); - // Sort RAN bearers by LCID. - std::sort(ue_cfg.cell_group.rlc_bearers.begin(), - ue_cfg.cell_group.rlc_bearers.end(), - [](const auto& lhs, const auto& rhs) { return lhs.lcid < rhs.lcid; }); - - // Sort DRBs by DRB ID. - std::sort( - ue_cfg.drbs.begin(), ue_cfg.drbs.end(), [](const auto& lhs, const auto& rhs) { return lhs.drb_id < rhs.drb_id; }); - return resp; } @@ -182,22 +152,21 @@ void du_bearer_resource_manager::setup_srbs(du_ue_resource_config& const du_ue_bearer_resource_update_request& upd_req) { for (srb_id_t srb_id : upd_req.srbs_to_setup) { - auto srb_it = find_by_srb_id(srb_id, ue_cfg.cell_group.rlc_bearers); - if (srb_it != ue_cfg.cell_group.rlc_bearers.end()) { + if (ue_cfg.srbs.contains(srb_id)) { // The SRB is already setup (e.g. SRB1 gets setup automatically). continue; } - auto srb_config_it = srb_config.find(srb_id); - lcid_t lcid = srb_id_to_lcid(srb_id); - auto& new_srb = ue_cfg.cell_group.rlc_bearers.emplace_back(); - new_srb.lcid = lcid; + ue_cfg.srbs.emplace(srb_id); + du_ue_srb_config& new_srb = ue_cfg.srbs[srb_id]; + new_srb.srb_id = srb_id; + auto srb_config_it = srb_config.find(srb_id); if (srb_config_it != srb_config.end()) { new_srb.rlc_cfg = srb_config_it->second.rlc; new_srb.mac_cfg = srb_config_it->second.mac; } else { new_srb.rlc_cfg = make_default_srb_rlc_config(); - new_srb.mac_cfg = make_default_srb_mac_lc_config(lcid); + new_srb.mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } } } @@ -208,7 +177,7 @@ std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_conf std::vector failed_drbs; for (const f1ap_drb_to_setup& drb_to_setup : upd_req.drbs_to_setup) { - auto res = validate_drb_setup_request(drb_to_setup, ue_cfg.cell_group.rlc_bearers, qos_config); + auto res = validate_drb_setup_request(drb_to_setup, ue_cfg.drbs, qos_config); if (not res.has_value()) { failed_drbs.push_back(drb_to_setup.drb_id); logger.warning("Failed to allocate {}. Cause: {}", drb_to_setup.drb_id, res.error()); @@ -216,7 +185,7 @@ std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_conf } // Allocate LCID. - lcid_t lcid = find_empty_lcid(ue_cfg.cell_group.rlc_bearers); + lcid_t lcid = find_empty_lcid(ue_cfg.drbs); if (lcid > LCID_MAX_DRB) { logger.warning("Failed to allocate {}. Cause: No available LCIDs", drb_to_setup.drb_id); failed_drbs.push_back(drb_to_setup.drb_id); @@ -228,22 +197,18 @@ std::vector du_bearer_resource_manager::setup_drbs(du_ue_resource_conf const du_qos_config& qos = qos_config.at(fiveqi); // Create new DRB QoS Flow. - drb_upper_layer_config& drb_qos = ue_cfg.drbs.emplace_back(); - drb_qos.drb_id = drb_to_setup.drb_id; - drb_qos.pdcp_sn_len = drb_to_setup.pdcp_sn_len; - drb_qos.s_nssai = drb_to_setup.qos_info.s_nssai; - drb_qos.qos = drb_to_setup.qos_info.drb_qos; - drb_qos.f1u = qos.f1u; - - // Create new L2 DRB. - rlc_bearer_config& ran_bearer = ue_cfg.cell_group.rlc_bearers.emplace_back(); - ran_bearer.lcid = lcid; - ran_bearer.drb_id = drb_to_setup.drb_id; - ran_bearer.rlc_cfg = qos.rlc; - ran_bearer.mac_cfg = qos.mac; + du_ue_drb_config& new_drb = ue_cfg.drbs.emplace(drb_to_setup.drb_id); + new_drb.drb_id = drb_to_setup.drb_id; + new_drb.lcid = lcid; + new_drb.pdcp_sn_len = drb_to_setup.pdcp_sn_len; + new_drb.s_nssai = drb_to_setup.qos_info.s_nssai; + new_drb.qos = drb_to_setup.qos_info.drb_qos; + new_drb.f1u = qos.f1u; + new_drb.rlc_cfg = qos.rlc; + new_drb.mac_cfg = qos.mac; // Update pdcp_sn_len in RLC config - auto& rlc_cfg = ran_bearer.rlc_cfg; + auto& rlc_cfg = new_drb.rlc_cfg; switch (rlc_cfg.mode) { case rlc_mode::am: rlc_cfg.am.tx.pdcp_sn_len = drb_to_setup.pdcp_sn_len; @@ -266,7 +231,7 @@ std::vector du_bearer_resource_manager::modify_drbs(du_ue_resource_con std::vector failed_drbs; for (const f1ap_drb_to_modify& drb_to_modify : upd_req.drbs_to_mod) { - auto res = validate_drb_modification_request(drb_to_modify, ue_cfg.cell_group.rlc_bearers); + auto res = validate_drb_modification_request(drb_to_modify, ue_cfg.drbs); if (not res.has_value()) { logger.warning("Failed to modify {}. Cause: {}", drb_to_modify.drb_id, res.error()); failed_drbs.push_back(drb_to_modify.drb_id); @@ -281,16 +246,12 @@ void du_bearer_resource_manager::rem_drbs(du_ue_resource_config& const du_ue_bearer_resource_update_request& upd_req) { for (drb_id_t drb_id : upd_req.drbs_to_rem) { - auto ran_bearer_it = find_by_drb_id(drb_id, ue_cfg.cell_group.rlc_bearers); - if (ran_bearer_it == ue_cfg.cell_group.rlc_bearers.end()) { + if (not ue_cfg.drbs.contains(drb_id)) { logger.warning("Failed to release {}. Cause: DRB not found", drb_id); continue; } - auto bearer_qos_it = find_by_drb_id(drb_id, ue_cfg.drbs); - // Remove DRB - ue_cfg.cell_group.rlc_bearers.erase(ran_bearer_it); - ue_cfg.drbs.erase(bearer_qos_it); + ue_cfg.drbs.erase(drb_id); } } diff --git a/lib/du_manager/ran_resource_management/du_ue_resource_config.h b/lib/du_manager/ran_resource_management/du_ue_resource_config.h index dcb9b22c01..0b40fc4a44 100644 --- a/lib/du_manager/ran_resource_management/du_ue_resource_config.h +++ b/lib/du_manager/ran_resource_management/du_ue_resource_config.h @@ -24,20 +24,30 @@ namespace srs_du { /// This struct stores the accumulated CellGroupConfig. struct cell_group_config { - std::vector rlc_bearers; mac_cell_group_config mcg_cfg; physical_cell_group_config pcg_cfg; slotted_vector cells; }; -struct drb_upper_layer_config { +/// Parameters of an SRB of the DU UE context. +struct du_ue_srb_config { + srb_id_t srb_id; + rlc_config rlc_cfg; + mac_lc_config mac_cfg; +}; + +/// Parameters of a DRB of the DU UE context. +struct du_ue_drb_config { drb_id_t drb_id; + lcid_t lcid; pdcp_sn_size pdcp_sn_len = pdcp_sn_size::invalid; s_nssai_t s_nssai; qos_flow_level_qos_parameters qos; f1u_config f1u; + rlc_config rlc_cfg; + mac_lc_config mac_cfg; - bool operator==(const drb_upper_layer_config& other) const + bool operator==(const du_ue_drb_config& other) const { return drb_id == other.drb_id and pdcp_sn_len == other.pdcp_sn_len and s_nssai == other.s_nssai and qos == other.qos and f1u == other.f1u; @@ -46,8 +56,9 @@ struct drb_upper_layer_config { /// Snapshot of the DU resources taken by a UE at a given instant. struct du_ue_resource_config { + slotted_id_table srbs; /// Upper layer configuration of UE DRBs - std::vector drbs; + slotted_id_vector drbs; /// CellGroupConfiguration of the RAN resources allocated to a UE. cell_group_config cell_group; }; diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index bf61d10eeb..ad1e5a7a83 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -21,10 +21,11 @@ using namespace srs_du; dummy_ue_resource_configurator_factory::dummy_ue_resource_configurator_factory() { - next_context_update_result.cell_group.rlc_bearers.resize(1); - next_context_update_result.cell_group.rlc_bearers[0].lcid = LCID_SRB1; - next_context_update_result.cell_group.rlc_bearers[0].rlc_cfg = make_default_srb_rlc_config(); - next_context_update_result.cell_group.rlc_bearers[0].mac_cfg = make_default_srb_mac_lc_config(LCID_SRB1); + next_context_update_result.srbs.emplace(srb_id_t::srb1); + auto& new_srb = next_context_update_result.srbs[srb_id_t::srb1]; + new_srb.srb_id = srb_id_t::srb1; + new_srb.rlc_cfg = make_default_srb_rlc_config(); + new_srb.mac_cfg = make_default_srb_mac_lc_config(LCID_SRB1); next_context_update_result.cell_group.cells.emplace(0, config_helpers::create_default_initial_ue_spcell_cell_config()); next_context_update_result.cell_group.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index cb602048cb..9e10b7673a 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -175,7 +175,8 @@ TEST_P(du_ran_resource_manager_tester, when_ue_resource_config_is_created_then_p ASSERT_FALSE(ue_res.empty()); ASSERT_EQ(ue_res->cell_group.cells.size(), 1); ASSERT_TRUE(ue_res->cell_group.cells.contains(0)); - ASSERT_TRUE(ue_res->cell_group.rlc_bearers.empty()); + ASSERT_TRUE(ue_res->srbs.empty()); + ASSERT_TRUE(ue_res->drbs.empty()); ASSERT_EQ(ue_res->cell_group.cells[0].serv_cell_cfg.cell_index, to_du_cell_index(0)); ASSERT_EQ(ue_res->cell_group.cells[0].serv_cell_idx, SERVING_CELL_PCELL_IDX); ASSERT_FALSE(ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list.empty()); @@ -189,9 +190,9 @@ TEST_P(du_ran_resource_manager_tester, when_srb1_is_added_then_ue_resource_confi auto resp = ue_res.update(to_du_cell_index(0), srb1_creation_req(ue_idx1)); ASSERT_FALSE(resp.failed()); - ASSERT_EQ(ue_res->cell_group.rlc_bearers.size(), 1); - ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].lcid, srsran::LCID_SRB1); - ASSERT_EQ(ue_res->cell_group.rlc_bearers[0].rlc_cfg.mode, rlc_mode::am); + ASSERT_EQ(ue_res->srbs.size(), 1); + ASSERT_TRUE(ue_res->srbs.contains(srb_id_t::srb1)); + ASSERT_EQ(ue_res->srbs[srb_id_t::srb1].rlc_cfg.mode, rlc_mode::am); } TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_use_different_sr_offsets) diff --git a/tests/unittests/du_manager/mac_cell_group_config_converter_test.cpp b/tests/unittests/du_manager/mac_cell_group_config_converter_test.cpp index 75efda4c52..6479cc2ed4 100644 --- a/tests/unittests/du_manager/mac_cell_group_config_converter_test.cpp +++ b/tests/unittests/du_manager/mac_cell_group_config_converter_test.cpp @@ -15,23 +15,23 @@ using namespace srsran; -static srs_du::cell_group_config make_initial_cell_group_config() +static srs_du::du_ue_resource_config make_initial_du_ue_resource_config() { - srs_du::cell_group_config dest_cell_grp_cfg{}; - dest_cell_grp_cfg.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); - return dest_cell_grp_cfg; + srs_du::du_ue_resource_config dest_cfg{}; + dest_cfg.cell_group.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); + return dest_cfg; } TEST(mac_cell_group_config_converter_test, test_default_initial_sr_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); const auto& rrc_mcg_cfg = rrc_cell_grp_cfg.mac_cell_group_cfg; - const auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + const auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; if (not dest_mcg_cfg.scheduling_request_config.empty()) { ASSERT_TRUE(rrc_mcg_cfg.sched_request_cfg_present); @@ -44,10 +44,10 @@ TEST(mac_cell_group_config_converter_test, test_default_initial_sr_cfg_conversio TEST(mac_cell_group_config_converter_test, test_custom_sr_cfg_conversion) { - const auto& src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + const auto& src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Add new configuration to be setup. - auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; dest_mcg_cfg.scheduling_request_config.push_back(scheduling_request_to_addmod{ .sr_id = static_cast(1), .prohibit_timer = sr_prohib_timer::ms1, .max_tx = sr_max_tx::n8}); dest_mcg_cfg.scheduling_request_config.push_back( @@ -57,7 +57,7 @@ TEST(mac_cell_group_config_converter_test, test_custom_sr_cfg_conversion) dest_mcg_cfg.scheduling_request_config.erase(dest_mcg_cfg.scheduling_request_config.begin()); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); @@ -73,16 +73,16 @@ TEST(mac_cell_group_config_converter_test, test_custom_sr_cfg_conversion) TEST(mac_cell_group_config_converter_test, test_custom_bsr_cfg_conversion) { - const auto& src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + const auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Add new configuration to be setup. Assume BSR Config is already set. - auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; dest_mcg_cfg.bsr_cfg.value().periodic_timer = srsran::periodic_bsr_timer::sf2560; dest_mcg_cfg.bsr_cfg.value().lc_sr_delay_timer = logical_channel_sr_delay_timer::sf1024; dest_mcg_cfg.bsr_cfg.value().retx_timer = srsran::retx_bsr_timer::sf5120; asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); @@ -97,14 +97,14 @@ TEST(mac_cell_group_config_converter_test, test_custom_bsr_cfg_conversion) TEST(mac_cell_group_config_converter_test, test_default_initial_tag_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); const auto& rrc_mcg_cfg = rrc_cell_grp_cfg.mac_cell_group_cfg; - const auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + const auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; if (not dest_mcg_cfg.tag_config.empty()) { ASSERT_TRUE(rrc_mcg_cfg.tag_cfg_present); @@ -116,16 +116,16 @@ TEST(mac_cell_group_config_converter_test, test_default_initial_tag_cfg_conversi TEST(mac_cell_group_config_converter_test, test_custom_tag_cfg_conversion) { - const auto& src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + const auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Add new configuration to be setup. - auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; dest_mcg_cfg.tag_config.push_back(tag{.tag_id = static_cast(1), .ta_timer = time_alignment_timer::ms2560}); dest_mcg_cfg.tag_config.push_back(tag{.tag_id = static_cast(2), .ta_timer = time_alignment_timer::ms1280}); dest_mcg_cfg.tag_config.erase(dest_mcg_cfg.tag_config.begin()); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); @@ -141,14 +141,14 @@ TEST(mac_cell_group_config_converter_test, test_custom_tag_cfg_conversion) TEST(mac_cell_group_config_converter_test, test_default_initial_phr_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); const auto& rrc_mcg_cfg = rrc_cell_grp_cfg.mac_cell_group_cfg; - const auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + const auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; if (dest_mcg_cfg.phr_cfg.has_value()) { ASSERT_TRUE(rrc_mcg_cfg.phr_cfg_present); @@ -159,10 +159,10 @@ TEST(mac_cell_group_config_converter_test, test_default_initial_phr_cfg_conversi TEST(mac_cell_group_config_converter_test, test_custom_phr_cfg_conversion) { - const auto& src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + const auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Add new configuration to be setup. - auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; dest_mcg_cfg.phr_cfg.value().periodic_timer = phr_periodic_timer::sf100; dest_mcg_cfg.phr_cfg.value().prohibit_timer = phr_prohibit_timer::sf20; dest_mcg_cfg.phr_cfg.value().power_factor_change = phr_tx_power_factor_change::db3; @@ -172,7 +172,7 @@ TEST(mac_cell_group_config_converter_test, test_custom_phr_cfg_conversion) dest_mcg_cfg.phr_cfg.value().phr_mode = phr_mode_other_cg::virtual_; asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); @@ -196,14 +196,14 @@ TEST(mac_cell_group_config_converter_test, test_custom_phr_cfg_conversion) TEST(serving_cell_config_converter_test, test_phr_cfg_release_conversion) { - const auto& src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + const auto& src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Remove PHR configuration to be setup. - auto& dest_mcg_cfg = dest_cell_grp_cfg.mcg_cfg; + auto& dest_mcg_cfg = dest_cfg.cell_group.mcg_cfg; dest_mcg_cfg.phr_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.mac_cell_group_cfg_present); diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index fedda89204..72cbcab3f0 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -76,44 +76,32 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ // Prepare DU resource allocator response. cell_res_alloc.next_context_update_result = cell_res_alloc.ue_resource_pool[req.ue_index]; for (srb_id_t srb_id : req.srbs_to_setup) { - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = - make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); + cell_res_alloc.next_context_update_result.srbs.emplace(srb_id); + auto& new_srb = cell_res_alloc.next_context_update_result.srbs[srb_id]; + new_srb.srb_id = srb_id; + new_srb.rlc_cfg = make_default_srb_rlc_config(); + new_srb.mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { - auto& rlc_drb = cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); - rlc_drb.drb_id = drb.drb_id; - rlc_drb.lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); - rlc_drb.rlc_cfg = make_default_srb_rlc_config(); - rlc_drb.mac_cfg = make_default_drb_mac_lc_config(); - drb_upper_layer_config& qos_drb = cell_res_alloc.next_context_update_result.drbs.emplace_back(); - qos_drb.drb_id = drb.drb_id; - qos_drb.pdcp_sn_len = drb.pdcp_sn_len; - qos_drb.s_nssai = drb.qos_info.s_nssai; - qos_drb.qos = drb.qos_info.drb_qos; - qos_drb.f1u = {}; + auto& new_drb = cell_res_alloc.next_context_update_result.drbs.emplace(drb.drb_id); + new_drb.drb_id = drb.drb_id; + new_drb.lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); + new_drb.rlc_cfg = make_default_srb_rlc_config(); + new_drb.mac_cfg = make_default_drb_mac_lc_config(); + new_drb.pdcp_sn_len = drb.pdcp_sn_len; + new_drb.s_nssai = drb.qos_info.s_nssai; + new_drb.qos = drb.qos_info.drb_qos; + new_drb.f1u = {}; } for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.emplace_back(); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().drb_id = drb.drb_id; - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().lcid = - uint_to_lcid(3 + (unsigned)drb.drb_id); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); - drb_upper_layer_config& qos_drb = cell_res_alloc.next_context_update_result.drbs.emplace_back(); + auto& mod_drb = cell_res_alloc.next_context_update_result.drbs.emplace(drb.drb_id); const du_ue_resource_config& old_ue_cfg = *ue_mng.find_ue(req.ue_index)->reestablished_cfg_pending; - auto old_drb_it = std::find_if( - old_ue_cfg.drbs.begin(), old_ue_cfg.drbs.end(), [&drb](const auto& d) { return d.drb_id == drb.drb_id; }); - qos_drb = *old_drb_it; + auto& old_drb = old_ue_cfg.drbs[drb.drb_id]; + mod_drb = old_drb; } for (drb_id_t drb_id : req.drbs_to_rem) { - auto it = std::find_if(cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.begin(), - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.end(), - [drb_id](const auto& b) { return b.drb_id == drb_id; }); - if (it != cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.end()) { - cell_res_alloc.next_context_update_result.cell_group.rlc_bearers.erase(it); + if (cell_res_alloc.next_context_update_result.drbs.contains(drb_id)) { + cell_res_alloc.next_context_update_result.drbs.erase(drb_id); } } diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index a18b236eb0..b64a974579 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -37,10 +37,11 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test { auto& next_cfg = this->cell_res_alloc.next_context_update_result; for (srb_id_t srb_id : req.srbs_to_setup) { - next_cfg.cell_group.rlc_bearers.emplace_back(); - next_cfg.cell_group.rlc_bearers.back().lcid = srb_id_to_lcid(srb_id); - next_cfg.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - next_cfg.cell_group.rlc_bearers.back().mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); + next_cfg.srbs.emplace(srb_id); + auto& new_srb = next_cfg.srbs[srb_id]; + new_srb.srb_id = srb_id; + new_srb.rlc_cfg = make_default_srb_rlc_config(); + new_srb.mac_cfg = make_default_srb_mac_lc_config(srb_id_to_lcid(srb_id)); } for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { if (std::find(failed_drbs.begin(), failed_drbs.end(), drb.drb_id) != failed_drbs.end()) { @@ -48,18 +49,16 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test this->cell_res_alloc.next_config_resp.failed_drbs.push_back(drb.drb_id); continue; } - next_cfg.cell_group.rlc_bearers.emplace_back(); - next_cfg.cell_group.rlc_bearers.back().lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); - next_cfg.cell_group.rlc_bearers.back().drb_id = drb.drb_id; - next_cfg.cell_group.rlc_bearers.back().rlc_cfg = make_default_srb_rlc_config(); - next_cfg.cell_group.rlc_bearers.back().mac_cfg = make_default_drb_mac_lc_config(); - auto& next_drb = next_cfg.drbs.emplace_back(); - next_drb.drb_id = drb.drb_id; - next_drb.pdcp_sn_len = drb.pdcp_sn_len; - next_drb.s_nssai = drb.qos_info.s_nssai; - next_drb.qos = drb.qos_info.drb_qos; - next_drb.f1u.t_notify = 100; - next_drb.f1u.warn_on_drop = false; + auto& new_drb = next_cfg.drbs.emplace(drb.drb_id); + new_drb.drb_id = drb.drb_id; + new_drb.lcid = uint_to_lcid(3 + (unsigned)drb.drb_id); + new_drb.rlc_cfg = make_default_srb_rlc_config(); + new_drb.mac_cfg = make_default_drb_mac_lc_config(); + new_drb.pdcp_sn_len = drb.pdcp_sn_len; + new_drb.s_nssai = drb.qos_info.s_nssai; + new_drb.qos = drb.qos_info.drb_qos; + new_drb.f1u.t_notify = 100; + new_drb.f1u.warn_on_drop = false; } proc = launch_async(req, ue_mng, params); @@ -406,13 +405,13 @@ TEST_F(ue_config_tester, when_reestablishment_is_signalled_then_bearers_are_marked_as_reestablishRLC_and_cell_config_are_sent) { // Mark UE as reestablishing. - test_ue->reestablished_cfg_pending = std::make_unique(); - auto& old_bearer = test_ue->reestablished_cfg_pending->cell_group.rlc_bearers.emplace_back(); - old_bearer.lcid = LCID_MIN_DRB; - old_bearer.drb_id = drb_id_t::drb1; - auto& old_drb = test_ue->reestablished_cfg_pending->drbs.emplace_back(); - old_drb.drb_id = drb_id_t::drb1; - old_drb.qos.qos_desc.get_nondyn_5qi().five_qi = uint_to_five_qi(9); + test_ue->reestablished_cfg_pending = std::make_unique(); + du_ue_drb_config& old_bearer = test_ue->reestablished_cfg_pending->drbs.emplace(drb_id_t::drb1); + old_bearer.drb_id = drb_id_t::drb1; + old_bearer.lcid = LCID_MIN_DRB; + old_bearer.rlc_cfg = make_default_srb_rlc_config(); + old_bearer.mac_cfg = make_default_drb_mac_lc_config(); + old_bearer.qos.qos_desc.get_nondyn_5qi().five_qi = uint_to_five_qi(9); // Run procedure to create SRB2 and DRB1. f1ap_ue_context_update_request req = @@ -441,5 +440,6 @@ TEST_F(ue_config_tester, ASSERT_EQ(this->f1ap.last_ue_config->f1c_bearers_to_add[0].srb_id, srb_id_t::srb2); ASSERT_TRUE(res.result); + req.srbs_to_setup.erase(req.srbs_to_setup.begin()); // Remove SRB1 for the checks. ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, false, true)); } diff --git a/tests/unittests/du_manager/serving_cell_config_converter_test.cpp b/tests/unittests/du_manager/serving_cell_config_converter_test.cpp index aeb9bd0bde..bcc6360d37 100644 --- a/tests/unittests/du_manager/serving_cell_config_converter_test.cpp +++ b/tests/unittests/du_manager/serving_cell_config_converter_test.cpp @@ -18,13 +18,12 @@ using namespace srsran; -srs_du::cell_group_config make_initial_cell_group_config() +srs_du::du_ue_resource_config make_initial_du_ue_resource_config() { - srs_du::cell_group_config dest_cell_grp_cfg{}; - dest_cell_grp_cfg.cells.emplace(0, config_helpers::create_default_initial_ue_spcell_cell_config()); - dest_cell_grp_cfg.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); - - return dest_cell_grp_cfg; + srs_du::du_ue_resource_config dest_cfg{}; + dest_cfg.cell_group.cells.emplace(0, config_helpers::create_default_initial_ue_spcell_cell_config()); + dest_cfg.cell_group.mcg_cfg = config_helpers::make_initial_mac_cell_group_config(); + return dest_cfg; } pusch_config make_initial_pusch_config() @@ -115,15 +114,15 @@ srs_config make_initial_srs_config() TEST(serving_cell_config_converter_test, test_default_initial_ue_pdcch_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.init_dl_bwp_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present, dest_sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.has_value()); @@ -143,17 +142,17 @@ TEST(serving_cell_config_converter_test, test_default_initial_ue_pdcch_cfg_conve TEST(serving_cell_config_converter_test, test_ue_pdcch_cfg_release_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg = make_initial_cell_group_config(); - dest_cell_grp_cfg.cells[0].serv_cell_cfg.init_dl_bwp.pdcch_cfg.reset(); + auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg = make_initial_du_ue_resource_config(); + dest_cfg.cell_group.cells[0].serv_cell_cfg.init_dl_bwp.pdcch_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.init_dl_bwp_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present, @@ -164,15 +163,15 @@ TEST(serving_cell_config_converter_test, test_ue_pdcch_cfg_release_conversion) TEST(serving_cell_config_converter_test, test_default_initial_ue_pdsch_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.init_dl_bwp_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg_present, dest_sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg.has_value()); @@ -204,17 +203,17 @@ TEST(serving_cell_config_converter_test, test_default_initial_ue_pdsch_cfg_conve TEST(serving_cell_config_converter_test, test_ue_pdsch_cfg_release_conversion) { - srs_du::cell_group_config dest_cell_grp_cfg = make_initial_cell_group_config(); - auto src_cell_grp_cfg = dest_cell_grp_cfg; - dest_cell_grp_cfg.cells[0].serv_cell_cfg.init_dl_bwp.pdsch_cfg.reset(); + srs_du::du_ue_resource_config dest_cfg = make_initial_du_ue_resource_config(); + auto src_cfg = dest_cfg; + dest_cfg.cell_group.cells[0].serv_cell_cfg.init_dl_bwp.pdsch_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.init_dl_bwp_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg_present, @@ -225,10 +224,10 @@ TEST(serving_cell_config_converter_test, test_ue_pdsch_cfg_release_conversion) TEST(serving_cell_config_converter_test, test_ue_custom_pdsch_cfg_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Add new configuration to be setup. - auto& dest_pdsch_cfg = dest_cell_grp_cfg.cells[0].serv_cell_cfg.init_dl_bwp.pdsch_cfg.value(); + auto& dest_pdsch_cfg = dest_cfg.cell_group.cells[0].serv_cell_cfg.init_dl_bwp.pdsch_cfg.value(); dest_pdsch_cfg.tci_states.push_back(tci_state{ .state_id = static_cast(1), .qcl_type1 = {.ref_sig = {.type = qcl_info::reference_signal::reference_signal_type::csi_rs, @@ -242,10 +241,10 @@ TEST(serving_cell_config_converter_test, test_ue_custom_pdsch_cfg_conversion) dest_pdsch_cfg.pdsch_mapping_type_a_dmrs.value().scrambling_id1 = 20; asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.init_dl_bwp_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg_present, dest_sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg.has_value()); @@ -262,15 +261,15 @@ TEST(serving_cell_config_converter_test, test_ue_custom_pdsch_cfg_conversion) TEST(serving_cell_config_converter_test, test_default_initial_ue_uplink_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_EQ(rrc_sp_cell_cfg_ded.ul_cfg_present, dest_sp_cell_cfg_ded.ul_config.has_value()); @@ -323,15 +322,15 @@ TEST(serving_cell_config_converter_test, test_default_initial_ue_uplink_cfg_conv TEST(serving_cell_config_converter_test, test_default_initial_ue_dl_bwp_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_EQ(rrc_sp_cell_cfg_ded.dl_bwp_to_add_mod_list.size(), dest_sp_cell_cfg_ded.dl_bwps.size()); ASSERT_EQ(rrc_sp_cell_cfg_ded.dl_bwp_to_release_list.size(), 0); @@ -339,15 +338,15 @@ TEST(serving_cell_config_converter_test, test_default_initial_ue_dl_bwp_conversi TEST(serving_cell_config_converter_test, test_default_initial_ue_pucch_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -396,10 +395,10 @@ TEST(serving_cell_config_converter_test, test_default_initial_ue_pucch_cfg_conve TEST(serving_cell_config_converter_test, test_ue_custom_pucch_cfg_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; + auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; // Add new configuration to be setup. Assume PUCCH Config is present in initial cell group config. - auto& dest_pucch_cfg = dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(); + auto& dest_pucch_cfg = dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(); // >> PUCCH Resource Set 1. dest_pucch_cfg.pucch_res_set.emplace_back(); @@ -449,13 +448,13 @@ TEST(serving_cell_config_converter_test, test_ue_custom_pucch_cfg_conversion) dest_pucch_cfg.sr_res_list.erase(dest_pucch_cfg.sr_res_list.begin()); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -495,18 +494,18 @@ TEST(serving_cell_config_converter_test, test_ue_custom_pucch_cfg_conversion) TEST(serving_cell_config_converter_test, test_ue_pucch_cfg_release_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.reset(); + auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -518,17 +517,17 @@ TEST(serving_cell_config_converter_test, test_ue_pucch_cfg_release_conversion) TEST(serving_cell_config_converter_test, test_initial_pusch_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); - dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg = make_initial_pusch_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); + dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg = make_initial_pusch_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -582,11 +581,11 @@ TEST(serving_cell_config_converter_test, test_initial_pusch_cfg_conversion) TEST(serving_cell_config_converter_test, test_ue_custom_pusch_cfg_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - src_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg = make_initial_pusch_config(); + auto src_cfg = make_initial_du_ue_resource_config(); + src_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg = make_initial_pusch_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - auto& dest_pusch_cfg = dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg.value(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + auto& dest_pusch_cfg = dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg.value(); // Add new/remove configurations. dest_pusch_cfg.pusch_mapping_type_a_dmrs.emplace(); dest_pusch_cfg.pusch_mapping_type_a_dmrs.value().trans_precoder_enabled.emplace( @@ -622,13 +621,13 @@ TEST(serving_cell_config_converter_test, test_ue_custom_pusch_cfg_conversion) .k2 = 4, .map_type = srsran::sch_mapping_type::typeB, .symbols = ofdm_symbol_range{2, 12}}); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -672,19 +671,19 @@ TEST(serving_cell_config_converter_test, test_ue_custom_pusch_cfg_conversion) TEST(serving_cell_config_converter_test, test_ue_pusch_cfg_release_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - src_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg = make_initial_pusch_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg.reset(); + auto src_cfg = make_initial_du_ue_resource_config(); + src_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg = make_initial_pusch_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pusch_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -696,17 +695,17 @@ TEST(serving_cell_config_converter_test, test_ue_pusch_cfg_release_conversion) TEST(serving_cell_config_converter_test, test_initial_srs_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); - dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg = make_initial_srs_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); + dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg = make_initial_srs_config(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -728,11 +727,11 @@ TEST(serving_cell_config_converter_test, test_initial_srs_cfg_conversion) TEST(serving_cell_config_converter_test, test_ue_custom_srs_cfg_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - src_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg = make_initial_srs_config(); + auto src_cfg = make_initial_du_ue_resource_config(); + src_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg = make_initial_srs_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - auto& dest_pusch_cfg = dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.value(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + auto& dest_pusch_cfg = dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.value(); // Add new/remove configurations. srs_config::srs_resource_set::semi_persistent_resource_type semi_persistent_resource; semi_persistent_resource.associated_csi_rs = static_cast(1); @@ -773,13 +772,13 @@ TEST(serving_cell_config_converter_test, test_ue_custom_srs_cfg_conversion) dest_pusch_cfg.srs_res.erase(dest_pusch_cfg.srs_res.begin()); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -799,19 +798,19 @@ TEST(serving_cell_config_converter_test, test_ue_custom_srs_cfg_conversion) TEST(serving_cell_config_converter_test, test_ue_srs_cfg_release_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - src_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg = make_initial_srs_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - dest_cell_grp_cfg.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.reset(); + auto src_cfg = make_initial_du_ue_resource_config(); + src_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg = make_initial_srs_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + dest_cfg.cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg_present); ASSERT_TRUE(rrc_sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present); @@ -823,19 +822,19 @@ TEST(serving_cell_config_converter_test, test_ue_srs_cfg_release_conversion) TEST(serving_cell_config_converter_test, test_initial_pdsch_serving_cell_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); - dest_cell_grp_cfg.cells[0].serv_cell_cfg.pdsch_serv_cell_cfg->nof_harq_proc = + dest_cfg.cell_group.cells[0].serv_cell_cfg.pdsch_serv_cell_cfg->nof_harq_proc = pdsch_serving_cell_config::nof_harq_proc_for_pdsch::n8; asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.pdsch_serving_cell_cfg_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.pdsch_serving_cell_cfg_present, dest_sp_cell_cfg_ded.pdsch_serv_cell_cfg.has_value()); @@ -850,10 +849,10 @@ TEST(serving_cell_config_converter_test, test_initial_pdsch_serving_cell_cfg_con TEST(serving_cell_config_converter_test, test_custom_pdsch_serving_cell_cfg_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); + auto src_cfg = make_initial_du_ue_resource_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - auto& dest_pdsch_serving_cell_cfg = dest_cell_grp_cfg.cells[0].serv_cell_cfg.pdsch_serv_cell_cfg.value(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + auto& dest_pdsch_serving_cell_cfg = dest_cfg.cell_group.cells[0].serv_cell_cfg.pdsch_serv_cell_cfg.value(); // Add new/remove configurations. Need not be valid configuration. dest_pdsch_serving_cell_cfg.code_block_group_tx.emplace(pdsch_code_block_group_transmission{ .max_cbg_per_tb = pdsch_code_block_group_transmission::max_code_block_groups_per_tb::n8, @@ -865,13 +864,13 @@ TEST(serving_cell_config_converter_test, test_custom_pdsch_serving_cell_cfg_conv dest_pdsch_serving_cell_cfg.processing_type_2_enabled = false; asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.pdsch_serving_cell_cfg_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.pdsch_serving_cell_cfg_present, dest_sp_cell_cfg_ded.pdsch_serv_cell_cfg.has_value()); @@ -888,18 +887,18 @@ TEST(serving_cell_config_converter_test, test_custom_pdsch_serving_cell_cfg_conv TEST(serving_cell_config_converter_test, test_pdsch_serving_cell_cfg_release_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - dest_cell_grp_cfg.cells[0].serv_cell_cfg.pdsch_serv_cell_cfg.reset(); + auto src_cfg = make_initial_du_ue_resource_config(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + dest_cfg.cell_group.cells[0].serv_cell_cfg.pdsch_serv_cell_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.pdsch_serving_cell_cfg_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.pdsch_serving_cell_cfg_present, @@ -919,20 +918,20 @@ static csi_meas_config make_test_csi_meas_cfg() TEST(serving_cell_config_converter_test, test_initial_csi_meas_cfg_conversion) { - auto dest_cell_grp_cfg = make_initial_cell_group_config(); + auto dest_cfg = make_initial_du_ue_resource_config(); - if (not dest_cell_grp_cfg.cells.begin()->serv_cell_cfg.csi_meas_cfg.has_value()) { - dest_cell_grp_cfg.cells.begin()->serv_cell_cfg.csi_meas_cfg = make_test_csi_meas_cfg(); + if (not dest_cfg.cell_group.cells.begin()->serv_cell_cfg.csi_meas_cfg.has_value()) { + dest_cfg.cell_group.cells.begin()->serv_cell_cfg.csi_meas_cfg = make_test_csi_meas_cfg(); } asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, {}, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.csi_meas_cfg_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.csi_meas_cfg_present, dest_sp_cell_cfg_ded.csi_meas_cfg.has_value()); @@ -970,17 +969,17 @@ TEST(serving_cell_config_converter_test, test_initial_csi_meas_cfg_conversion) TEST(serving_cell_config_converter_test, test_custom_csi_meas_cfg_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); - if (not src_cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg.has_value()) { - src_cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg = make_test_csi_meas_cfg(); + auto src_cfg = make_initial_du_ue_resource_config(); + if (not src_cfg.cell_group.cells[0].serv_cell_cfg.csi_meas_cfg.has_value()) { + src_cfg.cell_group.cells[0].serv_cell_cfg.csi_meas_cfg = make_test_csi_meas_cfg(); } - auto& src_meas = src_cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg.value(); + auto& src_meas = src_cfg.cell_group.cells[0].serv_cell_cfg.csi_meas_cfg.value(); src_meas.nzp_csi_rs_res_list.resize(1); src_meas.nzp_csi_rs_res_set_list.resize(1); src_meas.csi_res_cfg_list.resize(1); - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - auto& dest_csi_meas_cfg = dest_cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg.value(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + auto& dest_csi_meas_cfg = dest_cfg.cell_group.cells[0].serv_cell_cfg.csi_meas_cfg.value(); // Add new/remove configurations. Configuration need not be valid. // Resource 1. dest_csi_meas_cfg.nzp_csi_rs_res_list.push_back(dest_csi_meas_cfg.nzp_csi_rs_res_list[0]); @@ -1142,13 +1141,13 @@ TEST(serving_cell_config_converter_test, test_custom_csi_meas_cfg_conversion) csi_semi_persistent_on_pusch_trigger_state{.associated_report_cfg_info = static_cast(1)}); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.csi_meas_cfg_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.csi_meas_cfg_present, dest_sp_cell_cfg_ded.csi_meas_cfg.has_value()); @@ -1185,23 +1184,23 @@ TEST(serving_cell_config_converter_test, test_custom_csi_meas_cfg_conversion) TEST(serving_cell_config_converter_test, test_csi_meas_cfg_release_conversion) { - auto src_cell_grp_cfg = make_initial_cell_group_config(); + auto src_cfg = make_initial_du_ue_resource_config(); - if (not src_cell_grp_cfg.cells.begin()->serv_cell_cfg.csi_meas_cfg.has_value()) { - src_cell_grp_cfg.cells.begin()->serv_cell_cfg.csi_meas_cfg = make_test_csi_meas_cfg(); + if (not src_cfg.cell_group.cells.begin()->serv_cell_cfg.csi_meas_cfg.has_value()) { + src_cfg.cell_group.cells.begin()->serv_cell_cfg.csi_meas_cfg = make_test_csi_meas_cfg(); } - srs_du::cell_group_config dest_cell_grp_cfg{src_cell_grp_cfg}; - dest_cell_grp_cfg.cells[0].serv_cell_cfg.csi_meas_cfg.reset(); + srs_du::du_ue_resource_config dest_cfg{src_cfg}; + dest_cfg.cell_group.cells[0].serv_cell_cfg.csi_meas_cfg.reset(); asn1::rrc_nr::cell_group_cfg_s rrc_cell_grp_cfg; - srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cell_grp_cfg, dest_cell_grp_cfg); + srs_du::calculate_cell_group_config_diff(rrc_cell_grp_cfg, src_cfg, dest_cfg); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg_present); ASSERT_TRUE(rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded_present); auto& rrc_sp_cell_cfg_ded = rrc_cell_grp_cfg.sp_cell_cfg.sp_cell_cfg_ded; - auto& dest_sp_cell_cfg_ded = dest_cell_grp_cfg.cells[0].serv_cell_cfg; + auto& dest_sp_cell_cfg_ded = dest_cfg.cell_group.cells[0].serv_cell_cfg; ASSERT_TRUE(rrc_sp_cell_cfg_ded.csi_meas_cfg_present); ASSERT_EQ(rrc_sp_cell_cfg_ded.csi_meas_cfg_present, not dest_sp_cell_cfg_ded.csi_meas_cfg.has_value()); From c374078470c617492322e9f787ee67a60a36137e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 12 Aug 2024 10:39:28 +0200 Subject: [PATCH 222/407] du manager: update ue_configuration unit tests for reestablishment case --- .../converters/asn1_rrc_config_helpers.cpp | 309 ++++++++++-------- .../converters/rlc_config_helpers.h | 13 - .../du_manager_procedure_test_helpers.cpp | 11 +- .../procedures/ue_configuration_test.cpp | 127 ++++--- 4 files changed, 250 insertions(+), 210 deletions(-) diff --git a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp index 4c934ecf90..8596b5aeb7 100644 --- a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp +++ b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp @@ -17,131 +17,29 @@ using namespace srsran; using namespace srsran::srs_du; using namespace asn1::rrc_nr; -static asn1::rrc_nr::subcarrier_spacing_e get_asn1_scs(subcarrier_spacing scs) +namespace { + +asn1::rrc_nr::subcarrier_spacing_e get_asn1_scs(subcarrier_spacing scs) { return asn1::rrc_nr::subcarrier_spacing_e{static_cast(scs)}; } -asn1::rrc_nr::coreset_s srsran::srs_du::make_asn1_rrc_coreset(const coreset_configuration& cfg) -{ - coreset_s cs; - cs.coreset_id = cfg.id; - cs.freq_domain_res.from_number(cfg.freq_domain_resources().to_uint64()); - cs.dur = cfg.duration; - if (cfg.interleaved.has_value()) { - auto& interv = cs.cce_reg_map_type.set_interleaved(); - asn1::number_to_enum(interv.reg_bundle_size, cfg.interleaved->reg_bundle_sz); - asn1::number_to_enum(interv.interleaver_size, cfg.interleaved->interleaver_sz); - interv.shift_idx_present = true; - interv.shift_idx = cfg.interleaved->shift_index; - } else { - cs.cce_reg_map_type.set_non_interleaved(); - } - cs.precoder_granularity.value = - cfg.precoder_granurality == coreset_configuration::precoder_granularity_type::same_as_reg_bundle - ? coreset_s::precoder_granularity_opts::same_as_reg_bundle - : coreset_s::precoder_granularity_opts::all_contiguous_rbs; - cs.pdcch_dmrs_scrambling_id_present = cfg.pdcch_dmrs_scrambling_id.has_value(); - if (cs.pdcch_dmrs_scrambling_id_present) { - cs.pdcch_dmrs_scrambling_id = *cfg.pdcch_dmrs_scrambling_id; - } - return cs; -} +/// Helper type used to generate ASN.1 diff +struct rlc_bearer_config { + lcid_t lcid; + std::optional drb_id; + const rlc_config* rlc_cfg; + const mac_lc_config* mac_cfg; -asn1::rrc_nr::search_space_s srsran::srs_du::make_asn1_rrc_search_space(const search_space_configuration& cfg) -{ - search_space_s ss; - ss.search_space_id = cfg.get_id(); - ss.coreset_id_present = true; - ss.coreset_id = cfg.get_coreset_id(); - ss.monitoring_slot_periodicity_and_offset_present = true; - search_space_s::monitoring_slot_periodicity_and_offset_c_::types period; - bool success = asn1::number_to_enum(period, cfg.get_monitoring_slot_periodicity()); - srsran_assert(success, "Invalid slot period"); - ss.monitoring_slot_periodicity_and_offset.set(period); - switch (ss.monitoring_slot_periodicity_and_offset.type().value) { - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl1: - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl2: - ss.monitoring_slot_periodicity_and_offset.sl2() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl4: - ss.monitoring_slot_periodicity_and_offset.sl4() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl5: - ss.monitoring_slot_periodicity_and_offset.sl5() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl8: - ss.monitoring_slot_periodicity_and_offset.sl8() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl10: - ss.monitoring_slot_periodicity_and_offset.sl10() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl16: - ss.monitoring_slot_periodicity_and_offset.sl16() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl20: - ss.monitoring_slot_periodicity_and_offset.sl20() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl40: - ss.monitoring_slot_periodicity_and_offset.sl40() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl80: - ss.monitoring_slot_periodicity_and_offset.sl80() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl160: - ss.monitoring_slot_periodicity_and_offset.sl160() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl320: - ss.monitoring_slot_periodicity_and_offset.sl320() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl640: - ss.monitoring_slot_periodicity_and_offset.sl640() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl1280: - ss.monitoring_slot_periodicity_and_offset.sl1280() = cfg.get_monitoring_slot_offset(); - break; - case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl2560: - ss.monitoring_slot_periodicity_and_offset.sl2560() = cfg.get_monitoring_slot_offset(); - break; - default: - srsran_assertion_failure("Invalid PDCCH slot offset={}", cfg.get_monitoring_slot_offset()); + bool operator==(const rlc_bearer_config& rhs) const + { + // TODO: Remaining fields + return lcid == rhs.lcid and drb_id == rhs.drb_id and rlc_cfg->mode == rhs.rlc_cfg->mode and + *mac_cfg == *rhs.mac_cfg; } - if (cfg.get_duration() != 1) { - ss.dur_present = true; - ss.dur = cfg.get_duration(); - } - if (cfg.get_monitoring_symbols_within_slot().any()) { - ss.monitoring_symbols_within_slot_present = true; - ss.monitoring_symbols_within_slot.from_number(cfg.get_monitoring_symbols_within_slot().to_uint64()); - } - ss.nrof_candidates_present = true; - asn1::number_to_enum(ss.nrof_candidates.aggregation_level1, cfg.get_nof_candidates()[0]); - asn1::number_to_enum(ss.nrof_candidates.aggregation_level2, cfg.get_nof_candidates()[1]); - asn1::number_to_enum(ss.nrof_candidates.aggregation_level4, cfg.get_nof_candidates()[2]); - asn1::number_to_enum(ss.nrof_candidates.aggregation_level8, cfg.get_nof_candidates()[3]); - asn1::number_to_enum(ss.nrof_candidates.aggregation_level16, cfg.get_nof_candidates()[4]); - ss.search_space_type_present = true; - if (cfg.is_common_search_space()) { - const auto dci_fmt = std::get(cfg.get_monitored_dci_formats()); - ss.search_space_type.set_common(); - ss.search_space_type.common().dci_format0_0_and_format1_0_present = dci_fmt.f0_0_and_f1_0; - ss.search_space_type.common().dci_format2_0_present = dci_fmt.f2_0; - ss.search_space_type.common().dci_format2_1_present = dci_fmt.f2_1; - ss.search_space_type.common().dci_format2_2_present = dci_fmt.f2_2; - ss.search_space_type.common().dci_format2_3_present = dci_fmt.f2_3; - } else { - const auto dci_fmt = std::get(cfg.get_monitored_dci_formats()); - ss.search_space_type.set_ue_specific(); - ss.search_space_type.ue_specific().dci_formats.value = - dci_fmt == srsran::search_space_configuration::ue_specific_dci_format::f0_0_and_f1_0 - ? search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_opts::formats0_neg0_and_neg1_neg0 - : search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_opts::formats0_neg1_and_neg1_neg1; - } - return ss; -} +}; -static rlc_bearer_cfg_s make_asn1_rrc_rlc_bearer(const rlc_bearer_config& cfg) +rlc_bearer_cfg_s make_asn1_rrc_rlc_bearer(const rlc_bearer_config& cfg) { rlc_bearer_cfg_s out; @@ -155,39 +53,39 @@ static rlc_bearer_cfg_s make_asn1_rrc_rlc_bearer(const rlc_bearer_config& cfg) } out.rlc_cfg_present = true; - switch (cfg.rlc_cfg.mode) { + switch (cfg.rlc_cfg->mode) { case rlc_mode::am: { rlc_cfg_c::am_s_& am = out.rlc_cfg.set_am(); am.ul_am_rlc.sn_field_len_present = true; - asn1::number_to_enum(am.ul_am_rlc.sn_field_len, to_number(cfg.rlc_cfg.am.tx.sn_field_length)); - asn1::number_to_enum(am.ul_am_rlc.t_poll_retx, cfg.rlc_cfg.am.tx.t_poll_retx); - asn1::number_to_enum(am.ul_am_rlc.poll_pdu, cfg.rlc_cfg.am.tx.poll_pdu); - asn1::number_to_enum(am.ul_am_rlc.poll_byte, cfg.rlc_cfg.am.tx.poll_byte); - asn1::number_to_enum(am.ul_am_rlc.max_retx_thres, cfg.rlc_cfg.am.tx.max_retx_thresh); + asn1::number_to_enum(am.ul_am_rlc.sn_field_len, to_number(cfg.rlc_cfg->am.tx.sn_field_length)); + asn1::number_to_enum(am.ul_am_rlc.t_poll_retx, cfg.rlc_cfg->am.tx.t_poll_retx); + asn1::number_to_enum(am.ul_am_rlc.poll_pdu, cfg.rlc_cfg->am.tx.poll_pdu); + asn1::number_to_enum(am.ul_am_rlc.poll_byte, cfg.rlc_cfg->am.tx.poll_byte); + asn1::number_to_enum(am.ul_am_rlc.max_retx_thres, cfg.rlc_cfg->am.tx.max_retx_thresh); am.dl_am_rlc.sn_field_len_present = true; - asn1::number_to_enum(am.dl_am_rlc.sn_field_len, to_number(cfg.rlc_cfg.am.rx.sn_field_length)); - asn1::number_to_enum(am.dl_am_rlc.t_reassembly, cfg.rlc_cfg.am.rx.t_reassembly); - asn1::number_to_enum(am.dl_am_rlc.t_status_prohibit, cfg.rlc_cfg.am.rx.t_status_prohibit); + asn1::number_to_enum(am.dl_am_rlc.sn_field_len, to_number(cfg.rlc_cfg->am.rx.sn_field_length)); + asn1::number_to_enum(am.dl_am_rlc.t_reassembly, cfg.rlc_cfg->am.rx.t_reassembly); + asn1::number_to_enum(am.dl_am_rlc.t_status_prohibit, cfg.rlc_cfg->am.rx.t_status_prohibit); } break; case rlc_mode::um_bidir: { auto& um = out.rlc_cfg.set_um_bi_dir(); um.ul_um_rlc.sn_field_len_present = true; - asn1::number_to_enum(um.ul_um_rlc.sn_field_len, to_number(cfg.rlc_cfg.um.tx.sn_field_length)); + asn1::number_to_enum(um.ul_um_rlc.sn_field_len, to_number(cfg.rlc_cfg->um.tx.sn_field_length)); um.dl_um_rlc.sn_field_len_present = true; - asn1::number_to_enum(um.dl_um_rlc.sn_field_len, to_number(cfg.rlc_cfg.um.rx.sn_field_length)); - asn1::number_to_enum(um.dl_um_rlc.t_reassembly, cfg.rlc_cfg.um.rx.t_reassembly); + asn1::number_to_enum(um.dl_um_rlc.sn_field_len, to_number(cfg.rlc_cfg->um.rx.sn_field_length)); + asn1::number_to_enum(um.dl_um_rlc.t_reassembly, cfg.rlc_cfg->um.rx.t_reassembly); } break; case rlc_mode::um_unidir_dl: { auto& um = out.rlc_cfg.set_um_uni_dir_dl(); um.dl_um_rlc.sn_field_len_present = true; - asn1::number_to_enum(um.dl_um_rlc.sn_field_len, to_number(cfg.rlc_cfg.um.rx.sn_field_length)); + asn1::number_to_enum(um.dl_um_rlc.sn_field_len, to_number(cfg.rlc_cfg->um.rx.sn_field_length)); asn1::number_to_enum(um.dl_um_rlc.t_reassembly, um.dl_um_rlc.t_reassembly); } break; case rlc_mode::um_unidir_ul: { auto& um = out.rlc_cfg.set_um_uni_dir_ul(); um.ul_um_rlc.sn_field_len_present = true; - asn1::number_to_enum(um.ul_um_rlc.sn_field_len, to_number(cfg.rlc_cfg.um.tx.sn_field_length)); + asn1::number_to_enum(um.ul_um_rlc.sn_field_len, to_number(cfg.rlc_cfg->um.tx.sn_field_length)); } break; default: report_fatal_error("Invalid RLC bearer configuration type"); @@ -195,8 +93,8 @@ static rlc_bearer_cfg_s make_asn1_rrc_rlc_bearer(const rlc_bearer_config& cfg) out.mac_lc_ch_cfg_present = true; out.mac_lc_ch_cfg.ul_specific_params_present = true; - out.mac_lc_ch_cfg.ul_specific_params.prio = cfg.mac_cfg.priority; - switch (cfg.mac_cfg.pbr) { + out.mac_lc_ch_cfg.ul_specific_params.prio = cfg.mac_cfg->priority; + switch (cfg.mac_cfg->pbr) { case prioritized_bit_rate::kBps0: out.mac_lc_ch_cfg.ul_specific_params.prioritised_bit_rate.value = lc_ch_cfg_s::ul_specific_params_s_::prioritised_bit_rate_opts::kbps0; @@ -262,9 +160,9 @@ static rlc_bearer_cfg_s make_asn1_rrc_rlc_bearer(const rlc_bearer_config& cfg) lc_ch_cfg_s::ul_specific_params_s_::prioritised_bit_rate_opts::infinity; break; default: - report_fatal_error("Invalid Prioritised Bit Rate {}", cfg.mac_cfg.pbr); + report_fatal_error("Invalid Prioritised Bit Rate {}", cfg.mac_cfg->pbr); } - switch (cfg.mac_cfg.bsd) { + switch (cfg.mac_cfg->bsd) { case bucket_size_duration::ms5: out.mac_lc_ch_cfg.ul_specific_params.bucket_size_dur.value = lc_ch_cfg_s::ul_specific_params_s_::bucket_size_dur_opts::ms5; @@ -302,18 +200,139 @@ static rlc_bearer_cfg_s make_asn1_rrc_rlc_bearer(const rlc_bearer_config& cfg) lc_ch_cfg_s::ul_specific_params_s_::bucket_size_dur_opts::ms1000; break; default: - report_fatal_error("Invalid Bucket size duration {}", cfg.mac_cfg.bsd); + report_fatal_error("Invalid Bucket size duration {}", cfg.mac_cfg->bsd); } out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group_present = true; - out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group = cfg.mac_cfg.lcg_id; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group = cfg.mac_cfg->lcg_id; out.mac_lc_ch_cfg.ul_specific_params.sched_request_id_present = true; - out.mac_lc_ch_cfg.ul_specific_params.sched_request_id = cfg.mac_cfg.sr_id; - out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_mask = cfg.mac_cfg.lc_sr_mask; - out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_delay_timer_applied = cfg.mac_cfg.lc_sr_delay_applied; + out.mac_lc_ch_cfg.ul_specific_params.sched_request_id = cfg.mac_cfg->sr_id; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_mask = cfg.mac_cfg->lc_sr_mask; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_delay_timer_applied = cfg.mac_cfg->lc_sr_delay_applied; return out; } +} // namespace + +asn1::rrc_nr::coreset_s srsran::srs_du::make_asn1_rrc_coreset(const coreset_configuration& cfg) +{ + coreset_s cs; + cs.coreset_id = cfg.id; + cs.freq_domain_res.from_number(cfg.freq_domain_resources().to_uint64()); + cs.dur = cfg.duration; + if (cfg.interleaved.has_value()) { + auto& interv = cs.cce_reg_map_type.set_interleaved(); + asn1::number_to_enum(interv.reg_bundle_size, cfg.interleaved->reg_bundle_sz); + asn1::number_to_enum(interv.interleaver_size, cfg.interleaved->interleaver_sz); + interv.shift_idx_present = true; + interv.shift_idx = cfg.interleaved->shift_index; + } else { + cs.cce_reg_map_type.set_non_interleaved(); + } + cs.precoder_granularity.value = + cfg.precoder_granurality == coreset_configuration::precoder_granularity_type::same_as_reg_bundle + ? coreset_s::precoder_granularity_opts::same_as_reg_bundle + : coreset_s::precoder_granularity_opts::all_contiguous_rbs; + cs.pdcch_dmrs_scrambling_id_present = cfg.pdcch_dmrs_scrambling_id.has_value(); + if (cs.pdcch_dmrs_scrambling_id_present) { + cs.pdcch_dmrs_scrambling_id = *cfg.pdcch_dmrs_scrambling_id; + } + return cs; +} + +asn1::rrc_nr::search_space_s srsran::srs_du::make_asn1_rrc_search_space(const search_space_configuration& cfg) +{ + search_space_s ss; + ss.search_space_id = cfg.get_id(); + ss.coreset_id_present = true; + ss.coreset_id = cfg.get_coreset_id(); + ss.monitoring_slot_periodicity_and_offset_present = true; + search_space_s::monitoring_slot_periodicity_and_offset_c_::types period; + bool success = asn1::number_to_enum(period, cfg.get_monitoring_slot_periodicity()); + srsran_assert(success, "Invalid slot period"); + ss.monitoring_slot_periodicity_and_offset.set(period); + switch (ss.monitoring_slot_periodicity_and_offset.type().value) { + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl1: + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl2: + ss.monitoring_slot_periodicity_and_offset.sl2() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl4: + ss.monitoring_slot_periodicity_and_offset.sl4() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl5: + ss.monitoring_slot_periodicity_and_offset.sl5() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl8: + ss.monitoring_slot_periodicity_and_offset.sl8() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl10: + ss.monitoring_slot_periodicity_and_offset.sl10() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl16: + ss.monitoring_slot_periodicity_and_offset.sl16() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl20: + ss.monitoring_slot_periodicity_and_offset.sl20() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl40: + ss.monitoring_slot_periodicity_and_offset.sl40() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl80: + ss.monitoring_slot_periodicity_and_offset.sl80() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl160: + ss.monitoring_slot_periodicity_and_offset.sl160() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl320: + ss.monitoring_slot_periodicity_and_offset.sl320() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl640: + ss.monitoring_slot_periodicity_and_offset.sl640() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl1280: + ss.monitoring_slot_periodicity_and_offset.sl1280() = cfg.get_monitoring_slot_offset(); + break; + case search_space_s::monitoring_slot_periodicity_and_offset_c_::types_opts::sl2560: + ss.monitoring_slot_periodicity_and_offset.sl2560() = cfg.get_monitoring_slot_offset(); + break; + default: + srsran_assertion_failure("Invalid PDCCH slot offset={}", cfg.get_monitoring_slot_offset()); + } + if (cfg.get_duration() != 1) { + ss.dur_present = true; + ss.dur = cfg.get_duration(); + } + if (cfg.get_monitoring_symbols_within_slot().any()) { + ss.monitoring_symbols_within_slot_present = true; + ss.monitoring_symbols_within_slot.from_number(cfg.get_monitoring_symbols_within_slot().to_uint64()); + } + ss.nrof_candidates_present = true; + asn1::number_to_enum(ss.nrof_candidates.aggregation_level1, cfg.get_nof_candidates()[0]); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level2, cfg.get_nof_candidates()[1]); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level4, cfg.get_nof_candidates()[2]); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level8, cfg.get_nof_candidates()[3]); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level16, cfg.get_nof_candidates()[4]); + ss.search_space_type_present = true; + if (cfg.is_common_search_space()) { + const auto dci_fmt = std::get(cfg.get_monitored_dci_formats()); + ss.search_space_type.set_common(); + ss.search_space_type.common().dci_format0_0_and_format1_0_present = dci_fmt.f0_0_and_f1_0; + ss.search_space_type.common().dci_format2_0_present = dci_fmt.f2_0; + ss.search_space_type.common().dci_format2_1_present = dci_fmt.f2_1; + ss.search_space_type.common().dci_format2_2_present = dci_fmt.f2_2; + ss.search_space_type.common().dci_format2_3_present = dci_fmt.f2_3; + } else { + const auto dci_fmt = std::get(cfg.get_monitored_dci_formats()); + ss.search_space_type.set_ue_specific(); + ss.search_space_type.ue_specific().dci_formats.value = + dci_fmt == srsran::search_space_configuration::ue_specific_dci_format::f0_0_and_f1_0 + ? search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_opts::formats0_neg0_and_neg1_neg0 + : search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_opts::formats0_neg1_and_neg1_neg1; + } + return ss; +} + asn1::dyn_array srsran::srs_du::make_asn1_rrc_scs_specific_carrier_list(span scs_carrier_list) { @@ -3005,15 +3024,15 @@ static static_vector fill_rlc_bearers(const } rlc_bearer_config& bearer = list.emplace_back(); bearer.lcid = srb_id_to_lcid(srb.srb_id); - bearer.rlc_cfg = srb.rlc_cfg; - bearer.mac_cfg = srb.mac_cfg; + bearer.rlc_cfg = &srb.rlc_cfg; + bearer.mac_cfg = &srb.mac_cfg; } for (const auto& drb : res.drbs) { rlc_bearer_config& bearer = list.emplace_back(); bearer.lcid = drb.lcid; bearer.drb_id = drb.drb_id; - bearer.rlc_cfg = drb.rlc_cfg; - bearer.mac_cfg = drb.mac_cfg; + bearer.rlc_cfg = &drb.rlc_cfg; + bearer.mac_cfg = &drb.mac_cfg; } return list; } diff --git a/lib/du_manager/converters/rlc_config_helpers.h b/lib/du_manager/converters/rlc_config_helpers.h index 2cc85d275e..831e382950 100644 --- a/lib/du_manager/converters/rlc_config_helpers.h +++ b/lib/du_manager/converters/rlc_config_helpers.h @@ -22,19 +22,6 @@ namespace srsran { namespace srs_du { -struct rlc_bearer_config { - lcid_t lcid; - std::optional drb_id; - rlc_config rlc_cfg; - mac_lc_config mac_cfg; - - bool operator==(const rlc_bearer_config& rhs) const - { - // TODO: Remaining fields - return lcid == rhs.lcid and drb_id == rhs.drb_id and rlc_cfg.mode == rhs.rlc_cfg.mode and mac_cfg == rhs.mac_cfg; - } -}; - /// \brief Create configuration for RLC SRB entity. rlc_entity_creation_message make_rlc_entity_creation_message(gnb_du_id_t du_id, du_ue_index_t ue_index, diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp index 72cbcab3f0..4a7bb9d2b7 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.cpp @@ -75,6 +75,11 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ // Prepare DU resource allocator response. cell_res_alloc.next_context_update_result = cell_res_alloc.ue_resource_pool[req.ue_index]; + auto& u = *ue_mng.find_ue(req.ue_index); + if (u.reestablished_cfg_pending != nullptr) { + cell_res_alloc.next_context_update_result.srbs = u.reestablished_cfg_pending->srbs; + cell_res_alloc.next_context_update_result.drbs = u.reestablished_cfg_pending->drbs; + } for (srb_id_t srb_id : req.srbs_to_setup) { cell_res_alloc.next_context_update_result.srbs.emplace(srb_id); auto& new_srb = cell_res_alloc.next_context_update_result.srbs[srb_id]; @@ -94,10 +99,8 @@ f1ap_ue_context_update_response du_manager_proc_tester::configure_ue(const f1ap_ new_drb.f1u = {}; } for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { - auto& mod_drb = cell_res_alloc.next_context_update_result.drbs.emplace(drb.drb_id); - const du_ue_resource_config& old_ue_cfg = *ue_mng.find_ue(req.ue_index)->reestablished_cfg_pending; - auto& old_drb = old_ue_cfg.drbs[drb.drb_id]; - mod_drb = old_drb; + srsran_assert(cell_res_alloc.next_context_update_result.drbs.contains(drb.drb_id), + "reestablishment context should have created DRB"); } for (drb_id_t drb_id : req.drbs_to_rem) { if (cell_res_alloc.next_context_update_result.drbs.contains(drb_id)) { diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index b64a974579..9a2c757a7e 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -74,8 +74,8 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test void check_du_to_cu_rrc_container(const f1ap_ue_context_update_request& req, const byte_buffer& container, - bool reestablishment, - bool verbose) + const du_ue_resource_config* reest_context = nullptr, + bool verbose = false) { ASSERT_FALSE(container.empty()); asn1::rrc_nr::cell_group_cfg_s cell_group; @@ -89,28 +89,68 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test } } - ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), - req.srbs_to_setup.size() + req.drbs_to_setup.size() + req.drbs_to_mod.size()); - for (srb_id_t srb_id : req.srbs_to_setup) { - auto srb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), - cell_group.rlc_bearer_to_add_mod_list.end(), - [srb_id](const auto& b) { - return b.served_radio_bearer.type().value == - asn1::rrc_nr::rlc_bearer_cfg_s::served_radio_bearer_c_::types::srb_id and - b.served_radio_bearer.srb_id() == srb_id_to_uint(srb_id); - }); - ASSERT_NE(srb_it, cell_group.rlc_bearer_to_add_mod_list.end()); - ASSERT_EQ(srb_it->lc_ch_id, srb_id_to_lcid(srb_id)); - if (reestablishment) { - ASSERT_FALSE(srb_it->mac_lc_ch_cfg_present); - ASSERT_FALSE(srb_it->rlc_cfg_present); - ASSERT_TRUE(srb_it->reestablish_rlc_present); - } else { + if (reest_context == nullptr) { + ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), + req.srbs_to_setup.size() + req.drbs_to_setup.size() + req.drbs_to_mod.size()); + + for (srb_id_t srb_id : req.srbs_to_setup) { + auto srb_it = + std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), + cell_group.rlc_bearer_to_add_mod_list.end(), + [srb_id](const auto& b) { + return b.served_radio_bearer.type().value == + asn1::rrc_nr::rlc_bearer_cfg_s::served_radio_bearer_c_::types::srb_id and + b.served_radio_bearer.srb_id() == srb_id_to_uint(srb_id); + }); + ASSERT_NE(srb_it, cell_group.rlc_bearer_to_add_mod_list.end()); + ASSERT_EQ(srb_it->lc_ch_id, srb_id_to_lcid(srb_id)); ASSERT_TRUE(srb_it->mac_lc_ch_cfg_present); ASSERT_TRUE(srb_it->rlc_cfg_present); ASSERT_FALSE(srb_it->reestablish_rlc_present); } + for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { + auto drb_it = + std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), + cell_group.rlc_bearer_to_add_mod_list.end(), + [&drb](const auto& b) { + return b.served_radio_bearer.type().value == + asn1::rrc_nr::rlc_bearer_cfg_s::served_radio_bearer_c_::types::drb_id and + b.served_radio_bearer.drb_id() == drb_id_to_uint(drb.drb_id); + }); + ASSERT_NE(drb_it, cell_group.rlc_bearer_to_add_mod_list.end()); + ASSERT_FALSE(is_srb(uint_to_lcid(drb_it->lc_ch_id))); + ASSERT_TRUE(drb_it->mac_lc_ch_cfg_present); + ASSERT_TRUE(drb_it->rlc_cfg_present); + ASSERT_FALSE(drb_it->reestablish_rlc_present); + } + } else { + ASSERT_TRUE(req.srbs_to_setup.empty()); + ASSERT_TRUE(req.drbs_to_setup.empty()); + unsigned nof_srb_reest = reest_context->srbs.size() - 1; // SRB1 has already been reestablished. + ASSERT_EQ(cell_group.rlc_bearer_to_add_mod_list.size(), nof_srb_reest + req.drbs_to_mod.size()); + + // Check SRBs/DRBs to reestablish in the UE + for (const auto& bearer : cell_group.rlc_bearer_to_add_mod_list) { + ASSERT_FALSE(bearer.mac_lc_ch_cfg_present); + ASSERT_FALSE(bearer.rlc_cfg_present); + ASSERT_TRUE(bearer.reestablish_rlc_present); + if (bearer.served_radio_bearer.type().value == + asn1::rrc_nr::rlc_bearer_cfg_s::served_radio_bearer_c_::types::srb_id) { + // SRB case + srb_id_t srb_id = to_srb_id(uint_to_lcid(bearer.served_radio_bearer.srb_id())); + ASSERT_NE(srb_id, srb_id_t::srb1); + ASSERT_TRUE(reest_context->srbs.contains(srb_id)); + } else { + // DRB case + drb_id_t drb_id = uint_to_drb_id(bearer.served_radio_bearer.drb_id()); + ASSERT_TRUE(reest_context->drbs.contains(drb_id)); + auto it = std::find_if( + req.drbs_to_mod.begin(), req.drbs_to_mod.end(), [drb_id](const auto& d) { return d.drb_id == drb_id; }); + ASSERT_NE(it, req.drbs_to_mod.end()); + } + } } + for (const f1ap_drb_to_setup& drb : req.drbs_to_setup) { auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), cell_group.rlc_bearer_to_add_mod_list.end(), @@ -125,26 +165,6 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test ASSERT_TRUE(drb_it->rlc_cfg_present); ASSERT_FALSE(drb_it->reestablish_rlc_present); } - for (const f1ap_drb_to_modify& drb : req.drbs_to_mod) { - auto drb_it = std::find_if(cell_group.rlc_bearer_to_add_mod_list.begin(), - cell_group.rlc_bearer_to_add_mod_list.end(), - [&drb](const auto& b) { - return b.served_radio_bearer.type().value == - asn1::rrc_nr::rlc_bearer_cfg_s::served_radio_bearer_c_::types::drb_id and - b.served_radio_bearer.drb_id() == drb_id_to_uint(drb.drb_id); - }); - ASSERT_NE(drb_it, cell_group.rlc_bearer_to_add_mod_list.end()); - ASSERT_FALSE(is_srb(uint_to_lcid(drb_it->lc_ch_id))); - if (reestablishment) { - ASSERT_FALSE(drb_it->mac_lc_ch_cfg_present); - ASSERT_FALSE(drb_it->rlc_cfg_present); - ASSERT_TRUE(drb_it->reestablish_rlc_present); - } else { - ASSERT_TRUE(drb_it->mac_lc_ch_cfg_present); - ASSERT_TRUE(drb_it->rlc_cfg_present); - ASSERT_FALSE(drb_it->reestablish_rlc_present); - } - } ASSERT_EQ(cell_group.rlc_bearer_to_release_list.size(), req.drbs_to_rem.size()); for (unsigned i = 0; i != req.drbs_to_rem.size(); ++i) { @@ -152,7 +172,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test ASSERT_EQ(lcid, cell_group.rlc_bearer_to_release_list[i]); } - if (reestablishment) { + if (reest_context != nullptr) { ASSERT_TRUE(cell_group.sp_cell_cfg_present); ASSERT_TRUE(cell_group.sp_cell_cfg.sp_cell_cfg_ded_present); ASSERT_TRUE(cell_group.sp_cell_cfg.sp_cell_cfg_ded.ul_cfg_present); @@ -209,7 +229,7 @@ TEST_F(ue_config_tester, when_du_manager_completes_ue_configuration_procedure_th ASSERT_TRUE(proc.ready()); f1ap_ue_context_update_response resp = proc.get(); ASSERT_TRUE(resp.result); - ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, resp.du_to_cu_rrc_container, false, true)); + ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, resp.du_to_cu_rrc_container, nullptr, true)); } TEST_F(ue_config_tester, when_du_manager_finishes_processing_ue_config_request_then_mac_rlc_f1c_bearers_are_connected) @@ -380,7 +400,7 @@ TEST_F(ue_config_tester, when_drbs_are_released_then_they_are_added_in_rrc_conta res = this->configure_ue(req); ASSERT_TRUE(res.result); - ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, false, true)); + ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, nullptr, true)); } TEST_F(ue_config_tester, when_drb_to_be_released_does_not_exist_then_request_is_ignored) @@ -398,27 +418,38 @@ TEST_F(ue_config_tester, when_drb_to_be_released_does_not_exist_then_request_is_ ASSERT_TRUE(res.result); auto req_no_drb_release = req; req_no_drb_release.drbs_to_rem.clear(); - ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req_no_drb_release, res.du_to_cu_rrc_container, false, true)); + ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req_no_drb_release, res.du_to_cu_rrc_container, nullptr, true)); } TEST_F(ue_config_tester, when_reestablishment_is_signalled_then_bearers_are_marked_as_reestablishRLC_and_cell_config_are_sent) { // Mark UE as reestablishing. - test_ue->reestablished_cfg_pending = std::make_unique(); + test_ue->reestablished_cfg_pending = std::make_unique(); + test_ue->reestablished_cfg_pending->srbs.emplace(srb_id_t::srb1); + du_ue_srb_config& old_srb1 = test_ue->reestablished_cfg_pending->srbs[srb_id_t::srb1]; + old_srb1.srb_id = srb_id_t::srb1; + old_srb1.rlc_cfg = make_default_srb_rlc_config(); + old_srb1.mac_cfg = make_default_drb_mac_lc_config(); + test_ue->reestablished_cfg_pending->srbs.emplace(srb_id_t::srb2); + du_ue_srb_config& old_srb2 = test_ue->reestablished_cfg_pending->srbs[srb_id_t::srb2]; + old_srb2.srb_id = srb_id_t::srb2; + old_srb2.rlc_cfg = make_default_srb_rlc_config(); + old_srb2.mac_cfg = make_default_drb_mac_lc_config(); du_ue_drb_config& old_bearer = test_ue->reestablished_cfg_pending->drbs.emplace(drb_id_t::drb1); old_bearer.drb_id = drb_id_t::drb1; old_bearer.lcid = LCID_MIN_DRB; old_bearer.rlc_cfg = make_default_srb_rlc_config(); old_bearer.mac_cfg = make_default_drb_mac_lc_config(); old_bearer.qos.qos_desc.get_nondyn_5qi().five_qi = uint_to_five_qi(9); + du_ue_resource_config reest_cfg_copy = *test_ue->reestablished_cfg_pending; - // Run procedure to create SRB2 and DRB1. + // Run procedure to modify DRB1. f1ap_ue_context_update_request req = - create_f1ap_ue_context_update_request(test_ue->ue_index, {srb_id_t::srb2}, {}, {drb_id_t::drb1}); + create_f1ap_ue_context_update_request(test_ue->ue_index, {}, {}, {drb_id_t::drb1}); f1ap_ue_context_update_response res = this->configure_ue(req); ASSERT_TRUE(res.result); - ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, true, true)); + ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, &reest_cfg_copy, true)); } TEST_F(ue_config_tester, @@ -441,5 +472,5 @@ TEST_F(ue_config_tester, ASSERT_TRUE(res.result); req.srbs_to_setup.erase(req.srbs_to_setup.begin()); // Remove SRB1 for the checks. - ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, false, true)); + ASSERT_NO_FATAL_FAILURE(check_du_to_cu_rrc_container(req, res.du_to_cu_rrc_container, nullptr, true)); } From 37c73a034a0336bb1ff6b03c03d509cff5ba1abf Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 12 Aug 2024 13:20:24 +0200 Subject: [PATCH 223/407] f1ap: refactor f1ap asn1 converters --- lib/f1ap/common/asn1_helpers.cpp | 538 +++++++++++++++++- lib/f1ap/common/asn1_helpers.h | 53 +- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 419 -------------- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 398 ------------- .../ue_context_modification_procedure.cpp | 374 +++++++++++- .../procedures/ue_context_setup_procedure.cpp | 39 +- lib/f1ap/du/procedures/CMakeLists.txt | 1 - .../procedures/f1ap_du_ue_context_common.cpp | 104 ---- .../du/procedures/f1ap_du_ue_context_common.h | 42 -- ...p_du_ue_context_modification_procedure.cpp | 15 +- .../f1ap_du_ue_context_setup_procedure.cpp | 6 +- tests/unittests/asn1/CMakeLists.txt | 2 +- tests/unittests/cu_cp/cu_cp_test_messages.cpp | 13 - tests/unittests/cu_cp/cu_cp_test_messages.h | 4 - tests/unittests/f1ap/cu_cp/CMakeLists.txt | 1 - .../f1ap/cu_cp/f1ap_cu_msg_filler_test.cpp | 82 --- 16 files changed, 963 insertions(+), 1128 deletions(-) delete mode 100644 lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp delete mode 100644 lib/f1ap/du/procedures/f1ap_du_ue_context_common.h delete mode 100644 tests/unittests/f1ap/cu_cp/f1ap_cu_msg_filler_test.cpp diff --git a/lib/f1ap/common/asn1_helpers.cpp b/lib/f1ap/common/asn1_helpers.cpp index daf6837b66..ad188002e4 100644 --- a/lib/f1ap/common/asn1_helpers.cpp +++ b/lib/f1ap/common/asn1_helpers.cpp @@ -13,6 +13,59 @@ #include "srsran/asn1/f1ap/common.h" using namespace srsran; +using namespace asn1::f1ap; + +f1ap_cause_t srsran::asn1_to_cause(asn1::f1ap::cause_c asn1_cause) +{ + f1ap_cause_t cause; + + switch (asn1_cause.type()) { + case asn1::f1ap::cause_c::types_opts::radio_network: + cause = static_cast(asn1_cause.radio_network().value); + break; + case asn1::f1ap::cause_c::types_opts::transport: + cause = static_cast(asn1_cause.transport().value); + break; + case asn1::f1ap::cause_c::types_opts::protocol: + cause = static_cast(asn1_cause.protocol().value); + break; + case asn1::f1ap::cause_c::types_opts::misc: + cause = static_cast(asn1_cause.misc().value); + break; + default: + report_fatal_error("Cannot convert F1AP ASN.1 cause {} to common type", asn1_cause.type()); + } + + return cause; +} + +/// \brief Convert \c f1ap_cause_t type to F1AP cause. +/// \param cause The f1ap_cause_t type. +/// \return The F1AP cause. +asn1::f1ap::cause_c srsran::cause_to_asn1(f1ap_cause_t cause) +{ + asn1::f1ap::cause_c asn1_cause; + + if (const auto* result = std::get_if(&cause)) { + asn1_cause.set_radio_network() = static_cast(*result); + return asn1_cause; + } + if (const auto* result = std::get_if(&cause)) { + asn1_cause.set_transport() = static_cast(*result); + return asn1_cause; + } + if (const auto* result = std::get_if(&cause)) { + asn1_cause.set_protocol() = static_cast(*result); + return asn1_cause; + } + if (const auto* result = std::get_if(&cause)) { + asn1_cause.set_misc() = static_cast(*result); + return asn1_cause; + } + + report_fatal_error("Cannot convert cause to F1AP type: {}", cause); + return asn1_cause; +} expected srsran::cgi_from_asn1(const asn1::f1ap::nr_cgi_s& asn1_cgi) { @@ -27,19 +80,32 @@ expected srsran::cgi_from_asn1(const asn1::f1ap::nr_cgi_s& return nr_cell_global_id_t{plmn.value(), nci.value()}; } -pdcp_sn_size srsran::pdcp_sn_size_from_f1ap_asn1(const asn1::f1ap::pdcp_sn_len_e& asn1_pdcp_sn_size) +asn1::f1ap::nr_cgi_s srsran::cgi_to_asn1(const nr_cell_global_id_t& cgi) +{ + asn1::f1ap::nr_cgi_s asn1_nr_cgi; + asn1_nr_cgi.nr_cell_id.from_number(cgi.nci.value()); + asn1_nr_cgi.plmn_id = cgi.plmn_id.to_bytes(); + return asn1_nr_cgi; +} + +expected srsran::nr_cell_id_from_asn1(asn1::f1ap::nr_cgi_s& f1ap_cgi) +{ + return nr_cell_identity::create(f1ap_cgi.nr_cell_id.to_number()); +} + +static pdcp_sn_size pdcp_sn_size_from_f1ap_asn1(const pdcp_sn_len_e& asn1_pdcp_sn_size) { switch (asn1_pdcp_sn_size) { - case asn1::f1ap::pdcp_sn_len_opts::twelve_bits: + case pdcp_sn_len_opts::twelve_bits: return pdcp_sn_size::size12bits; - case asn1::f1ap::pdcp_sn_len_opts::eighteen_bits: + case pdcp_sn_len_opts::eighteen_bits: return pdcp_sn_size::size18bits; default: return pdcp_sn_size::invalid; } } -asn1::f1ap::pdcp_sn_len_e srsran::pdcp_sn_size_to_f1ap_asn1(pdcp_sn_size sn_size) +static pdcp_sn_len_e pdcp_sn_size_to_f1ap_asn1(pdcp_sn_size sn_size) { switch (sn_size) { case pdcp_sn_size::size12bits: @@ -67,8 +133,8 @@ static void fill_drb_setup_mod_common(ASN1Type& asn1obj, const f1ap_drb_setupmod } } -std::vector -srsran::make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l& asn1_list) +static std::vector +make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l& asn1_list) { std::vector uluptnl_info_list; uluptnl_info_list.reserve(asn1_list.size()); @@ -78,8 +144,18 @@ srsran::make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_li return uluptnl_info_list; } -asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l -srsran::make_asn1_ul_up_tnl_info_list(span list) +static std::vector +make_dl_up_tnl_info_list(const asn1::f1ap::dl_up_tnl_info_to_be_setup_list_l& asn1_list) +{ + std::vector uptnl_info_list; + uptnl_info_list.reserve(asn1_list.size()); + for (const auto& tnl_info : asn1_list) { + uptnl_info_list.push_back(asn1_to_up_transport_layer_info(tnl_info.dl_up_tnl_info)); + } + return uptnl_info_list; +} + +static ul_up_tnl_info_to_be_setup_list_l make_asn1_ul_up_tnl_info_list(span list) { asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l ret; ret.resize(list.size()); @@ -89,14 +165,394 @@ srsran::make_asn1_ul_up_tnl_info_list(span list) return ret; } +static rlc_mode get_rlc_mode(const asn1::f1ap::rlc_mode_e& asn1type) +{ + switch (asn1type) { + case asn1::f1ap::rlc_mode_opts::rlc_am: + return rlc_mode::am; + case asn1::f1ap::rlc_mode_opts::rlc_um_bidirectional: + return rlc_mode::um_bidir; + case asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_ul: + return rlc_mode::um_unidir_ul; + case asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_dl: + return rlc_mode::um_unidir_dl; + default: + break; + } + report_fatal_error("Invalid RLC mode"); +} + +/// \brief Convert \c rlc_mode to F1AP ASN.1. +/// \param rlc_mod The common type RLC mode. +/// \return The ASN.1 RLC mode. +static rlc_mode_e rlc_mode_to_f1ap_asn1(const rlc_mode& mode) +{ + rlc_mode_e asn1type; + switch (mode) { + case rlc_mode::am: + return rlc_mode_opts::rlc_am; + case rlc_mode::um_bidir: + return rlc_mode_opts::rlc_um_bidirectional; + case rlc_mode::um_unidir_ul: + return rlc_mode_opts::rlc_um_unidirectional_ul; + case rlc_mode::um_unidir_dl: + return rlc_mode_opts::rlc_um_unidirectional_dl; + default: + break; + } + return asn1type; +} + +static f1ap_drb_info drb_info_from_f1ap_asn1(const asn1::f1ap::qos_info_c& asn1_qos) +{ + f1ap_drb_info out; + + // TODO: Handle Dynamic 5QI. + const drb_info_s& asn1_drb_info = asn1_qos.choice_ext().value().drb_info(); + const non_dyn_5qi_descriptor_s& asn1_non_dyn_5qi = asn1_drb_info.drb_qos.qos_characteristics.non_dyn_5qi(); + out.drb_qos.qos_desc = non_dyn_5qi_descriptor{}; + non_dyn_5qi_descriptor& nondyn_5qi = out.drb_qos.qos_desc.get_nondyn_5qi(); + nondyn_5qi.five_qi = uint_to_five_qi(asn1_non_dyn_5qi.five_qi); + out.drb_qos.alloc_retention_prio.prio_level_arp = asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.prio_level; + out.s_nssai.sst = asn1_drb_info.snssai.sst.to_number(); + if (asn1_drb_info.snssai.sd_present) { + out.s_nssai.sd = asn1_drb_info.snssai.sd.to_number(); + } + // TODO: Do not populate gbr_flow_info for non-GBR flows. + if (asn1_drb_info.drb_qos.gbr_qos_flow_info_present) { + auto& gbr = out.drb_qos.gbr_qos_info.emplace(); + gbr.max_br_dl = asn1_drb_info.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; + gbr.max_br_ul = asn1_drb_info.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; + gbr.gbr_dl = asn1_drb_info.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; + gbr.gbr_ul = asn1_drb_info.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; + if (asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { + gbr.max_packet_loss_rate_dl.emplace(asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); + } + if (asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present) { + gbr.max_packet_loss_rate_dl.emplace(asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul); + } + } + + return out; +} + +/// \brief Convert \c qos_characteristics_t to F1AP ASN.1. +/// \param qos_characteristics The common type QoS characteristics. +/// \return The ASN.1 QoS characteristics. +static asn1::f1ap::qos_characteristics_c qos_characteristics_to_f1ap_asn1(const qos_characteristics& qos_desc) +{ + asn1::f1ap::qos_characteristics_c asn1_qos_characteristics; + + if (qos_desc.is_dyn_5qi()) { + auto& asn1_dyn_5qi = asn1_qos_characteristics.set_dyn_5qi(); + const dyn_5qi_descriptor& dyn_5qi = qos_desc.get_dyn_5qi(); + asn1_dyn_5qi.qos_prio_level = qos_prio_level_to_uint(dyn_5qi.qos_prio_level); + asn1_dyn_5qi.packet_delay_budget = dyn_5qi.packet_delay_budget; + asn1_dyn_5qi.packet_error_rate.per_scalar = dyn_5qi.per.scalar; + asn1_dyn_5qi.packet_error_rate.per_exponent = dyn_5qi.per.exponent; + + if (dyn_5qi.five_qi.has_value()) { + asn1_dyn_5qi.five_qi_present = true; + asn1_dyn_5qi.five_qi = five_qi_to_uint(dyn_5qi.five_qi.value()); + } + + if (dyn_5qi.is_delay_critical.has_value()) { + asn1_dyn_5qi.delay_crit_present = true; + asn1_dyn_5qi.delay_crit.value = dyn_5qi.is_delay_critical.value() + ? asn1::f1ap::dyn_5qi_descriptor_s::delay_crit_opts::delay_crit + : asn1::f1ap::dyn_5qi_descriptor_s::delay_crit_opts::non_delay_crit; + } + + if (dyn_5qi.averaging_win.has_value()) { + asn1_dyn_5qi.averaging_win_present = true; + asn1_dyn_5qi.averaging_win = dyn_5qi.averaging_win.value(); + } + + if (dyn_5qi.max_data_burst_volume.has_value()) { + asn1_dyn_5qi.max_data_burst_volume_present = true; + asn1_dyn_5qi.max_data_burst_volume = dyn_5qi.max_data_burst_volume.value(); + } + + } else { + auto& asn1_non_dyn_5qi = asn1_qos_characteristics.set_non_dyn_5qi(); + const non_dyn_5qi_descriptor& non_dyn_5qi = qos_desc.get_nondyn_5qi(); + + asn1_non_dyn_5qi.five_qi = five_qi_to_uint(non_dyn_5qi.five_qi); + + if (non_dyn_5qi.qos_prio_level.has_value()) { + asn1_non_dyn_5qi.qos_prio_level_present = true; + asn1_non_dyn_5qi.qos_prio_level = qos_prio_level_to_uint(non_dyn_5qi.qos_prio_level.value()); + } + + if (non_dyn_5qi.averaging_win.has_value()) { + asn1_non_dyn_5qi.averaging_win_present = true; + asn1_non_dyn_5qi.averaging_win = non_dyn_5qi.averaging_win.value(); + } + + if (non_dyn_5qi.max_data_burst_volume.has_value()) { + asn1_non_dyn_5qi.max_data_burst_volume_present = true; + asn1_non_dyn_5qi.max_data_burst_volume = non_dyn_5qi.max_data_burst_volume.value(); + } + } + + return asn1_qos_characteristics; +} + +/// \brief Convert QoS info to F1AP ASN.1. +/// \param[in] qos_info The common type qos info. +/// \return The ASN.1 qos info. +static qos_info_c qos_info_to_f1ap_asn1(const f1ap_drb_info& drb_info) +{ + qos_info_c asn1type; + asn1type.set_choice_ext(); + auto& choice_ext = asn1type.choice_ext(); + choice_ext.load_info_obj(ASN1_F1AP_ID_DRB_INFO); + auto& asn1_drb_info = choice_ext.value().drb_info(); + + // qos characteristics + asn1_drb_info.drb_qos.qos_characteristics = qos_characteristics_to_f1ap_asn1(drb_info.drb_qos.qos_desc); + + // alloc and retention prio + asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.prio_level = drb_info.drb_qos.alloc_retention_prio.prio_level_arp; + asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_cap.value = + drb_info.drb_qos.alloc_retention_prio.may_trigger_preemption + ? asn1::f1ap::pre_emption_cap_opts::may_trigger_pre_emption + : asn1::f1ap::pre_emption_cap_opts::shall_not_trigger_pre_emption; + asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_vulnerability.value = + drb_info.drb_qos.alloc_retention_prio.is_preemptable + ? asn1::f1ap::pre_emption_vulnerability_opts::pre_emptable + : asn1::f1ap::pre_emption_vulnerability_opts::not_pre_emptable; + + // gbr qos info + if (drb_info.drb_qos.gbr_qos_info.has_value()) { + asn1_drb_info.drb_qos.gbr_qos_flow_info_present = true; + asn1_drb_info.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl = drb_info.drb_qos.gbr_qos_info.value().max_br_dl; + asn1_drb_info.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul = drb_info.drb_qos.gbr_qos_info.value().max_br_ul; + asn1_drb_info.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl = drb_info.drb_qos.gbr_qos_info.value().gbr_dl; + asn1_drb_info.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul = drb_info.drb_qos.gbr_qos_info.value().gbr_ul; + + if (drb_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_dl.has_value()) { + asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present = true; + asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl = + drb_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_dl.value(); + } + + if (drb_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_ul.has_value()) { + asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present = true; + asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul = + drb_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_ul.value(); + } + } + + // reflective qos attribute + if (drb_info.drb_qos.reflective_qos_attribute_subject_to) { + asn1_drb_info.drb_qos.reflective_qos_attribute_present = true; + asn1_drb_info.drb_qos.reflective_qos_attribute.value = + asn1::f1ap::qos_flow_level_qos_params_s::reflective_qos_attribute_opts::subject_to; + } + + // s nssai + asn1_drb_info.snssai.sst.from_number(drb_info.s_nssai.sst); + if (drb_info.s_nssai.sd.has_value()) { + asn1_drb_info.snssai.sd_present = true; + asn1_drb_info.snssai.sd.from_number(drb_info.s_nssai.sd.value()); + } + + // notif ctrl + if (drb_info.notif_ctrl.has_value()) { + asn1_drb_info.notif_ctrl_present = true; + asn1_drb_info.notif_ctrl = drb_info.notif_ctrl.value() == srsran::drb_notification_control::active + ? notif_ctrl_opts::options::active + : notif_ctrl_opts::options::not_active; + } + + // flows mapped to drb list + for (const auto& qos_flow : drb_info.flows_mapped_to_drb_list) { + asn1::f1ap::flows_mapped_to_drb_item_s asn1_flow; + asn1_flow.qos_flow_id = qos_flow_id_to_uint(qos_flow.qos_flow_id); + asn1_flow.qos_flow_level_qos_params = asn1_drb_info.drb_qos; + + asn1_drb_info.flows_mapped_to_drb_list.push_back(asn1_flow); + } + + return asn1type; +} + +f1ap_srb_to_setup srsran::make_srb_to_setup(const asn1::f1ap::srbs_to_be_setup_item_s& asn1_type) +{ + f1ap_srb_to_setup srb_obj; + srb_obj.srb_id = int_to_srb_id(asn1_type.srb_id); + return srb_obj; +} + +srbs_to_be_setup_list_l srsran::make_srb_to_setup_list(span srbs) +{ + srbs_to_be_setup_list_l asn1_type(srbs.size()); + for (unsigned i = 0; i != srbs.size(); ++i) { + asn1_type[i].load_info_obj(ASN1_F1AP_ID_SRBS_TO_BE_SETUP_ITEM); + asn1_type[i].value().srbs_to_be_setup_item().srb_id = srb_id_to_uint(srbs[i].srb_id); + } + return asn1_type; +} + +srbs_to_be_setup_mod_list_l srsran::make_srb_to_setupmod_list(span srbs) +{ + srbs_to_be_setup_mod_list_l asn1_type(srbs.size()); + for (unsigned i = 0; i != srbs.size(); ++i) { + asn1_type[i].load_info_obj(ASN1_F1AP_ID_SRBS_TO_BE_SETUP_MOD_ITEM); + asn1_type[i].value().srbs_to_be_setup_mod_item().srb_id = srb_id_to_uint(srbs[i].srb_id); + } + return asn1_type; +} + +srbs_setup_list_l srsran::make_srb_setup_list(span srbs) +{ + srbs_setup_list_l asn1_list(srbs.size()); + for (unsigned i = 0; i != srbs.size(); ++i) { + asn1_list[i].load_info_obj(ASN1_F1AP_ID_SRBS_SETUP_ITEM); + asn1_list[i].value().srbs_setup_item().srb_id = srb_id_to_uint(srbs[i]); + asn1_list[i].value().srbs_setup_item().lcid = srb_id_to_lcid(srbs[i]); + } + return asn1_list; +} + +srbs_setup_mod_list_l srsran::make_srb_setupmod_list(span srbs) +{ + srbs_setup_mod_list_l asn1_list(srbs.size()); + for (unsigned i = 0; i != srbs.size(); ++i) { + asn1_list[i].load_info_obj(ASN1_F1AP_ID_SRBS_SETUP_MOD_ITEM); + asn1_list[i].value().srbs_setup_mod_item().srb_id = srb_id_to_uint(srbs[i]); + asn1_list[i].value().srbs_setup_mod_item().lcid = srb_id_to_lcid(srbs[i]); + } + return asn1_list; +} + +template +void fill_common_srb_failed_to_setupmod(T& srb_item, const ASN1Type& asn1_type) +{ + srb_item.srb_id = int_to_srb_id(asn1_type.srb_id); + if (asn1_type.cause_present) { + srb_item.cause = asn1_to_cause(asn1_type.cause); + } +} + +f1ap_srb_failed_to_setup srsran::make_srb_failed_to_setupmod(const srbs_failed_to_be_setup_item_s& asn1_type) +{ + f1ap_srb_failed_to_setup srb_item; + fill_common_srb_failed_to_setupmod(srb_item, asn1_type); + return srb_item; +} + +f1ap_srb_failed_to_setup srsran::make_srb_failed_to_setupmod(const srbs_failed_to_be_setup_mod_item_s& asn1_type) +{ + f1ap_srb_failed_to_setup srb_item; + fill_common_srb_failed_to_setupmod(srb_item, asn1_type); + return srb_item; +} + +// Helper method common to DRBs-toBeSetup-Item and DRBs-toBeSetupMod-Item +template +static void fill_drb_setup_common_fields(T& drb_obj, const ASN1Type& asn1_type) +{ + drb_obj.drb_id = uint_to_drb_id(asn1_type.drb_id); + drb_obj.mode = get_rlc_mode(asn1_type.rlc_mode); + drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(asn1_type.ul_up_tnl_info_to_be_setup_list); + drb_obj.qos_info = drb_info_from_f1ap_asn1(asn1_type.qos_info); +} + +f1ap_drb_to_setup srsran::make_drb_to_setup(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) +{ + f1ap_drb_to_setup drb_obj; + fill_drb_setup_common_fields(drb_obj, drb_item); + if (drb_item.ie_exts_present) { + drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); + } + return drb_obj; +} + +f1ap_drb_to_setup srsran::make_drb_to_setup(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) +{ + f1ap_drb_to_setup drb_obj; + fill_drb_setup_common_fields(drb_obj, drb_item); + if (drb_item.ie_exts_present) { + if (drb_item.ie_exts.dl_pdcp_sn_len_present) { + drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); + } + } + return drb_obj; +} + f1ap_drb_to_modify srsran::make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item) { f1ap_drb_to_modify drb_obj; - drb_obj.drb_id = static_cast(drb_item.drb_id); + drb_obj.drb_id = uint_to_drb_id(drb_item.drb_id); drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(drb_item.ul_up_tnl_info_to_be_setup_list); return drb_obj; } +drbs_to_be_setup_item_s srsran::make_drb_to_setup(const f1ap_drb_to_setup& drb_item) +{ + drbs_to_be_setup_item_s asn1type; + asn1type.drb_id = drb_id_to_uint(drb_item.drb_id); + asn1type.qos_info = qos_info_to_f1ap_asn1(drb_item.qos_info); + asn1type.ul_up_tnl_info_to_be_setup_list = make_asn1_ul_up_tnl_info_list(drb_item.uluptnl_info_list); + asn1type.rlc_mode = rlc_mode_to_f1ap_asn1(drb_item.mode); + asn1type.ie_exts_present = true; + asn1type.ie_exts.dl_pdcp_sn_len = pdcp_sn_size_to_f1ap_asn1(drb_item.pdcp_sn_len); + return asn1type; +} + +drbs_to_be_setup_mod_item_s srsran::make_drb_to_setupmod(const f1ap_drb_to_setup& drb_item) +{ + drbs_to_be_setup_mod_item_s asn1type; + asn1type.drb_id = drb_id_to_uint(drb_item.drb_id); + asn1type.qos_info = qos_info_to_f1ap_asn1(drb_item.qos_info); + asn1type.ul_up_tnl_info_to_be_setup_list = make_asn1_ul_up_tnl_info_list(drb_item.uluptnl_info_list); + asn1type.rlc_mode = rlc_mode_to_f1ap_asn1(drb_item.mode); + asn1type.ie_exts_present = true; + asn1type.ie_exts.dl_pdcp_sn_len_present = true; + asn1type.ie_exts.dl_pdcp_sn_len = pdcp_sn_size_to_f1ap_asn1(drb_item.pdcp_sn_len); + return asn1type; +} + +drbs_to_be_modified_item_s srsran::make_drb_to_mod(const f1ap_drb_to_modify& drb_item) +{ + drbs_to_be_modified_item_s asn1type; + asn1type.drb_id = drb_id_to_uint(drb_item.drb_id); + asn1type.ul_up_tnl_info_to_be_setup_list = make_asn1_ul_up_tnl_info_list(drb_item.uluptnl_info_list); + return asn1type; +} + +drbs_to_be_setup_list_l srsran::make_drb_to_setup_list(span drb_list) +{ + drbs_to_be_setup_list_l asn1_list(drb_list.size()); + for (unsigned i = 0; i != drb_list.size(); ++i) { + asn1_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_SETUP_ITEM); + asn1_list[i]->drbs_to_be_setup_item() = make_drb_to_setup(drb_list[i]); + } + return asn1_list; +} + +drbs_to_be_setup_mod_list_l srsran::make_drb_to_setupmod_list(span drb_list) +{ + drbs_to_be_setup_mod_list_l asn1_list(drb_list.size()); + for (unsigned i = 0; i != drb_list.size(); ++i) { + asn1_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_SETUP_MOD_ITEM); + asn1_list[i]->drbs_to_be_setup_mod_item() = make_drb_to_setupmod(drb_list[i]); + } + return asn1_list; +} + +drbs_to_be_modified_list_l srsran::make_drb_to_modify_list(span drb_list) +{ + drbs_to_be_modified_list_l asn1_list(drb_list.size()); + for (unsigned i = 0; i != drb_list.size(); ++i) { + asn1_list[i].load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_MODIFIED_ITEM); + asn1_list[i]->drbs_to_be_modified_item() = make_drb_to_mod(drb_list[i]); + } + return asn1_list; +} + asn1::f1ap::drbs_setup_list_l srsran::make_drbs_setup_list(span drbs) { asn1::f1ap::drbs_setup_list_l list(drbs.size()); @@ -132,13 +588,44 @@ asn1::f1ap::drbs_modified_list_l srsran::make_drbs_modified_list(span +void fill_common_drb_setup(T& out, const ASN1Type& asn1type) +{ + out.drb_id = uint_to_drb_id(asn1type.drb_id); + if (asn1type.lcid_present) { + out.lcid = uint_to_lcid(asn1type.lcid); + } + out.dluptnl_info_list = make_dl_up_tnl_info_list(asn1type.dl_up_tnl_info_to_be_setup_list); +} + +f1ap_drb_setupmod srsran::make_drb_setupmod(const asn1::f1ap::drbs_setup_item_s& drb) +{ + f1ap_drb_setupmod drb_obj; + fill_common_drb_setup(drb_obj, drb); + return drb_obj; +} + +f1ap_drb_setupmod srsran::make_drb_setupmod(const asn1::f1ap::drbs_setup_mod_item_s& drb) +{ + f1ap_drb_setupmod drb_obj; + fill_common_drb_setup(drb_obj, drb); + return drb_obj; +} + +f1ap_drb_setupmod srsran::make_drb_setupmod(const asn1::f1ap::drbs_modified_item_s& drb) +{ + f1ap_drb_setupmod drb_obj; + fill_common_drb_setup(drb_obj, drb); + return drb_obj; +} + template void fill_drb_failed_item(ASN1Type& asn1obj, const f1ap_drb_failed_to_setupmod& drb_obj) { asn1obj.drb_id = drb_id_to_uint(drb_obj.drb_id); asn1obj.cause_present = drb_obj.cause.has_value(); if (asn1obj.cause_present) { - asn1obj.cause = srs_cu_cp::cause_to_asn1(drb_obj.cause.value()); + asn1obj.cause = cause_to_asn1(drb_obj.cause.value()); } } @@ -174,3 +661,34 @@ srsran::make_drbs_failed_to_be_modified_list(span +static void fill_failed_drb(T& drb_item, const ASN1Type& asn1_type) +{ + drb_item.drb_id = uint_to_drb_id(asn1_type.drb_id); + if (asn1_type.cause_present) { + drb_item.cause = asn1_to_cause(asn1_type.cause); + } +} + +f1ap_drb_failed_to_setupmod +srsran::make_drb_failed_to_setupmod(const asn1::f1ap::drbs_failed_to_be_setup_item_s& asn1_type) +{ + f1ap_drb_failed_to_setupmod drb_item; + fill_failed_drb(drb_item, asn1_type); + return drb_item; +} +f1ap_drb_failed_to_setupmod +srsran::make_drb_failed_to_setupmod(const asn1::f1ap::drbs_failed_to_be_setup_mod_item_s& asn1_type) +{ + f1ap_drb_failed_to_setupmod drb_item; + fill_failed_drb(drb_item, asn1_type); + return drb_item; +} +f1ap_drb_failed_to_setupmod +srsran::make_drb_failed_to_setupmod(const asn1::f1ap::drbs_failed_to_be_modified_item_s& asn1_type) +{ + f1ap_drb_failed_to_setupmod drb_item; + fill_failed_drb(drb_item, asn1_type); + return drb_item; +} diff --git a/lib/f1ap/common/asn1_helpers.h b/lib/f1ap/common/asn1_helpers.h index 36de37fc88..66df6239fb 100644 --- a/lib/f1ap/common/asn1_helpers.h +++ b/lib/f1ap/common/asn1_helpers.h @@ -17,6 +17,16 @@ namespace srsran { +/// \brief Convert F1AP ASN.1 Cause to \c f1ap_cause_t type. +/// \param asn1_cause The F1AP Cause. +/// \return The f1ap_cause_t type. +f1ap_cause_t asn1_to_cause(asn1::f1ap::cause_c asn1_cause); + +/// \brief Convert \c f1ap_cause_t type to F1AP cause. +/// \param cause The f1ap_cause_t type. +/// \return The F1AP cause. +asn1::f1ap::cause_c cause_to_asn1(f1ap_cause_t cause); + /// \brief Extracts a \c drb_id_t from ASN.1 DRB Setup/Modified/Remove type. /// \param drb_item ASN.1 item with DRB-Id. /// \return drb_id_t object. @@ -30,21 +40,42 @@ drb_id_t get_drb_id(const Asn1Type& drb_item) /// \param[in] asn1_cgi The ASN.1 encoded NR-CGI. /// \return The CGI converted to flat internal struct. expected cgi_from_asn1(const asn1::f1ap::nr_cgi_s& asn1_cgi); +asn1::f1ap::nr_cgi_s cgi_to_asn1(const nr_cell_global_id_t& cgi); + +/// \brief Convert F1AP ASN.1 NR-CGI to NR Cell Identity. +/// \param f1ap_cgi The F1AP NR-CGI. +/// \return The NR Cell Identity. +expected nr_cell_id_from_asn1(asn1::f1ap::nr_cgi_s& f1ap_cgi); + +f1ap_srb_to_setup make_srb_to_setup(const asn1::f1ap::srbs_to_be_setup_item_s& srb_item); +asn1::f1ap::srbs_to_be_setup_list_l make_srb_to_setup_list(span srbs); +asn1::f1ap::srbs_to_be_setup_mod_list_l make_srb_to_setupmod_list(span srbs); -pdcp_sn_size pdcp_sn_size_from_f1ap_asn1(const asn1::f1ap::pdcp_sn_len_e& asn1_pdcp_sn_size); -asn1::f1ap::pdcp_sn_len_e pdcp_sn_size_to_f1ap_asn1(pdcp_sn_size sn_size); +/// \brief Conversion helpers between SRB setup/modified common types and respective ASN.1 TS 48.473 types. +asn1::f1ap::srbs_setup_list_l make_srb_setup_list(span srbs); +asn1::f1ap::srbs_setup_mod_list_l make_srb_setupmod_list(span srbs); -std::vector -make_ul_up_tnl_info_list(const asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l& asn1_list); -asn1::f1ap::ul_up_tnl_info_to_be_setup_list_l make_asn1_ul_up_tnl_info_list(span list); +f1ap_srb_failed_to_setup make_srb_failed_to_setupmod(const asn1::f1ap::srbs_failed_to_be_setup_item_s& asn1_type); +f1ap_srb_failed_to_setup make_srb_failed_to_setupmod(const asn1::f1ap::srbs_failed_to_be_setup_mod_item_s& asn1_type); -/// Convert 3GPP TS 38.473, DRBs-ToBeModified-Item ASN.1 type into f1ap_drb_to_modify. -f1ap_drb_to_modify make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); +/// \brief Conversion helpers between DRB to_setup/to_modify common types and respective ASN.1 TS 48.473 types. +f1ap_drb_to_setup make_drb_to_setup(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); +f1ap_drb_to_setup make_drb_to_setup(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); +f1ap_drb_to_modify make_drb_to_modify(const asn1::f1ap::drbs_to_be_modified_item_s& drb_item); +asn1::f1ap::drbs_to_be_setup_item_s make_drb_to_setup(const f1ap_drb_to_setup& drb_item); +asn1::f1ap::drbs_to_be_setup_mod_item_s make_drb_to_setupmod(const f1ap_drb_to_setup& drb_item); +asn1::f1ap::drbs_to_be_modified_item_s make_drb_to_mod(const f1ap_drb_to_modify& drb_item); +asn1::f1ap::drbs_to_be_setup_list_l make_drb_to_setup_list(span drb_list); +asn1::f1ap::drbs_to_be_setup_mod_list_l make_drb_to_setupmod_list(span drb_list); +asn1::f1ap::drbs_to_be_modified_list_l make_drb_to_modify_list(span drb_list); -/// Convert F1AP setup/modified types to respective ASN.1 TS 48.473 types. +/// Conversion helpers between DRB setup/setupmod/modified common types and respective ASN.1 TS 48.473 types. asn1::f1ap::drbs_setup_list_l make_drbs_setup_list(span drbs); asn1::f1ap::drbs_setup_mod_list_l make_drbs_setup_mod_list(span drbs); asn1::f1ap::drbs_modified_list_l make_drbs_modified_list(span drbs); +f1ap_drb_setupmod make_drb_setupmod(const asn1::f1ap::drbs_setup_item_s& drb); +f1ap_drb_setupmod make_drb_setupmod(const asn1::f1ap::drbs_setup_mod_item_s& drb); +f1ap_drb_setupmod make_drb_setupmod(const asn1::f1ap::drbs_modified_item_s& drb); /// Convert F1AP failed to setup/modify types to respective ASN.1 TS 48.473 types. asn1::f1ap::drbs_failed_to_be_setup_list_l @@ -52,6 +83,10 @@ make_drbs_failed_to_be_setup_list(span failed asn1::f1ap::drbs_failed_to_be_setup_mod_list_l make_drbs_failed_to_be_setup_mod_list(span failed_drbs); asn1::f1ap::drbs_failed_to_be_modified_list_l -make_drbs_failed_to_be_modified_list(span failed_drbs); + make_drbs_failed_to_be_modified_list(span failed_drbs); +f1ap_drb_failed_to_setupmod make_drb_failed_to_setupmod(const asn1::f1ap::drbs_failed_to_be_setup_item_s& asn1_type); +f1ap_drb_failed_to_setupmod +make_drb_failed_to_setupmod(const asn1::f1ap::drbs_failed_to_be_setup_mod_item_s& asn1_type); +f1ap_drb_failed_to_setupmod make_drb_failed_to_setupmod(const asn1::f1ap::drbs_failed_to_be_modified_item_s& asn1_type); } // namespace srsran diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 871bef80a1..3d98e09f90 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -25,271 +25,6 @@ namespace srsran { namespace srs_cu_cp { -/// \brief Convert F1AP ASN.1 Cause to \c f1ap_cause_t type. -/// \param asn1_cause The F1AP Cause. -/// \return The f1ap_cause_t type. -inline f1ap_cause_t asn1_to_cause(asn1::f1ap::cause_c asn1_cause) -{ - f1ap_cause_t cause; - - switch (asn1_cause.type()) { - case asn1::f1ap::cause_c::types_opts::radio_network: - cause = static_cast(asn1_cause.radio_network().value); - break; - case asn1::f1ap::cause_c::types_opts::transport: - cause = static_cast(asn1_cause.transport().value); - break; - case asn1::f1ap::cause_c::types_opts::protocol: - cause = static_cast(asn1_cause.protocol().value); - break; - case asn1::f1ap::cause_c::types_opts::misc: - cause = static_cast(asn1_cause.misc().value); - break; - default: - report_fatal_error("Cannot convert F1AP ASN.1 cause {} to common type", asn1_cause.type()); - } - - return cause; -} - -/// \brief Convert \c f1ap_cause_t type to F1AP cause. -/// \param cause The f1ap_cause_t type. -/// \return The F1AP cause. -inline asn1::f1ap::cause_c cause_to_asn1(f1ap_cause_t cause) -{ - asn1::f1ap::cause_c asn1_cause; - - if (const auto* result = std::get_if(&cause)) { - asn1_cause.set_radio_network() = static_cast(*result); - return asn1_cause; - } - if (const auto* result = std::get_if(&cause)) { - asn1_cause.set_transport() = static_cast(*result); - return asn1_cause; - } - if (const auto* result = std::get_if(&cause)) { - asn1_cause.set_protocol() = static_cast(*result); - return asn1_cause; - } - if (const auto* result = std::get_if(&cause)) { - asn1_cause.set_misc() = static_cast(*result); - return asn1_cause; - } - - report_fatal_error("Cannot convert cause to F1AP type: {}", cause); - return asn1_cause; -} - -/// \brief Convert F1AP NRCGI to NR Cell Identity. -/// \param f1ap_cgi The F1AP NRCGI. -/// \return The NR Cell Identity. -inline nr_cell_identity f1ap_asn1_to_nr_cell_identity(asn1::f1ap::nr_cgi_s& f1ap_cgi) -{ - return nr_cell_identity::create(f1ap_cgi.nr_cell_id.to_number()).value(); -} - -/// \brief Convert \c rlc_mode to F1AP ASN.1. -/// \param rlc_mod The common type RLC mode. -/// \return The ASN.1 RLC mode. -inline asn1::f1ap::rlc_mode_e rlc_mode_to_f1ap_asn1(const srsran::rlc_mode& rlc_mod) -{ - asn1::f1ap::rlc_mode_e asn1_rlc_mode; - - switch (rlc_mod) { - case rlc_mode::am: - asn1_rlc_mode.value = asn1::f1ap::rlc_mode_opts::rlc_am; - break; - case rlc_mode::um_bidir: - asn1_rlc_mode.value = asn1::f1ap::rlc_mode_opts::rlc_um_bidirectional; - break; - case rlc_mode::um_unidir_dl: - asn1_rlc_mode.value = asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_dl; - break; - case rlc_mode::um_unidir_ul: - asn1_rlc_mode.value = asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_ul; - break; - case rlc_mode::tm: - // TM not supported for DRBs - report_fatal_error("Invalid RLC mode {}", rlc_mod); - break; - } - - return asn1_rlc_mode; -} - -/// \brief Convert \c qos_characteristics_t to F1AP ASN.1. -/// \param qos_characteristics The common type QoS characteristics. -/// \return The ASN.1 QoS characteristics. -inline asn1::f1ap::qos_characteristics_c -qos_characteristics_to_f1ap_asn1(const qos_characteristics& qos_characteristics) -{ - asn1::f1ap::qos_characteristics_c asn1_qos_characteristics; - - if (qos_characteristics.is_dyn_5qi()) { - auto& asn1_dyn_5qi = asn1_qos_characteristics.set_dyn_5qi(); - const dyn_5qi_descriptor& dyn_5qi = qos_characteristics.get_dyn_5qi(); - asn1_dyn_5qi.qos_prio_level = qos_prio_level_to_uint(dyn_5qi.qos_prio_level); - asn1_dyn_5qi.packet_delay_budget = dyn_5qi.packet_delay_budget; - asn1_dyn_5qi.packet_error_rate.per_scalar = dyn_5qi.per.scalar; - asn1_dyn_5qi.packet_error_rate.per_exponent = dyn_5qi.per.exponent; - - if (dyn_5qi.five_qi.has_value()) { - asn1_dyn_5qi.five_qi_present = true; - asn1_dyn_5qi.five_qi = five_qi_to_uint(dyn_5qi.five_qi.value()); - } - - if (dyn_5qi.is_delay_critical.has_value()) { - asn1_dyn_5qi.delay_crit_present = true; - asn1_dyn_5qi.delay_crit.value = dyn_5qi.is_delay_critical.value() - ? asn1::f1ap::dyn_5qi_descriptor_s::delay_crit_opts::delay_crit - : asn1::f1ap::dyn_5qi_descriptor_s::delay_crit_opts::non_delay_crit; - } - - if (dyn_5qi.averaging_win.has_value()) { - asn1_dyn_5qi.averaging_win_present = true; - asn1_dyn_5qi.averaging_win = dyn_5qi.averaging_win.value(); - } - - if (dyn_5qi.max_data_burst_volume.has_value()) { - asn1_dyn_5qi.max_data_burst_volume_present = true; - asn1_dyn_5qi.max_data_burst_volume = dyn_5qi.max_data_burst_volume.value(); - } - - } else { - auto& asn1_non_dyn_5qi = asn1_qos_characteristics.set_non_dyn_5qi(); - const non_dyn_5qi_descriptor& non_dyn_5qi = qos_characteristics.get_nondyn_5qi(); - - asn1_non_dyn_5qi.five_qi = five_qi_to_uint(non_dyn_5qi.five_qi); - - if (non_dyn_5qi.qos_prio_level.has_value()) { - asn1_non_dyn_5qi.qos_prio_level_present = true; - asn1_non_dyn_5qi.qos_prio_level = qos_prio_level_to_uint(non_dyn_5qi.qos_prio_level.value()); - } - - if (non_dyn_5qi.averaging_win.has_value()) { - asn1_non_dyn_5qi.averaging_win_present = true; - asn1_non_dyn_5qi.averaging_win = non_dyn_5qi.averaging_win.value(); - } - - if (non_dyn_5qi.max_data_burst_volume.has_value()) { - asn1_non_dyn_5qi.max_data_burst_volume_present = true; - asn1_non_dyn_5qi.max_data_burst_volume = non_dyn_5qi.max_data_burst_volume.value(); - } - } - - return asn1_qos_characteristics; -} - -/// \brief Convert \c f1ap_notif_ctrl to F1AP ASN.1. -/// \param[in] notif_ctrl The common type notif ctrl. -/// \return The ASN.1 notif ctrl. -inline asn1::f1ap::notif_ctrl_e f1ap_notif_ctrl_to_asn1(const drb_notification_control& notif_ctrl) -{ - asn1::f1ap::notif_ctrl_e asn1_notif_ctrl; - - switch (notif_ctrl) { - case drb_notification_control::active: - asn1_notif_ctrl = asn1::f1ap::notif_ctrl_opts::options::active; - break; - case drb_notification_control::not_active: - asn1_notif_ctrl = asn1::f1ap::notif_ctrl_opts::options::not_active; - break; - } - - return asn1_notif_ctrl; -} - -/// \brief Convert QoS info to F1AP ASN.1. -/// \param[in] qos_info The common type qos info. -/// \return The ASN.1 qos info. -inline asn1::f1ap::qos_info_c f1ap_qos_info_to_asn1(const f1ap_drb_info& qos_info) -{ - asn1::f1ap::qos_info_c asn1_qos_info; - - // qos info - asn1_qos_info.set_choice_ext(); - auto& choice_ext = asn1_qos_info.choice_ext(); - choice_ext.load_info_obj(ASN1_F1AP_ID_DRB_INFO); - - auto& asn1_drb_info = choice_ext.value().drb_info(); - - // drb qos - // qos characteristics - asn1_drb_info.drb_qos.qos_characteristics = qos_characteristics_to_f1ap_asn1(qos_info.drb_qos.qos_desc); - - // alloc and retention prio - asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.prio_level = qos_info.drb_qos.alloc_retention_prio.prio_level_arp; - asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_cap.value = - qos_info.drb_qos.alloc_retention_prio.may_trigger_preemption - ? asn1::f1ap::pre_emption_cap_opts::may_trigger_pre_emption - : asn1::f1ap::pre_emption_cap_opts::shall_not_trigger_pre_emption; - asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_vulnerability.value = - qos_info.drb_qos.alloc_retention_prio.is_preemptable - ? asn1::f1ap::pre_emption_vulnerability_opts::pre_emptable - : asn1::f1ap::pre_emption_vulnerability_opts::not_pre_emptable; - - // assert valid conversion result - srsran_assert(asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_cap != - asn1::f1ap::pre_emption_cap_e::nulltype, - "Invalid preemption capability type"); - - srsran_assert(asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.pre_emption_vulnerability != - asn1::f1ap::pre_emption_vulnerability_opts::nulltype, - "Invalid preemption vulnerability type"); - - // gbr qos info - if (qos_info.drb_qos.gbr_qos_info.has_value()) { - asn1_drb_info.drb_qos.gbr_qos_flow_info_present = true; - asn1_drb_info.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl = qos_info.drb_qos.gbr_qos_info.value().max_br_dl; - asn1_drb_info.drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul = qos_info.drb_qos.gbr_qos_info.value().max_br_ul; - asn1_drb_info.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl = qos_info.drb_qos.gbr_qos_info.value().gbr_dl; - asn1_drb_info.drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul = qos_info.drb_qos.gbr_qos_info.value().gbr_ul; - - if (qos_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_dl.has_value()) { - asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present = true; - asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl = - qos_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_dl.value(); - } - - if (qos_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_ul.has_value()) { - asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present = true; - asn1_drb_info.drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul = - qos_info.drb_qos.gbr_qos_info.value().max_packet_loss_rate_ul.value(); - } - } - - // reflective qos attribute - if (qos_info.drb_qos.reflective_qos_attribute_subject_to) { - asn1_drb_info.drb_qos.reflective_qos_attribute_present = true; - asn1_drb_info.drb_qos.reflective_qos_attribute.value = - asn1::f1ap::qos_flow_level_qos_params_s::reflective_qos_attribute_opts::subject_to; - } - - // s nssai - asn1_drb_info.snssai.sst.from_number(qos_info.s_nssai.sst); - if (qos_info.s_nssai.sd.has_value()) { - asn1_drb_info.snssai.sd_present = true; - asn1_drb_info.snssai.sd.from_number(qos_info.s_nssai.sd.value()); - } - - // notif ctrl - if (qos_info.notif_ctrl.has_value()) { - asn1_drb_info.notif_ctrl_present = true; - asn1_drb_info.notif_ctrl = f1ap_notif_ctrl_to_asn1(qos_info.notif_ctrl.value()); - } - - // flows mapped to drb list - for (const auto& qos_flow : qos_info.flows_mapped_to_drb_list) { - asn1::f1ap::flows_mapped_to_drb_item_s asn1_flow; - asn1_flow.qos_flow_id = qos_flow_id_to_uint(qos_flow.qos_flow_id); - asn1_flow.qos_flow_level_qos_params = asn1_drb_info.drb_qos; - - asn1_drb_info.flows_mapped_to_drb_list.push_back(asn1_flow); - } - - return asn1_qos_info; -} - /// \brief Convert \c f1ap_cell_ul_cfg to F1AP ASN.1. /// \param[in] cell_ul_cfg The common type cell ul cfg. /// \return The ASN.1 cell ul cfg. @@ -375,68 +110,6 @@ inline void f1ap_scell_to_be_setup_mod_item_to_asn1(template_asn1_item& asn1_sce } } -/// \brief Convert srbs to be setup/setup mod item to F1AP ASN.1. -/// \param[out] asn1_srbs_to_be_setup_mod_item The ASN.1 struct to store the result. -/// \param[in] srbs_to_be_setup_mod_item The srbs to be setup/setup item mod common type struct. -template -inline void f1ap_srb_to_setup_to_asn1(template_asn1_item& asn1_srbs_to_be_setup_mod_item, - const f1ap_srb_to_setup& srbs_to_be_setup_mod_item) -{ - // srb id - asn1_srbs_to_be_setup_mod_item.srb_id = srb_id_to_uint(srbs_to_be_setup_mod_item.srb_id); -} - -/// \brief Convert extension fields of drb to be setup item to F1AP ASN.1. -/// \param[out] ie_exts The ASN.1 struct to store the result. -/// \param[in] drb_to_be_setup_item The drb to be setup item common type struct. -inline void f1ap_drb_to_setup_ext_ies_to_asn1(asn1::f1ap::drbs_to_be_setup_item_ext_ies_container& ie_exts, - const f1ap_drb_to_setup& drb_to_be_setup_mod_item) -{ - ie_exts.dl_pdcp_sn_len = pdcp_sn_size_to_f1ap_asn1(drb_to_be_setup_mod_item.pdcp_sn_len); -} - -/// \brief Convert extension fields of drb to be setup mod item to F1AP ASN.1. -/// \param[out] ie_exts The ASN.1 struct to store the result. -/// \param[in] drb_to_be_setup_mod_item The drb to be setup mod item common type struct. -inline void f1ap_drb_to_setup_ext_ies_to_asn1(asn1::f1ap::drbs_to_be_setup_mod_item_ext_ies_container& ie_exts, - const f1ap_drb_to_setup& drb_to_be_setup_mod_item) -{ - ie_exts.dl_pdcp_sn_len_present = true; - ie_exts.dl_pdcp_sn_len = pdcp_sn_size_to_f1ap_asn1(drb_to_be_setup_mod_item.pdcp_sn_len); -} - -/// \brief Convert drbs to be setup/setup mod item to F1AP ASN.1. -/// -/// This is as shared function for \c drbs_to_be_setup_item_s and \c drbs_to_be_setup_item_s, because of identical -/// items. Since the \c ie_exts are different, the filling of these extensions is delegated to respective overloads. -/// -/// \param[out] asn1_drbs_to_be_setup_mod_item The ASN.1 struct to store the result. -/// \param[in] drbs_to_be_setup_mod_item The drbs to be setup/setup item mod common type struct. -template -inline void f1ap_drb_to_setup_to_asn1(template_asn1_item& asn1_drb_to_be_setup_mod_item, - const f1ap_drb_to_setup& drb_to_be_setup_mod_item) -{ - // drb id - asn1_drb_to_be_setup_mod_item.drb_id = drb_id_to_uint(drb_to_be_setup_mod_item.drb_id); - - // qos info - asn1_drb_to_be_setup_mod_item.qos_info = f1ap_qos_info_to_asn1(drb_to_be_setup_mod_item.qos_info); - - // ul up tnl info to be setup list - for (const auto& ul_up_tnl_info_item : drb_to_be_setup_mod_item.uluptnl_info_list) { - asn1::f1ap::ul_up_tnl_info_to_be_setup_item_s item; - up_transport_layer_info_to_asn1(item.ul_up_tnl_info, ul_up_tnl_info_item); - asn1_drb_to_be_setup_mod_item.ul_up_tnl_info_to_be_setup_list.push_back(item); - } - - // rlc mode - asn1_drb_to_be_setup_mod_item.rlc_mode = rlc_mode_to_f1ap_asn1(drb_to_be_setup_mod_item.mode); - - // pdcp sn size - f1ap_drb_to_setup_ext_ies_to_asn1(asn1_drb_to_be_setup_mod_item.ie_exts, drb_to_be_setup_mod_item); - asn1_drb_to_be_setup_mod_item.ie_exts_present = true; -} - /// \brief Convert \c f1ap_tx_action_ind to F1AP ASN.1. /// \param[in] tx_action_ind The common type tx action ind. /// \return The ASN.1 tx action ind. @@ -599,98 +272,6 @@ f1ap_rat_freq_prio_info_to_asn1(const f1ap_rat_freq_prio_info& rat_freq_prio_inf return asn1_rat_freq_prio_info; } -/// \brief Convert \c nr_cell_global_id_t to F1AP ASN.1. -/// \param[in] nr_cgi The common type nr cgi. -/// \return The ASN.1 nr cgi. -inline asn1::f1ap::nr_cgi_s nr_cgi_to_f1ap_asn1(const nr_cell_global_id_t& nr_cgi) -{ - asn1::f1ap::nr_cgi_s asn1_nr_cgi; - - // nr cell id - asn1_nr_cgi.nr_cell_id.from_number(nr_cgi.nci.value()); - - // plmn id - asn1_nr_cgi.plmn_id = nr_cgi.plmn_id.to_bytes(); - - return asn1_nr_cgi; -} - -/// \brief Convert F1AP ASN.1 to \c nr_cell_global_id_t. -/// \param[in] asn1_nr_cgi The ASN.1 type nr cgi. -/// \return The common type nr cgi. -inline nr_cell_global_id_t f1ap_asn1_to_nr_cgi(const asn1::f1ap::nr_cgi_s& asn1_nr_cgi) -{ - nr_cell_global_id_t nr_cgi; - - // nr cell id - nr_cgi.nci = nr_cell_identity::create(asn1_nr_cgi.nr_cell_id.to_number()).value(); - - // plmn id - nr_cgi.plmn_id = plmn_identity::from_bytes(asn1_nr_cgi.plmn_id.to_bytes()).value(); - - return nr_cgi; -} - -/// \brief Convert F1AP ASN.1 drbs setup/setup mod item to common type. -/// \param[in] asn1_drbs_to_be_setup_mod_item The ASN.1 drbs setup/setup mod item struct. -/// \return The drbs setup/setup item mod common type struct. -template -inline f1ap_drb_setupmod asn1_to_f1ap_drbs_setup_mod_item(const template_asn1_item& asn1_drbs_setup_mod_item) -{ - f1ap_drb_setupmod drb_setup_mod_item; - - // drb id - drb_setup_mod_item.drb_id = uint_to_drb_id(asn1_drbs_setup_mod_item.drb_id); - - // Add DL UP TNL to be setup list - for (auto asn1_dl_up_tnl_info_to_be_setup_item : asn1_drbs_setup_mod_item.dl_up_tnl_info_to_be_setup_list) { - drb_setup_mod_item.dluptnl_info_list.push_back( - asn1_to_up_transport_layer_info(asn1_dl_up_tnl_info_to_be_setup_item.dl_up_tnl_info)); - } - - if (asn1_drbs_setup_mod_item.lcid_present) { - drb_setup_mod_item.lcid = uint_to_lcid(asn1_drbs_setup_mod_item.lcid); - } - - return drb_setup_mod_item; -} - -/// \brief Convert F1AP ASN.1 srbs failed to be setup/setup mod item to common type. -/// \param[in] asn1_srbs_failed_to_be_setup_mod_item The ASN.1 srbs failed to be setup/setup mod item struct. -/// \return The srbs failed to be setup/setup item mod common type struct. -template -inline f1ap_srb_failed_to_setup -asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(const template_asn1_item& asn1_srbs_failed_to_be_setup_mod_item) -{ - f1ap_srb_failed_to_setup item; - - // srb id - item.srb_id = int_to_srb_id(asn1_srbs_failed_to_be_setup_mod_item.srb_id); - if (asn1_srbs_failed_to_be_setup_mod_item.cause_present) { - item.cause = asn1_to_cause(asn1_srbs_failed_to_be_setup_mod_item.cause); - } - - return item; -} - -/// \brief Convert F1AP ASN.1 drbs failed to be setup/setup mod item to common type. -/// \param[in] asn1_drbs_failed_to_be_setup_mod_item The ASN.1 drbs failed to be setup/setup mod item struct. -/// \return The drbs failed to be setup/setup item mod common type struct. -template -inline f1ap_drb_failed_to_setupmod -asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(const template_asn1_item& asn1_drbs_failed_to_be_setup_mod_item) -{ - f1ap_drb_failed_to_setupmod item; - - // drb id - item.drb_id = uint_to_drb_id(asn1_drbs_failed_to_be_setup_mod_item.drb_id); - if (asn1_drbs_failed_to_be_setup_mod_item.cause_present) { - item.cause = asn1_to_cause(asn1_drbs_failed_to_be_setup_mod_item.cause); - } - - return item; -} - /// \brief Convert F1AP ASN.1 srbs setup/setup mod item to common type. /// \param[in] asn1_srbs_to_be_setup_mod_item The ASN.1 srbs setup/setup mod item struct. /// \return The srbs setup/setup item mod common type struct. diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index 7dc3b5cab2..7afac55779 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -25,404 +25,6 @@ namespace srsran { namespace srs_cu_cp { -/// \brief Convert the UE Context Modification Request from common type to ASN.1. -/// \param[out] asn1_request The ASN.1 struct to store the result. -/// \param[in] request The common type UE Context Modification Request. -inline void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod_request_s& asn1_request, - const f1ap_ue_context_modification_request& request) -{ - // sp cell id - if (request.sp_cell_id.has_value()) { - asn1_request->sp_cell_id_present = true; - asn1_request->sp_cell_id.nr_cell_id.from_number(request.sp_cell_id.value().nci.value()); - asn1_request->sp_cell_id.plmn_id = request.sp_cell_id.value().plmn_id.to_bytes(); - } - - // serv cell idx - if (request.serv_cell_idx.has_value()) { - asn1_request->serv_cell_idx_present = true; - asn1_request->serv_cell_idx = request.serv_cell_idx.value(); - } - - // sp cell ul cfg - if (request.sp_cell_ul_cfg.has_value()) { - asn1_request->sp_cell_ul_cfg_present = true; - asn1_request->sp_cell_ul_cfg = cell_ul_cfg_to_asn1(request.sp_cell_ul_cfg.value()); - } - - // drx cycle - if (request.drx_cycle.has_value()) { - asn1_request->drx_cycle_present = true; - asn1::number_to_enum(asn1_request->drx_cycle.long_drx_cycle_len, request.drx_cycle.value().long_drx_cycle_len); - - if (request.drx_cycle.value().short_drx_cycle_len.has_value()) { - asn1_request->drx_cycle.short_drx_cycle_len_present = true; - asn1::number_to_enum(asn1_request->drx_cycle.short_drx_cycle_len, - request.drx_cycle.value().short_drx_cycle_len.value()); - } - - if (request.drx_cycle.value().short_drx_cycle_timer.has_value()) { - asn1_request->drx_cycle.short_drx_cycle_timer_present = true; - asn1_request->drx_cycle.short_drx_cycle_timer = request.drx_cycle.value().short_drx_cycle_timer.value(); - } - } - - // cu to du rrc info - if (request.cu_to_du_rrc_info.has_value()) { - asn1_request->cu_to_du_rrc_info_present = true; - asn1_request->cu_to_du_rrc_info.cg_cfg_info = request.cu_to_du_rrc_info.value().cg_cfg_info.copy(); - asn1_request->cu_to_du_rrc_info.ue_cap_rat_container_list = - request.cu_to_du_rrc_info.value().ue_cap_rat_container_list.copy(); - asn1_request->cu_to_du_rrc_info.meas_cfg = request.cu_to_du_rrc_info.value().meas_cfg.copy(); - } - - // tx action ind - if (request.tx_action_ind.has_value()) { - asn1_request->tx_action_ind_present = true; - asn1_request->tx_action_ind = f1ap_tx_action_ind_to_asn1(request.tx_action_ind.value()); - } - - // res coordination transfer container - if (!request.res_coordination_transfer_container.empty()) { - asn1_request->res_coordination_transfer_container_present = true; - asn1_request->res_coordination_transfer_container = request.res_coordination_transfer_container.copy(); - } - - // rrc recfg complete ind - if (request.rrc_recfg_complete_ind.has_value()) { - asn1_request->rrc_recfg_complete_ind_present = true; - asn1_request->rrc_recfg_complete_ind = f1ap_rrc_recfg_complete_ind_to_asn1(request.rrc_recfg_complete_ind.value()); - } - - // rrc container - if (!request.rrc_container.empty()) { - asn1_request->rrc_container_present = true; - asn1_request->rrc_container = request.rrc_container.copy(); - } - - // scell to be setup mod list - if (!request.scell_to_be_setup_mod_list.empty()) { - asn1_request->scell_to_be_setup_mod_list_present = true; - for (const auto& scell_to_be_setup_mod_item : request.scell_to_be_setup_mod_list) { - asn1::protocol_ie_single_container_s - asn1_scell_to_be_setup_mod_item_container; - asn1_scell_to_be_setup_mod_item_container.load_info_obj(ASN1_F1AP_ID_SCELL_TO_BE_SETUP_MOD_ITEM); - - auto& asn1_scell_to_be_setup_mod_item = - asn1_scell_to_be_setup_mod_item_container.value().scell_to_be_setup_mod_item(); - - f1ap_scell_to_be_setup_mod_item_to_asn1(asn1_scell_to_be_setup_mod_item, scell_to_be_setup_mod_item); - - asn1_request->scell_to_be_setup_mod_list.push_back(asn1_scell_to_be_setup_mod_item_container); - } - } - - // scell to be remd list - if (!request.scell_to_be_remd_list.empty()) { - asn1_request->scell_to_be_remd_list_present = true; - for (const auto& scell_to_be_remd_item : request.scell_to_be_remd_list) { - asn1::protocol_ie_single_container_s - asn1_scell_to_be_remd_item_container; - asn1_scell_to_be_remd_item_container.load_info_obj(ASN1_F1AP_ID_SCELL_TO_BE_REMD_ITEM); - - auto& asn1_scell_to_be_remd_item = asn1_scell_to_be_remd_item_container.value().scell_to_be_remd_item(); - asn1_scell_to_be_remd_item.scell_id.nr_cell_id.from_number(scell_to_be_remd_item.scell_id.nci.value()); - asn1_scell_to_be_remd_item.scell_id.plmn_id = scell_to_be_remd_item.scell_id.plmn_id.to_bytes(); - - asn1_request->scell_to_be_remd_list.push_back(asn1_scell_to_be_remd_item_container); - } - } - - // srbs to be setup mod list - if (!request.srbs_to_be_setup_mod_list.empty()) { - asn1_request->srbs_to_be_setup_mod_list_present = true; - for (const auto& srbs_to_be_setup_mod_item : request.srbs_to_be_setup_mod_list) { - asn1::protocol_ie_single_container_s - asn1_srbs_to_be_setup_mod_item_container; - asn1_srbs_to_be_setup_mod_item_container.load_info_obj(ASN1_F1AP_ID_SRBS_TO_BE_SETUP_MOD_ITEM); - - auto& asn1_srbs_to_be_setup_mod_item = - asn1_srbs_to_be_setup_mod_item_container.value().srbs_to_be_setup_mod_item(); - - f1ap_srb_to_setup_to_asn1(asn1_srbs_to_be_setup_mod_item, srbs_to_be_setup_mod_item); - asn1_request->srbs_to_be_setup_mod_list.push_back(asn1_srbs_to_be_setup_mod_item_container); - } - } - - // drbs to be setup mod list - if (!request.drbs_to_be_setup_mod_list.empty()) { - asn1_request->drbs_to_be_setup_mod_list_present = true; - for (const auto& drb_to_be_setup_mod_item : request.drbs_to_be_setup_mod_list) { - asn1::protocol_ie_single_container_s - asn1_drb_to_be_setup_mod_item_container; - asn1_drb_to_be_setup_mod_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_SETUP_MOD_ITEM); - - f1ap_drb_to_setup_to_asn1(asn1_drb_to_be_setup_mod_item_container.value().drbs_to_be_setup_mod_item(), - drb_to_be_setup_mod_item); - - asn1_request->drbs_to_be_setup_mod_list.push_back(asn1_drb_to_be_setup_mod_item_container); - } - } - - // drbs to be modified list - if (!request.drbs_to_be_modified_list.empty()) { - asn1_request->drbs_to_be_modified_list_present = true; - - for (const auto& drb_to_be_modified_item : request.drbs_to_be_modified_list) { - asn1::protocol_ie_single_container_s - asn1_drb_to_be_modified_item_container; - asn1_drb_to_be_modified_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_MODIFIED_ITEM); - - auto& asn1_drb_to_be_modified_item = asn1_drb_to_be_modified_item_container.value().drbs_to_be_modified_item(); - asn1_drb_to_be_modified_item.drb_id = drb_id_to_uint(drb_to_be_modified_item.drb_id); - - // ul up tnl info to be setup list - asn1_drb_to_be_modified_item.ul_up_tnl_info_to_be_setup_list = - make_asn1_ul_up_tnl_info_list(drb_to_be_modified_item.uluptnl_info_list); - - asn1_request->drbs_to_be_modified_list.push_back(asn1_drb_to_be_modified_item_container); - } - } - - // srbs to be released list - if (!request.srbs_to_be_released_list.empty()) { - asn1_request->srbs_to_be_released_list_present = true; - for (const auto& srb_id : request.srbs_to_be_released_list) { - asn1::protocol_ie_single_container_s - asn1_srb_to_be_released_item_container; - asn1_srb_to_be_released_item_container.load_info_obj(ASN1_F1AP_ID_SRBS_TO_BE_RELEASED_ITEM); - - auto& asn1_srb_to_be_released_item = asn1_srb_to_be_released_item_container.value().srbs_to_be_released_item(); - asn1_srb_to_be_released_item.srb_id = srb_id_to_uint(srb_id); - - asn1_request->srbs_to_be_released_list.push_back(asn1_srb_to_be_released_item_container); - } - } - - // drbs to be released list - if (!request.drbs_to_be_released_list.empty()) { - asn1_request->drbs_to_be_released_list_present = true; - for (const auto& drb_id : request.drbs_to_be_released_list) { - asn1::protocol_ie_single_container_s - asn1_drb_to_be_released_item_container; - asn1_drb_to_be_released_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_RELEASED_ITEM); - - auto& asn1_drb_to_be_released_item = asn1_drb_to_be_released_item_container.value().drbs_to_be_released_item(); - asn1_drb_to_be_released_item.drb_id = drb_id_to_uint(drb_id); - - asn1_request->drbs_to_be_released_list.push_back(asn1_drb_to_be_released_item_container); - } - } - - // inactivity monitoring request - if (request.inactivity_monitoring_request.has_value()) { - asn1_request->inactivity_monitoring_request_present = true; - asn1::bool_to_enum(asn1_request->inactivity_monitoring_request, request.inactivity_monitoring_request.value()); - } - - // rat freq prio info - if (request.rat_freq_prio_info.has_value()) { - asn1_request->rat_freq_prio_info_present = true; - asn1_request->rat_freq_prio_info = f1ap_rat_freq_prio_info_to_asn1(request.rat_freq_prio_info.value()); - } - - // drx cfg ind - if (request.drx_cfg_ind.has_value()) { - asn1_request->drx_cfg_ind_present = true; - asn1::bool_to_enum(asn1_request->drx_cfg_ind, request.drx_cfg_ind.value()); - } - - // rlc fail ind - if (request.rlc_fail_ind.has_value()) { - asn1_request->rlc_fail_ind_present = true; - asn1_request->rlc_fail_ind.assocated_lcid = request.rlc_fail_ind.value().assocated_lcid; - } - - // ul tx direct current list info - if (!request.ul_tx_direct_current_list_info.empty()) { - asn1_request->ul_tx_direct_current_list_info_present = true; - asn1_request->ul_tx_direct_current_list_info = request.ul_tx_direct_current_list_info.copy(); - } - - // gnb du cfg query - if (request.gnb_du_cfg_query.has_value()) { - asn1_request->gnb_du_cfg_query_present = true; - asn1::bool_to_enum(asn1_request->gnb_du_cfg_query, request.gnb_du_cfg_query.value()); - } - - // gnb du ue ambr ul - if (request.gnb_du_ue_ambr_ul.has_value()) { - asn1_request->gnb_du_ue_ambr_ul_present = true; - asn1_request->gnb_du_ue_ambr_ul = request.gnb_du_ue_ambr_ul.value(); - } - - // execute dupl - if (request.execute_dupl.has_value()) { - asn1_request->execute_dupl_present = true; - asn1::bool_to_enum(asn1_request->execute_dupl, request.execute_dupl.value()); - } - - // rrc delivery status request - if (request.rrc_delivery_status_request.has_value()) { - asn1_request->rrc_delivery_status_request_present = true; - asn1::bool_to_enum(asn1_request->rrc_delivery_status_request, request.rrc_delivery_status_request.value()); - } - - // res coordination transfer info - if (request.res_coordination_transfer_info.has_value()) { - asn1_request->res_coordination_transfer_info_present = true; - asn1_request->res_coordination_transfer_info.res_coordination_eutra_cell_info_present = false; - asn1_request->res_coordination_transfer_info.m_enb_cell_id.from_number( - request.res_coordination_transfer_info.value().m_enb_cell_id.value()); - } - - // serving cell mo - if (request.serving_cell_mo.has_value()) { - asn1_request->serving_cell_mo_present = true; - asn1_request->serving_cell_mo = request.serving_cell_mo.value(); - } - - // need for gap - if (request.need_for_gap.has_value()) { - asn1_request->needfor_gap_present = true; - asn1::bool_to_enum(asn1_request->needfor_gap, request.need_for_gap.value()); - } - - // full cfg - if (request.full_cfg.has_value()) { - asn1_request->full_cfg_present = true; - asn1::bool_to_enum(asn1_request->full_cfg, request.full_cfg.value()); - } -} - -/// \brief Convert the UE Context Modification Response from ASN.1 to common type. -/// \param[out] res The common type struct to store the result. -/// \param[in] asn1_response The ASN.1 type UE Context Modification Response. -inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modification_response& res, - const asn1::f1ap::ue_context_mod_resp_s& asn1_response) -{ - res.success = true; - - // DUtoCURRCInformation - if (asn1_response->du_to_cu_rrc_info_present) { - res.du_to_cu_rrc_info.cell_group_cfg = asn1_response->du_to_cu_rrc_info.cell_group_cfg.copy(); - res.du_to_cu_rrc_info.meas_gap_cfg = asn1_response->du_to_cu_rrc_info.meas_gap_cfg.copy(); - res.du_to_cu_rrc_info.requested_p_max_fr1 = asn1_response->du_to_cu_rrc_info.requested_p_max_fr1.copy(); - } - - // Add DRBs setup mod list - if (asn1_response->drbs_setup_mod_list_present) { - for (auto asn1_drb_setup_mod_list_item : asn1_response->drbs_setup_mod_list) { - auto& asn1_drb_mod_item = asn1_drb_setup_mod_list_item.value().drbs_setup_mod_item(); - res.drbs_setup_list.push_back(asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item)); - } - } - - // Add DRBs modified list - if (asn1_response->drbs_modified_list_present) { - for (auto asn1_drbs_modified_list_item : asn1_response->drbs_modified_list) { - auto& asn1_drb_mod_item = asn1_drbs_modified_list_item.value().drbs_modified_item(); - res.drbs_modified_list.push_back(asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item)); - } - } - - // Add SRBs failed to be setup mod list - if (asn1_response->srbs_failed_to_be_setup_mod_list_present) { - for (auto asn1_srbs_failed_setup_mod_list_item : asn1_response->srbs_failed_to_be_setup_mod_list) { - auto& asn1_srb_failed_item = asn1_srbs_failed_setup_mod_list_item.value().srbs_failed_to_be_setup_mod_item(); - res.srbs_failed_to_be_setup_list.push_back(asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item)); - } - } - - // Add DRBs failed to be setup mod list - if (asn1_response->drbs_failed_to_be_setup_mod_list_present) { - for (auto asn1_drbs_failed_setup_mod_list_item : asn1_response->drbs_failed_to_be_setup_mod_list) { - auto& asn1_drb_failed_item = asn1_drbs_failed_setup_mod_list_item.value().drbs_failed_to_be_setup_mod_item(); - res.drbs_failed_to_be_setup_list.push_back(asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item)); - } - } - - // Add SCell failed to be setup mod list - if (asn1_response->scell_failedto_setup_mod_list_present) { - for (auto asn1_scell_failed_setup_mod_list_item : asn1_response->scell_failedto_setup_mod_list) { - auto& asn1_scell_failed_item = asn1_scell_failed_setup_mod_list_item.value().scell_failedto_setup_mod_item(); - - f1ap_scell_failed_to_setup_mod_item scell_failed_item; - scell_failed_item.scell_id = cgi_from_asn1(asn1_scell_failed_item.scell_id).value(); - if (asn1_scell_failed_item.cause_present) { - scell_failed_item.cause = asn1_to_cause(asn1_scell_failed_item.cause); - } - res.scell_failed_to_be_setup_list.push_back(scell_failed_item); - } - } - - // Add DRBs failed to be modified list - if (asn1_response->drbs_failed_to_be_modified_list_present) { - for (auto asn1_drbs_failed_modified_list_item : asn1_response->drbs_failed_to_be_modified_list) { - auto& asn1_drb_failed_item = asn1_drbs_failed_modified_list_item.value().drbs_failed_to_be_modified_item(); - - f1ap_drb_failed_to_setupmod drb_item = asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item); - res.drbs_failed_to_be_modified_list.push_back(drb_item); - } - } - - // Add inactivity monitoring response - if (asn1_response->inactivity_monitoring_resp_present) { - res.inactivity_monitoring_resp = asn1::enum_to_bool(asn1_response->inactivity_monitoring_resp); - } - - // Add C-RNTI - if (asn1_response->c_rnti_present) { - res.c_rnti = to_rnti(asn1_response->c_rnti); - } - - // Add associated SCell list - if (asn1_response->associated_scell_list_present) { - for (auto asn1_associated_scell_list_item : asn1_response->associated_scell_list) { - auto& asn1_associated_scell_item = asn1_associated_scell_list_item.value().associated_scell_item(); - - f1ap_associated_scell_item associated_scell_item; - associated_scell_item.scell_id = f1ap_asn1_to_nr_cell_identity(asn1_associated_scell_item.scell_id); - - res.associated_scell_list.push_back(associated_scell_item); - } - } - - // Add SRBs setup mod list - if (asn1_response->srbs_setup_mod_list_present) { - for (auto asn1_srbs_setup_mod_list_item : asn1_response->srbs_setup_mod_list) { - auto& asn1_srbs_setup_mod_item = asn1_srbs_setup_mod_list_item.value().srbs_setup_mod_item(); - res.srbs_setup_mod_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_setup_mod_item)); - } - } - - // Add SRBs modified list - if (asn1_response->srbs_modified_list_present) { - for (auto asn1_srbs_modified_list_item : asn1_response->srbs_modified_list) { - auto& asn1_srbs_modified_item = asn1_srbs_modified_list_item.value().srbs_modified_item(); - res.srbs_modified_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_modified_item)); - } - } - - // Add full configuration - if (asn1_response->full_cfg_present) { - res.full_cfg = asn1_response->full_cfg.to_string(); - } -} - -/// \brief Convert the UE Context Modification Failure from ASN.1 to common type. -/// \param[out] res The common type struct to store the result. -/// \param[in] asn1_fail The ASN.1 type UE Context Modification Failure. -inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modification_response& res, - const asn1::f1ap::ue_context_mod_fail_s& asn1_fail) -{ - res.success = false; - res.cause = asn1_to_cause(asn1_fail->cause); - if (asn1_fail->crit_diagnostics_present) { - // TODO: Add crit diagnostics - } -} - /// \brief Convert the \c cu_cp_paging_message type to ASN.1. /// \param[out] asn1_paging The ASN.1 type struct to store the result. /// \param[in] paging The common type Paging message. diff --git a/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp index 23ecc6af46..e4df702a93 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp @@ -10,7 +10,7 @@ #include "ue_context_modification_procedure.h" #include "../../common/asn1_helpers.h" -#include "../f1ap_asn1_helpers.h" +#include "../f1ap_asn1_converters.h" #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/ran/cause/ngap_cause.h" @@ -20,6 +20,24 @@ using namespace asn1::f1ap; constexpr std::chrono::milliseconds bearer_context_mod_response_timeout{1000}; +/// \brief Convert the UE Context Modification Request from common type to ASN.1. +/// \param[out] asn1_request The ASN.1 struct to store the result. +/// \param[in] request The common type UE Context Modification Request. +static void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod_request_s& asn1_request, + const f1ap_ue_context_modification_request& request); + +/// \brief Convert the UE Context Modification Response from ASN.1 to common type. +/// \param[out] res The common type struct to store the result. +/// \param[in] asn1_response The ASN.1 type UE Context Modification Response. +static void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modification_response& res, + const asn1::f1ap::ue_context_mod_resp_s& asn1_response); + +/// \brief Convert the UE Context Modification Failure from ASN.1 to common type. +/// \param[out] res The common type struct to store the result. +/// \param[in] asn1_fail The ASN.1 type UE Context Modification Failure. +static void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modification_response& res, + const asn1::f1ap::ue_context_mod_fail_s& asn1_fail); + ue_context_modification_procedure::ue_context_modification_procedure( const f1ap_ue_context_modification_request& request_, f1ap_ue_context& ue_ctxt_, @@ -92,3 +110,357 @@ f1ap_ue_context_modification_response ue_context_modification_procedure::create_ return res; } + +static void fill_asn1_ue_context_modification_request(asn1::f1ap::ue_context_mod_request_s& asn1_request, + const f1ap_ue_context_modification_request& request) +{ + // sp cell id + if (request.sp_cell_id.has_value()) { + asn1_request->sp_cell_id_present = true; + asn1_request->sp_cell_id.nr_cell_id.from_number(request.sp_cell_id.value().nci.value()); + asn1_request->sp_cell_id.plmn_id = request.sp_cell_id.value().plmn_id.to_bytes(); + } + + // serv cell idx + if (request.serv_cell_idx.has_value()) { + asn1_request->serv_cell_idx_present = true; + asn1_request->serv_cell_idx = request.serv_cell_idx.value(); + } + + // sp cell ul cfg + if (request.sp_cell_ul_cfg.has_value()) { + asn1_request->sp_cell_ul_cfg_present = true; + asn1_request->sp_cell_ul_cfg = cell_ul_cfg_to_asn1(request.sp_cell_ul_cfg.value()); + } + + // drx cycle + if (request.drx_cycle.has_value()) { + asn1_request->drx_cycle_present = true; + asn1::number_to_enum(asn1_request->drx_cycle.long_drx_cycle_len, request.drx_cycle.value().long_drx_cycle_len); + + if (request.drx_cycle.value().short_drx_cycle_len.has_value()) { + asn1_request->drx_cycle.short_drx_cycle_len_present = true; + asn1::number_to_enum(asn1_request->drx_cycle.short_drx_cycle_len, + request.drx_cycle.value().short_drx_cycle_len.value()); + } + + if (request.drx_cycle.value().short_drx_cycle_timer.has_value()) { + asn1_request->drx_cycle.short_drx_cycle_timer_present = true; + asn1_request->drx_cycle.short_drx_cycle_timer = request.drx_cycle.value().short_drx_cycle_timer.value(); + } + } + + // cu to du rrc info + if (request.cu_to_du_rrc_info.has_value()) { + asn1_request->cu_to_du_rrc_info_present = true; + asn1_request->cu_to_du_rrc_info.cg_cfg_info = request.cu_to_du_rrc_info.value().cg_cfg_info.copy(); + asn1_request->cu_to_du_rrc_info.ue_cap_rat_container_list = + request.cu_to_du_rrc_info.value().ue_cap_rat_container_list.copy(); + asn1_request->cu_to_du_rrc_info.meas_cfg = request.cu_to_du_rrc_info.value().meas_cfg.copy(); + } + + // tx action ind + if (request.tx_action_ind.has_value()) { + asn1_request->tx_action_ind_present = true; + asn1_request->tx_action_ind = f1ap_tx_action_ind_to_asn1(request.tx_action_ind.value()); + } + + // res coordination transfer container + if (!request.res_coordination_transfer_container.empty()) { + asn1_request->res_coordination_transfer_container_present = true; + asn1_request->res_coordination_transfer_container = request.res_coordination_transfer_container.copy(); + } + + // rrc recfg complete ind + if (request.rrc_recfg_complete_ind.has_value()) { + asn1_request->rrc_recfg_complete_ind_present = true; + asn1_request->rrc_recfg_complete_ind = f1ap_rrc_recfg_complete_ind_to_asn1(request.rrc_recfg_complete_ind.value()); + } + + // rrc container + if (!request.rrc_container.empty()) { + asn1_request->rrc_container_present = true; + asn1_request->rrc_container = request.rrc_container.copy(); + } + + // scell to be setup mod list + if (!request.scell_to_be_setup_mod_list.empty()) { + asn1_request->scell_to_be_setup_mod_list_present = true; + for (const auto& scell_to_be_setup_mod_item : request.scell_to_be_setup_mod_list) { + asn1::protocol_ie_single_container_s + asn1_scell_to_be_setup_mod_item_container; + asn1_scell_to_be_setup_mod_item_container.load_info_obj(ASN1_F1AP_ID_SCELL_TO_BE_SETUP_MOD_ITEM); + + auto& asn1_scell_to_be_setup_mod_item = + asn1_scell_to_be_setup_mod_item_container.value().scell_to_be_setup_mod_item(); + + f1ap_scell_to_be_setup_mod_item_to_asn1(asn1_scell_to_be_setup_mod_item, scell_to_be_setup_mod_item); + + asn1_request->scell_to_be_setup_mod_list.push_back(asn1_scell_to_be_setup_mod_item_container); + } + } + + // scell to be remd list + if (!request.scell_to_be_remd_list.empty()) { + asn1_request->scell_to_be_remd_list_present = true; + for (const auto& scell_to_be_remd_item : request.scell_to_be_remd_list) { + asn1::protocol_ie_single_container_s + asn1_scell_to_be_remd_item_container; + asn1_scell_to_be_remd_item_container.load_info_obj(ASN1_F1AP_ID_SCELL_TO_BE_REMD_ITEM); + + auto& asn1_scell_to_be_remd_item = asn1_scell_to_be_remd_item_container.value().scell_to_be_remd_item(); + asn1_scell_to_be_remd_item.scell_id.nr_cell_id.from_number(scell_to_be_remd_item.scell_id.nci.value()); + asn1_scell_to_be_remd_item.scell_id.plmn_id = scell_to_be_remd_item.scell_id.plmn_id.to_bytes(); + + asn1_request->scell_to_be_remd_list.push_back(asn1_scell_to_be_remd_item_container); + } + } + + // srbs to be setup mod list + if (!request.srbs_to_be_setup_mod_list.empty()) { + asn1_request->srbs_to_be_setup_mod_list_present = true; + asn1_request->srbs_to_be_setup_mod_list = make_srb_to_setupmod_list(request.srbs_to_be_setup_mod_list); + } + + // drbs to be setup mod list + if (!request.drbs_to_be_setup_mod_list.empty()) { + asn1_request->drbs_to_be_setup_mod_list_present = true; + asn1_request->drbs_to_be_setup_mod_list = make_drb_to_setupmod_list(request.drbs_to_be_setup_mod_list); + } + + // drbs to be modified list + if (!request.drbs_to_be_modified_list.empty()) { + asn1_request->drbs_to_be_modified_list_present = true; + asn1_request->drbs_to_be_modified_list = make_drb_to_modify_list(request.drbs_to_be_modified_list); + } + + // srbs to be released list + if (!request.srbs_to_be_released_list.empty()) { + asn1_request->srbs_to_be_released_list_present = true; + for (const auto& srb_id : request.srbs_to_be_released_list) { + asn1::protocol_ie_single_container_s + asn1_srb_to_be_released_item_container; + asn1_srb_to_be_released_item_container.load_info_obj(ASN1_F1AP_ID_SRBS_TO_BE_RELEASED_ITEM); + + auto& asn1_srb_to_be_released_item = asn1_srb_to_be_released_item_container.value().srbs_to_be_released_item(); + asn1_srb_to_be_released_item.srb_id = srb_id_to_uint(srb_id); + + asn1_request->srbs_to_be_released_list.push_back(asn1_srb_to_be_released_item_container); + } + } + + // drbs to be released list + if (!request.drbs_to_be_released_list.empty()) { + asn1_request->drbs_to_be_released_list_present = true; + for (const auto& drb_id : request.drbs_to_be_released_list) { + asn1::protocol_ie_single_container_s + asn1_drb_to_be_released_item_container; + asn1_drb_to_be_released_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_RELEASED_ITEM); + + auto& asn1_drb_to_be_released_item = asn1_drb_to_be_released_item_container.value().drbs_to_be_released_item(); + asn1_drb_to_be_released_item.drb_id = drb_id_to_uint(drb_id); + + asn1_request->drbs_to_be_released_list.push_back(asn1_drb_to_be_released_item_container); + } + } + + // inactivity monitoring request + if (request.inactivity_monitoring_request.has_value()) { + asn1_request->inactivity_monitoring_request_present = true; + asn1::bool_to_enum(asn1_request->inactivity_monitoring_request, request.inactivity_monitoring_request.value()); + } + + // rat freq prio info + if (request.rat_freq_prio_info.has_value()) { + asn1_request->rat_freq_prio_info_present = true; + asn1_request->rat_freq_prio_info = f1ap_rat_freq_prio_info_to_asn1(request.rat_freq_prio_info.value()); + } + + // drx cfg ind + if (request.drx_cfg_ind.has_value()) { + asn1_request->drx_cfg_ind_present = true; + asn1::bool_to_enum(asn1_request->drx_cfg_ind, request.drx_cfg_ind.value()); + } + + // rlc fail ind + if (request.rlc_fail_ind.has_value()) { + asn1_request->rlc_fail_ind_present = true; + asn1_request->rlc_fail_ind.assocated_lcid = request.rlc_fail_ind.value().assocated_lcid; + } + + // ul tx direct current list info + if (!request.ul_tx_direct_current_list_info.empty()) { + asn1_request->ul_tx_direct_current_list_info_present = true; + asn1_request->ul_tx_direct_current_list_info = request.ul_tx_direct_current_list_info.copy(); + } + + // gnb du cfg query + if (request.gnb_du_cfg_query.has_value()) { + asn1_request->gnb_du_cfg_query_present = true; + asn1::bool_to_enum(asn1_request->gnb_du_cfg_query, request.gnb_du_cfg_query.value()); + } + + // gnb du ue ambr ul + if (request.gnb_du_ue_ambr_ul.has_value()) { + asn1_request->gnb_du_ue_ambr_ul_present = true; + asn1_request->gnb_du_ue_ambr_ul = request.gnb_du_ue_ambr_ul.value(); + } + + // execute dupl + if (request.execute_dupl.has_value()) { + asn1_request->execute_dupl_present = true; + asn1::bool_to_enum(asn1_request->execute_dupl, request.execute_dupl.value()); + } + + // rrc delivery status request + if (request.rrc_delivery_status_request.has_value()) { + asn1_request->rrc_delivery_status_request_present = true; + asn1::bool_to_enum(asn1_request->rrc_delivery_status_request, request.rrc_delivery_status_request.value()); + } + + // res coordination transfer info + if (request.res_coordination_transfer_info.has_value()) { + asn1_request->res_coordination_transfer_info_present = true; + asn1_request->res_coordination_transfer_info.res_coordination_eutra_cell_info_present = false; + asn1_request->res_coordination_transfer_info.m_enb_cell_id.from_number( + request.res_coordination_transfer_info.value().m_enb_cell_id.value()); + } + + // serving cell mo + if (request.serving_cell_mo.has_value()) { + asn1_request->serving_cell_mo_present = true; + asn1_request->serving_cell_mo = request.serving_cell_mo.value(); + } + + // need for gap + if (request.need_for_gap.has_value()) { + asn1_request->needfor_gap_present = true; + asn1::bool_to_enum(asn1_request->needfor_gap, request.need_for_gap.value()); + } + + // full cfg + if (request.full_cfg.has_value()) { + asn1_request->full_cfg_present = true; + asn1::bool_to_enum(asn1_request->full_cfg, request.full_cfg.value()); + } +} + +static void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modification_response& res, + const asn1::f1ap::ue_context_mod_resp_s& asn1_response) +{ + res.success = true; + + // DUtoCURRCInformation + if (asn1_response->du_to_cu_rrc_info_present) { + res.du_to_cu_rrc_info.cell_group_cfg = asn1_response->du_to_cu_rrc_info.cell_group_cfg.copy(); + res.du_to_cu_rrc_info.meas_gap_cfg = asn1_response->du_to_cu_rrc_info.meas_gap_cfg.copy(); + res.du_to_cu_rrc_info.requested_p_max_fr1 = asn1_response->du_to_cu_rrc_info.requested_p_max_fr1.copy(); + } + + // Add DRBs setup mod list + if (asn1_response->drbs_setup_mod_list_present) { + for (auto asn1_drb_setup_mod_list_item : asn1_response->drbs_setup_mod_list) { + auto& asn1_drb_mod_item = asn1_drb_setup_mod_list_item.value().drbs_setup_mod_item(); + res.drbs_setup_list.push_back(make_drb_setupmod(asn1_drb_mod_item)); + } + } + + // Add DRBs modified list + if (asn1_response->drbs_modified_list_present) { + for (auto asn1_drbs_modified_list_item : asn1_response->drbs_modified_list) { + auto& asn1_drb_mod_item = asn1_drbs_modified_list_item.value().drbs_modified_item(); + res.drbs_modified_list.push_back(make_drb_setupmod(asn1_drb_mod_item)); + } + } + + // Add SRBs failed to be setup mod list + if (asn1_response->srbs_failed_to_be_setup_mod_list_present) { + for (auto asn1_srbs_failed_setup_mod_list_item : asn1_response->srbs_failed_to_be_setup_mod_list) { + auto& asn1_srb_failed_item = asn1_srbs_failed_setup_mod_list_item.value().srbs_failed_to_be_setup_mod_item(); + res.srbs_failed_to_be_setup_list.push_back(make_srb_failed_to_setupmod(asn1_srb_failed_item)); + } + } + + // Add DRBs failed to be setup mod list + if (asn1_response->drbs_failed_to_be_setup_mod_list_present) { + for (auto asn1_drbs_failed_setup_mod_list_item : asn1_response->drbs_failed_to_be_setup_mod_list) { + auto& asn1_drb_failed_item = asn1_drbs_failed_setup_mod_list_item.value().drbs_failed_to_be_setup_mod_item(); + res.drbs_failed_to_be_setup_list.push_back(make_drb_failed_to_setupmod(asn1_drb_failed_item)); + } + } + + // Add SCell failed to be setup mod list + if (asn1_response->scell_failedto_setup_mod_list_present) { + for (auto asn1_scell_failed_setup_mod_list_item : asn1_response->scell_failedto_setup_mod_list) { + auto& asn1_scell_failed_item = asn1_scell_failed_setup_mod_list_item.value().scell_failedto_setup_mod_item(); + + f1ap_scell_failed_to_setup_mod_item scell_failed_item; + scell_failed_item.scell_id = cgi_from_asn1(asn1_scell_failed_item.scell_id).value(); + if (asn1_scell_failed_item.cause_present) { + scell_failed_item.cause = asn1_to_cause(asn1_scell_failed_item.cause); + } + res.scell_failed_to_be_setup_list.push_back(scell_failed_item); + } + } + + // Add DRBs failed to be modified list + if (asn1_response->drbs_failed_to_be_modified_list_present) { + for (auto asn1_drbs_failed_modified_list_item : asn1_response->drbs_failed_to_be_modified_list) { + auto& asn1_drb_failed_item = asn1_drbs_failed_modified_list_item.value().drbs_failed_to_be_modified_item(); + res.drbs_failed_to_be_modified_list.push_back(make_drb_failed_to_setupmod(asn1_drb_failed_item)); + } + } + + // Add inactivity monitoring response + if (asn1_response->inactivity_monitoring_resp_present) { + res.inactivity_monitoring_resp = asn1::enum_to_bool(asn1_response->inactivity_monitoring_resp); + } + + // Add C-RNTI + if (asn1_response->c_rnti_present) { + res.c_rnti = to_rnti(asn1_response->c_rnti); + } + + // Add associated SCell list + if (asn1_response->associated_scell_list_present) { + for (auto asn1_associated_scell_list_item : asn1_response->associated_scell_list) { + auto& asn1_associated_scell_item = asn1_associated_scell_list_item.value().associated_scell_item(); + + f1ap_associated_scell_item associated_scell_item; + associated_scell_item.scell_id = nr_cell_id_from_asn1(asn1_associated_scell_item.scell_id).value(); + + res.associated_scell_list.push_back(associated_scell_item); + } + } + + // Add SRBs setup mod list + if (asn1_response->srbs_setup_mod_list_present) { + for (auto asn1_srbs_setup_mod_list_item : asn1_response->srbs_setup_mod_list) { + auto& asn1_srbs_setup_mod_item = asn1_srbs_setup_mod_list_item.value().srbs_setup_mod_item(); + res.srbs_setup_mod_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_setup_mod_item)); + } + } + + // Add SRBs modified list + if (asn1_response->srbs_modified_list_present) { + for (auto asn1_srbs_modified_list_item : asn1_response->srbs_modified_list) { + auto& asn1_srbs_modified_item = asn1_srbs_modified_list_item.value().srbs_modified_item(); + res.srbs_modified_list.push_back(asn1_to_f1ap_srbs_setup_mod_item(asn1_srbs_modified_item)); + } + } + + // Add full configuration + if (asn1_response->full_cfg_present) { + res.full_cfg = asn1_response->full_cfg.to_string(); + } +} + +static void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modification_response& res, + const asn1::f1ap::ue_context_mod_fail_s& asn1_fail) +{ + res.success = false; + res.cause = asn1_to_cause(asn1_fail->cause); + if (asn1_fail->crit_diagnostics_present) { + // TODO: Add crit diagnostics + } +} diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index 01efcbc3e9..4dfc915797 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -215,7 +215,7 @@ static void fill_asn1_ue_context_setup_request(asn1::f1ap::ue_context_setup_requ asn1_request->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(ue_ids.du_ue_f1ap_id); } - asn1_request->sp_cell_id = nr_cgi_to_f1ap_asn1(request.sp_cell_id); + asn1_request->sp_cell_id = cgi_to_asn1(request.sp_cell_id); asn1_request->serv_cell_idx = request.serv_cell_idx; // sp cell ul cfg @@ -234,7 +234,7 @@ static void fill_asn1_ue_context_setup_request(asn1::f1ap::ue_context_setup_requ asn1_candidate_cell_item_container.load_info_obj(ASN1_F1AP_ID_CANDIDATE_SP_CELL_ITEM); auto& asn1_candidate_cell_item = asn1_candidate_cell_item_container.value().candidate_sp_cell_item(); - asn1_candidate_cell_item.candidate_sp_cell_id = nr_cgi_to_f1ap_asn1(candidate_cell_item.candidate_sp_cell_id); + asn1_candidate_cell_item.candidate_sp_cell_id = cgi_to_asn1(candidate_cell_item.candidate_sp_cell_id); asn1_request->candidate_sp_cell_list.push_back(asn1_candidate_cell_item_container); } @@ -285,32 +285,13 @@ static void fill_asn1_ue_context_setup_request(asn1::f1ap::ue_context_setup_requ // srbs to be setup list if (!request.srbs_to_be_setup_list.empty()) { asn1_request->srbs_to_be_setup_list_present = true; - - for (const auto& srbs_to_be_setup_item : request.srbs_to_be_setup_list) { - asn1::protocol_ie_single_container_s - asn1_srbs_to_be_setup_item_container; - asn1_srbs_to_be_setup_item_container.set_item(ASN1_F1AP_ID_SRBS_TO_BE_SETUP_ITEM); - auto& asn1_srbs_to_be_setup_item = asn1_srbs_to_be_setup_item_container.value().srbs_to_be_setup_item(); - - f1ap_srb_to_setup_to_asn1(asn1_srbs_to_be_setup_item, srbs_to_be_setup_item); - - asn1_request->srbs_to_be_setup_list.push_back(asn1_srbs_to_be_setup_item_container); - } + asn1_request->srbs_to_be_setup_list = make_srb_to_setup_list(request.srbs_to_be_setup_list); } // drbs to be setup list if (!request.drbs_to_be_setup_list.empty()) { asn1_request->drbs_to_be_setup_list_present = true; - - for (const auto& drb_to_be_setup_item : request.drbs_to_be_setup_list) { - asn1::protocol_ie_single_container_s asn1_drb_to_be_setup_item_container; - asn1_drb_to_be_setup_item_container.load_info_obj(ASN1_F1AP_ID_DRBS_TO_BE_SETUP_ITEM); - - f1ap_drb_to_setup_to_asn1(asn1_drb_to_be_setup_item_container.value().drbs_to_be_setup_item(), - drb_to_be_setup_item); - - asn1_request->drbs_to_be_setup_list.push_back(asn1_drb_to_be_setup_item_container); - } + asn1_request->drbs_to_be_setup_list = make_drb_to_setup_list(request.drbs_to_be_setup_list); } // inactivity monitoring request @@ -398,7 +379,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& for (const auto& asn1_potential_sp_cell_item : asn1_failure->potential_sp_cell_list) { potential_sp_cell_item.potential_sp_cell_id = - f1ap_asn1_to_nr_cgi(asn1_potential_sp_cell_item->potential_sp_cell_item().potential_sp_cell_id); + cgi_from_asn1(asn1_potential_sp_cell_item->potential_sp_cell_item().potential_sp_cell_id).value(); response.potential_sp_cell_list.push_back(potential_sp_cell_item); } @@ -436,7 +417,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->drbs_setup_list_present) { for (auto asn1_drbs_setup_list_item : asn1_response->drbs_setup_list) { auto& asn1_drb_mod_item = asn1_drbs_setup_list_item.value().drbs_setup_item(); - response.drbs_setup_list.push_back(asn1_to_f1ap_drbs_setup_mod_item(asn1_drb_mod_item)); + response.drbs_setup_list.push_back(make_drb_setupmod(asn1_drb_mod_item)); } } @@ -444,8 +425,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->srbs_failed_to_be_setup_list_present) { for (auto asn1_srbs_failed_setup_list_item : asn1_response->srbs_failed_to_be_setup_list) { auto& asn1_srb_failed_item = asn1_srbs_failed_setup_list_item.value().srbs_failed_to_be_setup_item(); - response.srbs_failed_to_be_setup_list.push_back( - asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(asn1_srb_failed_item)); + response.srbs_failed_to_be_setup_list.push_back(make_srb_failed_to_setupmod(asn1_srb_failed_item)); } } @@ -453,8 +433,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& if (asn1_response->drbs_failed_to_be_setup_list_present) { for (auto asn1_drbs_failed_setup_list_item : asn1_response->drbs_failed_to_be_setup_list) { auto& asn1_drb_failed_item = asn1_drbs_failed_setup_list_item.value().drbs_failed_to_be_setup_item(); - response.drbs_failed_to_be_setup_list.push_back( - asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(asn1_drb_failed_item)); + response.drbs_failed_to_be_setup_list.push_back(make_drb_failed_to_setupmod(asn1_drb_failed_item)); } } @@ -465,7 +444,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& // scell id scell_failed_to_setup_item.scell_id = - f1ap_asn1_to_nr_cgi(asn1_scell_failed_to_setup_item->scell_failedto_setup_item().scell_id); + cgi_from_asn1(asn1_scell_failed_to_setup_item->scell_failedto_setup_item().scell_id).value(); // cause if (asn1_scell_failed_to_setup_item->scell_failedto_setup_item().cause_present) { diff --git a/lib/f1ap/du/procedures/CMakeLists.txt b/lib/f1ap/du/procedures/CMakeLists.txt index 5b28b5eaa8..a94658a2c2 100644 --- a/lib/f1ap/du/procedures/CMakeLists.txt +++ b/lib/f1ap/du/procedures/CMakeLists.txt @@ -7,7 +7,6 @@ # set(SOURCES - f1ap_du_ue_context_common.cpp gnb_cu_configuration_update_procedure.cpp f1ap_du_setup_procedure.cpp f1ap_du_removal_procedure.cpp diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp deleted file mode 100644 index 9c9d8e9af5..0000000000 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.cpp +++ /dev/null @@ -1,104 +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 "f1ap_du_ue_context_common.h" -#include "srsran/asn1/f1ap/common.h" - -using namespace srsran; -using namespace srs_du; - -static rlc_mode get_rlc_mode(const asn1::f1ap::rlc_mode_e& asn1type) -{ - switch (asn1type) { - case asn1::f1ap::rlc_mode_opts::rlc_am: - return rlc_mode::am; - case asn1::f1ap::rlc_mode_opts::rlc_um_bidirectional: - return rlc_mode::um_bidir; - case asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_ul: - return rlc_mode::um_unidir_ul; - case asn1::f1ap::rlc_mode_opts::rlc_um_unidirectional_dl: - return rlc_mode::um_unidir_dl; - default: - break; - } - report_fatal_error("Invalid RLC mode"); -} - -template -static void fill_common_drb_config_request_fields(f1ap_drb_to_setup& drb_obj, const ASN1Type& drb_item) -{ - drb_obj.drb_id = static_cast(drb_item.drb_id); - drb_obj.uluptnl_info_list = make_ul_up_tnl_info_list(drb_item.ul_up_tnl_info_to_be_setup_list); - - // TODO: Handle Dynamic 5QI. - const asn1::f1ap::drb_info_s* asn1_drb_info = nullptr; - if constexpr (std::is_same_v) { - if (drb_item.qos_info_present) { - asn1_drb_info = &drb_item.qos_info.choice_ext().value().drb_info(); - } - } else { - asn1_drb_info = &drb_item.qos_info.choice_ext().value().drb_info(); - } - if (asn1_drb_info != nullptr) { - drb_obj.qos_info.drb_qos.qos_desc = non_dyn_5qi_descriptor{}; - non_dyn_5qi_descriptor& nondyn_5qi = drb_obj.qos_info.drb_qos.qos_desc.get_nondyn_5qi(); - nondyn_5qi.five_qi = uint_to_five_qi(asn1_drb_info->drb_qos.qos_characteristics.non_dyn_5qi().five_qi); - drb_obj.qos_info.drb_qos.alloc_retention_prio.prio_level_arp = - asn1_drb_info->drb_qos.ngra_nalloc_retention_prio.prio_level; - drb_obj.qos_info.s_nssai.sst = asn1_drb_info->snssai.sst.to_number(); - if (asn1_drb_info->snssai.sd_present) { - drb_obj.qos_info.s_nssai.sd = asn1_drb_info->snssai.sd.to_number(); - } - // TODO: Do not populate gbr_flow_info for non-GBR flows. - if (asn1_drb_info->drb_qos.gbr_qos_flow_info_present) { - auto& gbr = drb_obj.qos_info.drb_qos.gbr_qos_info.emplace(); - gbr.max_br_dl = asn1_drb_info->drb_qos.gbr_qos_flow_info.max_flow_bit_rate_dl; - gbr.max_br_ul = asn1_drb_info->drb_qos.gbr_qos_flow_info.max_flow_bit_rate_ul; - gbr.gbr_dl = asn1_drb_info->drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_dl; - gbr.gbr_ul = asn1_drb_info->drb_qos.gbr_qos_flow_info.guaranteed_flow_bit_rate_ul; - if (asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl_present) { - gbr.max_packet_loss_rate_dl.emplace(asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_dl); - } - if (asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul_present) { - gbr.max_packet_loss_rate_dl.emplace(asn1_drb_info->drb_qos.gbr_qos_flow_info.max_packet_loss_rate_ul); - } - } - } -} - -f1ap_drb_to_setup srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item) -{ - f1ap_drb_to_setup drb_obj; - fill_common_drb_config_request_fields(drb_obj, drb_item); - - drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); - - if (drb_item.ie_exts_present) { - drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); - } - - return drb_obj; -} - -f1ap_drb_to_setup srsran::srs_du::make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item) -{ - f1ap_drb_to_setup drb_obj; - fill_common_drb_config_request_fields(drb_obj, drb_item); - - drb_obj.mode = get_rlc_mode(drb_item.rlc_mode); - - if (drb_item.ie_exts_present) { - if (drb_item.ie_exts.dl_pdcp_sn_len_present) { - drb_obj.pdcp_sn_len = pdcp_sn_size_from_f1ap_asn1(drb_item.ie_exts.dl_pdcp_sn_len); - } - } - - return drb_obj; -} diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h deleted file mode 100644 index 6ced687c09..0000000000 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ /dev/null @@ -1,42 +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 "../../common/asn1_helpers.h" -#include "srsran/asn1/f1ap/f1ap_pdu_items.h" -#include "srsran/f1ap/du/f1ap_du_ue_context_update.h" -#include "srsran/ran/up_transport_layer_info.h" - -namespace srsran { -namespace srs_du { - -/// \brief Creates a \c srb_id_t from ASN.1 type. -/// -/// This function is used by the following procedures: -/// - f1ap_du_ue_context_setup_procedure -/// - f1ap_du_ue_context_modification_procedure -/// -/// \param srb_item ASN.1 item with SRB-specific parameters to be setup. -/// \return srb_id_t object. -template -srb_id_t make_srb_id(const Asn1Type& srb_item) -{ - return static_cast(srb_item.srb_id); -} - -/// Convert 3GPP TS 38.473, DRBs-ToBeSetup-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_to_setup make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_item_s& drb_item); - -/// Convert 3GPP TS 38.473, DRBs-ToBeSetupMod-Item ASN.1 type into f1ap_drb_config_request. -f1ap_drb_to_setup make_drb_config_request(const asn1::f1ap::drbs_to_be_setup_mod_item_s& drb_item); - -} // namespace srs_du -} // namespace srsran diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index 18fc2b677c..c0a880f63f 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -9,7 +9,7 @@ */ #include "f1ap_du_ue_context_modification_procedure.h" -#include "f1ap_du_ue_context_common.h" +#include "../../common/asn1_helpers.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/f1ap/common/f1ap_message.h" @@ -68,12 +68,12 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 // >> Pass SRBs to setup/modify. for (const auto& srb : msg->srbs_to_be_setup_mod_list) { - du_request.srbs_to_setup.push_back(make_srb_id(srb.value().srbs_to_be_setup_mod_item())); + du_request.srbs_to_setup.push_back(int_to_srb_id(srb.value().srbs_to_be_setup_mod_item().srb_id)); } // >> Pass DRBs to setup. for (const auto& drb : msg->drbs_to_be_setup_mod_list) { - du_request.drbs_to_setup.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_mod_item())); + du_request.drbs_to_setup.push_back(make_drb_to_setup(drb.value().drbs_to_be_setup_mod_item())); } // >> Pass DRBs to modify. @@ -119,14 +119,9 @@ void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_res resp->associated_scell_list_present = false; // > SRBs-SetupMod-List. + resp->srbs_setup_mod_list = make_srb_setupmod_list(du_request.srbs_to_setup); resp->srbs_setup_mod_list_present = not du_request.srbs_to_setup.empty(); - resp->srbs_setup_mod_list.resize(du_request.srbs_to_setup.size()); - for (unsigned i = 0; i != du_request.srbs_to_setup.size(); ++i) { - resp->srbs_setup_mod_list[i].load_info_obj(ASN1_F1AP_ID_SRBS_SETUP_MOD_ITEM); - srbs_setup_mod_item_s& srb = resp->srbs_setup_mod_list[i].value().srbs_setup_mod_item(); - srb.srb_id = srb_id_to_uint(du_request.srbs_to_setup[i]); - srb.lcid = srb_id_to_lcid(du_request.srbs_to_setup[i]); - } + resp->srbs_failed_to_be_setup_mod_list_present = false; resp->srbs_modified_list_present = false; resp->full_cfg_present = false; diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index 3505fd266e..f9ff933420 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -9,8 +9,8 @@ */ #include "f1ap_du_ue_context_setup_procedure.h" +#include "../../common/asn1_helpers.h" #include "../ue_context/f1ap_du_ue_manager.h" -#include "f1ap_du_ue_context_common.h" #include "proc_logger.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/f1ap/common/f1ap_message.h" @@ -139,12 +139,12 @@ async_task f1ap_du_ue_context_setup_procedure:: // > Pass SRBs to setup. for (const auto& srb : msg->srbs_to_be_setup_list) { - du_request.srbs_to_setup.push_back(make_srb_id(srb.value().srbs_to_be_setup_item())); + du_request.srbs_to_setup.push_back(int_to_srb_id(srb.value().srbs_to_be_setup_item().srb_id)); } // > Pass DRBs to setup. for (const auto& drb : msg->drbs_to_be_setup_list) { - du_request.drbs_to_setup.push_back(make_drb_config_request(drb.value().drbs_to_be_setup_item())); + du_request.drbs_to_setup.push_back(make_drb_to_setup(drb.value().drbs_to_be_setup_item())); } if (msg->cu_to_du_rrc_info.ie_exts_present) { diff --git a/tests/unittests/asn1/CMakeLists.txt b/tests/unittests/asn1/CMakeLists.txt index 3e774b0c9f..788aaa47a1 100644 --- a/tests/unittests/asn1/CMakeLists.txt +++ b/tests/unittests/asn1/CMakeLists.txt @@ -38,5 +38,5 @@ target_link_libraries(asn1_ngap_test ngap_asn1 srslog srsran_support srsran_pcap gtest_discover_tests(asn1_ngap_test) add_executable(asn1_cause_conversion_test asn1_cause_conversion_test.cpp) -target_link_libraries(asn1_cause_conversion_test ngap_asn1 f1ap_asn1 e1ap_asn1 srslog srsran_ran srsran_support gtest gtest_main) +target_link_libraries(asn1_cause_conversion_test ngap_asn1 f1ap_asn1 e1ap_asn1 srsran_f1ap_common srslog srsran_ran srsran_support gtest gtest_main) gtest_discover_tests(asn1_cause_conversion_test) diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.cpp b/tests/unittests/cu_cp/cu_cp_test_messages.cpp index f43c9e012a..9da4642014 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_messages.cpp @@ -167,16 +167,3 @@ srsran::srs_cu_cp::generate_e1ap_bearer_context_modification_response(gnb_cu_cp_ return resp; }; - -f1ap_ue_context_modification_response -srsran::srs_cu_cp::generate_f1ap_ue_context_modification_response(gnb_cu_ue_f1ap_id_t cu_ue_f1ap_id, - gnb_du_ue_f1ap_id_t du_ue_f1ap_id) -{ - f1ap_ue_context_modification_response resp; - - f1ap_message asn1_res = generate_ue_context_modification_response(cu_ue_f1ap_id, du_ue_f1ap_id); - - fill_f1ap_ue_context_modification_response(resp, asn1_res.pdu.successful_outcome().value.ue_context_mod_resp()); - - return resp; -}; diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.h b/tests/unittests/cu_cp/cu_cp_test_messages.h index 1ffc382b24..8ef7042e7b 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.h +++ b/tests/unittests/cu_cp/cu_cp_test_messages.h @@ -50,9 +50,5 @@ e1ap_bearer_context_modification_response generate_e1ap_bearer_context_modification_response(gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id); -/// \brief Generate a dummy CU-CP UE Context Modification Response. -f1ap_ue_context_modification_response generate_f1ap_ue_context_modification_response(gnb_cu_ue_f1ap_id_t cu_ue_f1ap_id, - gnb_du_ue_f1ap_id_t du_ue_f1ap_id); - } // namespace srs_cu_cp } // namespace srsran diff --git a/tests/unittests/f1ap/cu_cp/CMakeLists.txt b/tests/unittests/f1ap/cu_cp/CMakeLists.txt index bca54f0ccf..98e83f9931 100644 --- a/tests/unittests/f1ap/cu_cp/CMakeLists.txt +++ b/tests/unittests/f1ap/cu_cp/CMakeLists.txt @@ -16,7 +16,6 @@ set(SOURCES f1ap_cu_ue_context_modification_procedure_test.cpp f1ap_cu_ue_context_release_procedure_test.cpp f1ap_cu_test.cpp - f1ap_cu_msg_filler_test.cpp f1ap_cu_paging_test.cpp) add_executable(f1ap_cu_test ${SOURCES}) diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_msg_filler_test.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_msg_filler_test.cpp deleted file mode 100644 index f16a984452..0000000000 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_msg_filler_test.cpp +++ /dev/null @@ -1,82 +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 "../common/f1ap_cu_test_messages.h" -#include "lib/f1ap/cu_cp/f1ap_asn1_helpers.h" -#include - -using namespace asn1; -using namespace srsran; -using namespace srs_cu_cp; - -#define JSON_OUTPUT 1 - -class f1ap_cu_msg_filler_test : public ::testing::Test -{ -protected: - void SetUp() override - { - srslog::fetch_basic_logger("ASN1").set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("ASN1").set_hex_dump_max_size(-1); - - test_logger.set_level(srslog::basic_levels::debug); - test_logger.set_hex_dump_max_size(-1); - - srslog::init(); - - // Start the log backend. - srslog::init(); - } - - void TearDown() override - { - // flush logger after each test - srslog::flush(); - } - - void verify_f1ap_ue_context_modification(const asn1::f1ap::ue_context_mod_request_s& msg) - { - // set required fields to have full PDU - asn1::f1ap::f1ap_pdu_c pdu; - pdu.set_init_msg(); - pdu.init_msg().load_info_obj(ASN1_F1AP_ID_UE_CONTEXT_MOD); - pdu.init_msg().value.ue_context_mod_request() = msg; - pdu.init_msg().value.ue_context_mod_request()->gnb_cu_ue_f1ap_id = 1; - pdu.init_msg().value.ue_context_mod_request()->gnb_du_ue_f1ap_id = 2; - - // verify succesful packing - srsran::byte_buffer tx_buffer; - asn1::bit_ref bref(tx_buffer); - ASSERT_EQ(pdu.pack(bref), asn1::SRSASN_SUCCESS); - - std::vector bytes{tx_buffer.begin(), tx_buffer.end()}; -#if JSON_OUTPUT - asn1::json_writer json_writer1; - pdu.to_json(json_writer1); - test_logger.info(bytes.data(), bytes.size(), "PDU unpacked ({} B): \n {}", bytes.size(), json_writer1.to_string()); -#endif - - ASSERT_EQ(test_pack_unpack_consistency(pdu), asn1::SRSASN_SUCCESS); - } - - srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); -}; - -// Test correct filling and generation of F1AP ASN1 messages for UE context modficication request. -TEST_F(f1ap_cu_msg_filler_test, when_context_mod_req_valid_then_valid_asn1_msg_generated) -{ - f1ap_ue_context_modification_request msg = generate_ue_context_modification_request(uint_to_ue_index(1)); - - asn1::f1ap::ue_context_mod_request_s f1ap_ue_context_mod_request = {}; - fill_asn1_ue_context_modification_request(f1ap_ue_context_mod_request, msg); - - // pack full F1AP PDU and verify correctnes - verify_f1ap_ue_context_modification(f1ap_ue_context_mod_request); -} From 4999730b23c2a899d993c51e68d2008747cc14fc Mon Sep 17 00:00:00 2001 From: sauka Date: Tue, 16 Jul 2024 15:24:12 +0300 Subject: [PATCH 224/407] ofh: compress PRBs directly into an output buffer ofh: decompress PRBs directly from input buffer avoiding compressed_prb class usage --- include/srsran/adt/bit_buffer.h | 186 ++++++++++++------ .../srsran/ofh/compression/compressed_prb.h | 70 ------- .../ofh/compression/compression_properties.h | 40 ++++ .../srsran/ofh/compression/iq_compressor.h | 13 +- .../srsran/ofh/compression/iq_decompressor.h | 11 +- lib/ofh/compression/CMakeLists.txt | 3 +- lib/ofh/compression/compressed_prb_packer.h | 32 --- .../compression/compressed_prb_unpacker.cpp | 38 ---- lib/ofh/compression/compressed_prb_unpacker.h | 32 --- .../compression/iq_compression_bfp_avx2.cpp | 79 ++++++-- lib/ofh/compression/iq_compression_bfp_avx2.h | 5 +- .../compression/iq_compression_bfp_avx512.cpp | 105 +++++++--- .../compression/iq_compression_bfp_avx512.h | 5 +- .../compression/iq_compression_bfp_impl.cpp | 79 +++++--- lib/ofh/compression/iq_compression_bfp_impl.h | 17 +- .../compression/iq_compression_bfp_neon.cpp | 115 +++++++---- lib/ofh/compression/iq_compression_bfp_neon.h | 5 +- .../compression/iq_compression_death_impl.cpp | 4 +- .../compression/iq_compression_death_impl.h | 9 +- .../compression/iq_compression_none_avx2.cpp | 65 ++++-- .../compression/iq_compression_none_avx2.h | 5 +- .../iq_compression_none_avx512.cpp | 55 ++++-- .../compression/iq_compression_none_avx512.h | 5 +- .../compression/iq_compression_none_impl.cpp | 51 +++-- .../compression/iq_compression_none_impl.h | 4 +- .../compression/iq_compression_none_neon.cpp | 75 ++++--- .../compression/iq_compression_none_neon.h | 5 +- .../compression/iq_compressor_selector.cpp | 4 +- lib/ofh/compression/iq_compressor_selector.h | 4 +- .../compression/iq_decompressor_selector.cpp | 4 +- .../compression/iq_decompressor_selector.h | 5 +- lib/ofh/compression/packing_utils_avx2.h | 91 +++++---- lib/ofh/compression/packing_utils_avx512.h | 44 +++-- ...b_packer.cpp => packing_utils_generic.cpp} | 38 ++-- lib/ofh/compression/packing_utils_generic.h | 27 +++ lib/ofh/compression/packing_utils_neon.h | 38 ++-- .../ofh_uplane_message_builder_impl.cpp | 19 +- .../ofh_uplane_message_decoder_impl.cpp | 82 +------- .../network_order_binary_deserializer.h | 8 + .../support/network_order_binary_serializer.h | 8 + ...fh_data_flow_uplane_downlink_data_impl.cpp | 1 + .../ofh/ofh_compression_benchmark.cpp | 12 +- .../ofh/compression/ofh_compression_test.cpp | 46 +++-- .../ofh_iq_compressor_test_doubles.h | 6 +- .../ofh_iq_decompressor_test_doubles.h | 5 +- ...plane_packet_decoder_dynamic_impl_test.cpp | 5 +- ...uplane_packet_decoder_static_impl_test.cpp | 5 +- ...ta_flow_uplane_downlink_data_impl_test.cpp | 1 + 48 files changed, 872 insertions(+), 694 deletions(-) delete mode 100644 include/srsran/ofh/compression/compressed_prb.h create mode 100644 include/srsran/ofh/compression/compression_properties.h delete mode 100644 lib/ofh/compression/compressed_prb_packer.h delete mode 100644 lib/ofh/compression/compressed_prb_unpacker.cpp delete mode 100644 lib/ofh/compression/compressed_prb_unpacker.h rename lib/ofh/compression/{compressed_prb_packer.cpp => packing_utils_generic.cpp} (50%) create mode 100644 lib/ofh/compression/packing_utils_generic.h diff --git a/include/srsran/adt/bit_buffer.h b/include/srsran/adt/bit_buffer.h index 2e888e2307..fdd69c93bd 100644 --- a/include/srsran/adt/bit_buffer.h +++ b/include/srsran/adt/bit_buffer.h @@ -15,8 +15,9 @@ namespace srsran { -/// Describes a bit buffer that contains packed bits. -class bit_buffer +namespace detail { + +class bit_buffer_base { protected: /// Internal storage word. @@ -31,19 +32,43 @@ class bit_buffer return (nof_bits + (bits_per_word - 1)) / bits_per_word; } + /// Determines the number of words that are currently used. + unsigned nof_words() const { return calculate_nof_words(size()); } + + /// Determines the number of words that are fully occupied by bits. + unsigned nof_full_words() const { return size() / bits_per_word; } + + /// Current size in bits. + size_t current_size; + +public: + /// Constructor specifying the size of buffer. + bit_buffer_base(size_t current_size_ = 0) : current_size(current_size_) {} + + /// Gets the current bit buffer size. + size_t size() const { return current_size; } + + /// Determines whether the bit buffer is empty. + bool is_empty() const { return current_size == 0; } +}; + +} // namespace detail + +/// Describes a reader class that extracts bits packed in a bit buffer. +class bit_buffer_reader : public detail::bit_buffer_base +{ +public: /// \brief Replaces the internal data container and sets the current size. /// \remark The previous data container will still contain the data present before calling this method. - void set_buffer(span new_buffer, unsigned new_size) + void set_buffer(span new_buffer, unsigned new_size) { buffer = new_buffer; current_size = new_size; } - /// Default constructor - it creates a bit buffer with an invalid data storage. - bit_buffer() : buffer({}), current_size(0) {} - - /// Creates a bit buffer from a buffer and a size. - bit_buffer(span buffer_, unsigned current_size_ = 0) : buffer(buffer_), current_size(current_size_) + /// Creates a bit buffer reader from a buffer and a size. + bit_buffer_reader(span buffer_, size_t current_size_ = 0) : + detail::bit_buffer_base(current_size_), buffer(buffer_) { srsran_assert(nof_words() <= buffer.size(), "The current size (i.e., {}) requires {} words which exceeds the maximum number of words (i.e., {}).", @@ -52,9 +77,98 @@ class bit_buffer buffer.size()); } + /// Creates a bit buffer reader from a view of bytes. + static bit_buffer_reader from_bytes(span bytes) { return {bytes, bytes.size() * bits_per_word}; } + + /// \brief Extracts a consecutive \c count number of bits starting at \c startpos. + /// + /// Extracts \c count bits starting at \c startpos position and stores them at the \c count least significant bits. + /// + /// \tparam Integer Integer type of the bits to insert. + /// \param[in] startpos Starting bit position. + /// \param[in] count Number of bits to insert. + /// \return The corresponding bits occupying the \c count least significant bits. + /// \remark An assertion is triggered if the number of bits is larger than the number of bits per word. + /// \remark An assertion is triggered if range of bits exceed the maximum size of the buffer. + template + Integer extract(unsigned startpos, unsigned count) const + { + srsran_assert(count <= bits_per_word, + "The number of bits to insert (i.e., {}) exceeds the number of bits per word (i.e., {}).", + count, + static_cast(bits_per_word)); + srsran_assert(startpos + count <= size(), + "The bit range starting at {} for {} bits exceed the buffer size (i.e., {}).", + startpos, + count, + size()); + unsigned start_word = startpos / bits_per_word; + unsigned start_mod = startpos % bits_per_word; + + // If the operation does not cross boundaries between words. + if (start_mod == 0) { + return buffer[start_word] >> (bits_per_word - count); + } + + // If the insertion only affects to one word. + if (start_mod + count <= bits_per_word) { + return (buffer[start_word] >> (bits_per_word - start_mod - count)) & mask_lsb_ones(count); + } + + // Concatenates two bytes in a 32-bit register and then extracts a word with the requested number of bits. + using extended_word_t = uint32_t; + extended_word_t word = static_cast(buffer[start_word]) << bits_per_word; + word |= static_cast(buffer[start_word + 1]); + word = word >> (2 * bits_per_word - start_mod - count); + word &= mask_lsb_ones(count); + + return static_cast(word); + } + + /// \brief Gets an entire byte. + /// \remark The byte index must not point to a word that is not fully occupied by bits. + const uint8_t get_byte(unsigned i_byte) const + { + srsran_assert(i_byte < nof_full_words(), + "The byte index {} exceeds the number of full words (i.e., {}).", + i_byte, + nof_full_words()); + return buffer[i_byte]; + } + +private: + /// Data storage. + span buffer; +}; + +/// Describes a bit buffer that contains packed bits. +class bit_buffer : public detail::bit_buffer_base +{ +protected: + // using word_t = detail::word_t; + + /// \brief Replaces the internal data container and sets the current size. + /// \remark The previous data container will still contain the data present before calling this method. + void set_buffer(span new_buffer, unsigned new_size) + { + buffer = new_buffer; + current_size = new_size; + } + + /// Default constructor - it creates a bit buffer with an invalid data storage. + bit_buffer() : buffer({}) {} + + /// Creates a bit buffer from a buffer and a size. + bit_buffer(span buffer_, unsigned current_size_ = 0) : detail::bit_buffer_base(current_size_), buffer(buffer_) + { + } + public: /// Creates a bit buffer from a view of bytes. - static bit_buffer from_bytes(span bytes) { return bit_buffer(bytes, bytes.size() * bits_per_word); } + static bit_buffer from_bytes(span bytes) { return {bytes, unsigned(bytes.size()) * bits_per_word}; } + + /// Returns a reader object for this bit buffer. + bit_buffer_reader get_reader() const { return {buffer, current_size}; } /// Fill with zeros. void zero() { std::fill_n(buffer.begin(), nof_words(), 0); } @@ -147,48 +261,12 @@ class bit_buffer template Integer extract(unsigned startpos, unsigned count) const { - srsran_assert(count <= bits_per_word, - "The number of bits to insert (i.e., {}) exceeds the number of bits per word (i.e., {}).", - count, - static_cast(bits_per_word)); - srsran_assert(startpos + count <= size(), - "The bit range starting at {} for {} bits exceed the buffer size (i.e., {}).", - startpos, - count, - size()); - unsigned start_word = startpos / bits_per_word; - unsigned start_mod = startpos % bits_per_word; - - // If the operation does not cross boundaries between words. - if (start_mod == 0) { - return buffer[start_word] >> (bits_per_word - count); - } - - // If the insertion only affects to one word. - if (start_mod + count <= bits_per_word) { - return (buffer[start_word] >> (bits_per_word - start_mod - count)) & mask_lsb_ones(count); - } - - // Concatenates two bytes in a 32-bit register and then extracts a word with the requested number of bits. - using extended_word_t = uint32_t; - extended_word_t word = static_cast(buffer[start_word]) << bits_per_word; - word |= static_cast(buffer[start_word + 1]); - word = word >> (2 * bits_per_word - start_mod - count); - word &= mask_lsb_ones(count); - - return static_cast(word); + return get_reader().extract(startpos, count); } /// \brief Gets an entire byte. /// \remark The byte index must not point to a word that is not fully occupied by bits. - const uint8_t get_byte(unsigned i_byte) const - { - srsran_assert(i_byte < nof_full_words(), - "The byte index {} exceeds the number of full words (i.e., {}).", - i_byte, - nof_full_words()); - return buffer[i_byte]; - } + const uint8_t get_byte(unsigned i_byte) const { return get_reader().get_byte(i_byte); } /// \brief Sets an entire byte. /// \remark The byte index must not point to a word that is not fully occupied by bits. @@ -244,9 +322,6 @@ class bit_buffer return bit_buffer(buffer.subspan(buffer_start, buffer_len), count); } - /// Gets the current bit buffer size. - size_t size() const { return current_size; } - /// Converts the bit buffer into a binary string. template OutputIt to_bin_string(OutputIt&& mem_buffer) const @@ -273,9 +348,6 @@ class bit_buffer return mem_buffer; } - /// Determines whether the bit buffer is empty. - bool is_empty() const { return current_size == 0; } - /// Copy assign operator. bit_buffer& operator=(const bit_buffer& other) { @@ -318,16 +390,8 @@ class bit_buffer span get_buffer() const { return buffer.first(nof_words()); } private: - /// Determines the number of words that are currently used. - unsigned nof_words() const { return calculate_nof_words(size()); } - - /// Determines the number of words that are fully occupied by bits. - unsigned nof_full_words() const { return size() / bits_per_word; } - /// Data storage. span buffer; - /// Current size in bits. - size_t current_size; }; /// \brief Implements a bit buffer that uses static memory. diff --git a/include/srsran/ofh/compression/compressed_prb.h b/include/srsran/ofh/compression/compressed_prb.h deleted file mode 100644 index 9216b64b51..0000000000 --- a/include/srsran/ofh/compression/compressed_prb.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/bit_buffer.h" -#include "srsran/ofh/compression/compression_params.h" -#include "srsran/ran/resource_block.h" - -namespace srsran { -namespace ofh { - -/// \brief Describes the storage of one compressed PRB. -/// -/// Compressed IQ samples are stored in packed format. -class compressed_prb -{ - /// Number of bits required to store compressed IQ samples of one PRB. - static constexpr size_t CAPACITY_BITS = NOF_SUBCARRIERS_PER_RB * 2 * MAX_IQ_WIDTH; - -public: - compressed_prb() = default; - - /// Returns the compression parameter. - uint8_t get_compression_param() const { return comp_param; } - - /// Sets the compression parameter. - void set_compression_param(uint8_t param) { comp_param = param; } - - /// Returns the internal bit buffer storage. - static_bit_buffer& get_bit_buffer() { return data; } - - /// Returns the internal bit buffer storage. - const static_bit_buffer& get_bit_buffer() const { return data; } - - /// Returns the internal buffer storage. - span get_byte_buffer() { return data.get_buffer(); } - - /// Returns the bit buffer storage. - span get_byte_buffer() const { return data.get_buffer(); } - - /// Returns a span of bytes containing packed compressed IQ samples. - span get_packed_data() const - { - srsran_assert(bytes_used != 0, "No bytes yet packed"); - srsran_assert(bytes_used * 8 <= CAPACITY_BITS, "Bit buffer overflow"); - return data.get_buffer().first(bytes_used); - } - - /// Sets the size, in bytes, of the compressed IQ samples. - void set_stored_size(unsigned bytes_used_) { bytes_used = bytes_used_; } - -private: - /// Packed bits of compressed IQ samples. - static_bit_buffer data{CAPACITY_BITS}; - /// Number of bytes of the internal bit buffer actually used by PRB samples. - unsigned bytes_used = 0; - /// Compression parameter specific for every compression type. - uint8_t comp_param = 0; -}; - -} // namespace ofh -} // namespace srsran diff --git a/include/srsran/ofh/compression/compression_properties.h b/include/srsran/ofh/compression/compression_properties.h new file mode 100644 index 0000000000..ecaf825511 --- /dev/null +++ b/include/srsran/ofh/compression/compression_properties.h @@ -0,0 +1,40 @@ +/* + * + * 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 "compression_params.h" +#include "srsran/ran/resource_block.h" +#include "srsran/support/units.h" + +namespace srsran { +namespace ofh { + +/// Returns true if the compression parameter is present based on the given compression type. +constexpr bool is_compression_param_present(compression_type type) +{ + return (type == compression_type::BFP) || (type == compression_type::mu_law) || + (type == compression_type::bfp_selective) || (type == compression_type::mod_selective); +} + +/// Returns size of a PRB compressed according to the given compression parameters. +inline units::bytes get_compressed_prb_size(const ru_compression_params& params) +{ + static constexpr units::bytes compr_param_size{1}; + + unsigned prb_size = NOF_SUBCARRIERS_PER_RB * 2 * params.data_width; + if (is_compression_param_present(params.type)) { + prb_size += compr_param_size.to_bits().value(); + } + return units::bits(prb_size).round_up_to_bytes(); +} + +} // namespace ofh +} // namespace srsran diff --git a/include/srsran/ofh/compression/iq_compressor.h b/include/srsran/ofh/compression/iq_compressor.h index 47edae315d..1232df039f 100644 --- a/include/srsran/ofh/compression/iq_compressor.h +++ b/include/srsran/ofh/compression/iq_compressor.h @@ -12,7 +12,6 @@ #include "srsran/adt/complex.h" #include "srsran/adt/span.h" -#include "srsran/ofh/compression/compressed_prb.h" #include "srsran/ofh/compression/compression_params.h" namespace srsran { @@ -20,7 +19,8 @@ namespace ofh { /// \brief Describes the IQ data compressor. /// -/// Compresses floating point IQ samples according to compression methods specified in WG4.CUS.0 document. +/// Compresses and serializes floating point IQ samples together with compression parameters according to compression +/// methods specified in WG4.CUS.0 document. class iq_compressor { public: @@ -32,11 +32,10 @@ class iq_compressor /// Compresses IQ samples from the input buffer according to received compression parameters and puts the results into /// an array of compressed PRBs. /// - /// \param[out] compressed_prbs A span containing compressed PRBs. - /// \param[in] iq_data IQ samples to be compressed. - /// \param[in] params Compression parameters. - virtual void - compress(span compressed_prbs, span iq_data, const ru_compression_params& params) = 0; + /// \param[out] buffer Buffer where the compressed IQ data and compression parameters will be stored. + /// \param[in] iq_data IQ samples to be compressed. + /// \param[in] params Compression parameters. + virtual void compress(span buffer, span iq_data, const ru_compression_params& params) = 0; }; } // namespace ofh diff --git a/include/srsran/ofh/compression/iq_decompressor.h b/include/srsran/ofh/compression/iq_decompressor.h index d5c5ba57e5..03b964c95f 100644 --- a/include/srsran/ofh/compression/iq_decompressor.h +++ b/include/srsran/ofh/compression/iq_decompressor.h @@ -12,7 +12,6 @@ #include "srsran/adt/complex.h" #include "srsran/adt/span.h" -#include "srsran/ofh/compression/compressed_prb.h" #include "srsran/ofh/compression/compression_params.h" namespace srsran { @@ -20,7 +19,8 @@ namespace ofh { /// \brief Describes the IQ data decompressor. /// -/// Decompresses received PRBs with compressed IQ data according to compression methods specified in WG4.CUS.0 document. +/// Deserializes compression parameters and decompresses received PRBs with compressed IQ data according to compression +/// methods specified in WG4.CUS.0 document. class iq_decompressor { public: @@ -33,11 +33,10 @@ class iq_decompressor /// results into an array of brain floating point IQ samples. /// /// \param[out] iq_data Resulting IQ samples after decompression. - /// \param[in] compressed_prbs A span containing received compressed PRBs. + /// \param[in] compressed_data A span containing received compressed IQ data and compression parameters. /// \param[in] params Compression parameters. - virtual void decompress(span iq_data, - span compressed_prbs, - const ru_compression_params& params) = 0; + virtual void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) = 0; }; } // namespace ofh diff --git a/lib/ofh/compression/CMakeLists.txt b/lib/ofh/compression/CMakeLists.txt index 0d34c79994..a14442125f 100644 --- a/lib/ofh/compression/CMakeLists.txt +++ b/lib/ofh/compression/CMakeLists.txt @@ -7,8 +7,7 @@ # set(SOURCES - compressed_prb_packer.cpp - compressed_prb_unpacker.cpp + packing_utils_generic.cpp compression_factory.cpp iq_compression_none_impl.cpp iq_compression_bfp_impl.cpp diff --git a/lib/ofh/compression/compressed_prb_packer.h b/lib/ofh/compression/compressed_prb_packer.h deleted file mode 100644 index 84b37d9175..0000000000 --- a/lib/ofh/compression/compressed_prb_packer.h +++ /dev/null @@ -1,32 +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/ofh/compression/compressed_prb.h" - -namespace srsran { -namespace ofh { - -/// Provides methods to pack compressed IQ samples into the underlying \c compressed_prb object. -class compressed_prb_packer -{ - /// Handle to the storage. - compressed_prb& prb; - -public: - explicit compressed_prb_packer(compressed_prb& prb_) : prb(prb_) {} - - /// Packs the given IQ samples into the underlying object. - void pack(span compressed_iq, unsigned iq_width); -}; - -} // namespace ofh -} // namespace srsran diff --git a/lib/ofh/compression/compressed_prb_unpacker.cpp b/lib/ofh/compression/compressed_prb_unpacker.cpp deleted file mode 100644 index 2a7735071b..0000000000 --- a/lib/ofh/compression/compressed_prb_unpacker.cpp +++ /dev/null @@ -1,38 +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 "compressed_prb_unpacker.h" -#include "srsran/support/units.h" - -using namespace srsran; -using namespace ofh; - -int16_t compressed_prb_unpacker::unpack(unsigned offset, unsigned length) const -{ - static constexpr unsigned NUM_BITS_IN_BYTE = units::bytes(1).to_bits().value(); - - int16_t value = 0; - unsigned bits_left_to_read = length; - - while (bits_left_to_read) { - if (bits_left_to_read > NUM_BITS_IN_BYTE) { - value = prb.get_bit_buffer().extract(offset, NUM_BITS_IN_BYTE); - value <<= (bits_left_to_read - NUM_BITS_IN_BYTE); - bits_left_to_read -= NUM_BITS_IN_BYTE; - offset += NUM_BITS_IN_BYTE; - continue; - } - - value |= prb.get_bit_buffer().extract(offset, bits_left_to_read); - bits_left_to_read = 0; - } - - return value; -} diff --git a/lib/ofh/compression/compressed_prb_unpacker.h b/lib/ofh/compression/compressed_prb_unpacker.h deleted file mode 100644 index 23e9d654a6..0000000000 --- a/lib/ofh/compression/compressed_prb_unpacker.h +++ /dev/null @@ -1,32 +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/ofh/compression/compressed_prb.h" - -namespace srsran { -namespace ofh { - -/// Provides methods to unpack compressed IQ samples from the underlying \c compressed_prb object. -class compressed_prb_unpacker -{ - /// Handle to the storage. - const compressed_prb& prb; - -public: - explicit compressed_prb_unpacker(const compressed_prb& prb_) : prb(prb_) {} - - /// Extract \c length bits from the underlying storage starting from offset \c offset. - int16_t unpack(unsigned offset, unsigned length) const; -}; - -} // namespace ofh -} // namespace srsran diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.cpp b/lib/ofh/compression/iq_compression_bfp_avx2.cpp index b711f91c31..bd9005eccd 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx2.cpp @@ -12,28 +12,38 @@ #include "avx2_helpers.h" #include "packing_utils_avx2.h" #include "quantizer.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/srsvec/prod.h" +#include "srsran/support/math_utils.h" using namespace srsran; using namespace ofh; -void iq_compression_bfp_avx2::compress(span output, - span input, +void iq_compression_bfp_avx2::compress(span buffer, + span iq_data, const ru_compression_params& params) { // Use generic implementation if AVX2 utils don't support requested bit width. if (!mm256::iq_width_packing_supported(params.data_width)) { - iq_compression_bfp_impl::compress(output, input, params); + iq_compression_bfp_impl::compress(buffer, iq_data, params); return; } // AVX2 register size in a number of 16bit words. static constexpr size_t AVX2_REG_SIZE = 16; + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); span input_quantized_span(input_quantized.data(), float_samples_span.size()); // Performs conversion of input complex float values to signed 16-bit integers. quantize_input(input_quantized_span, float_samples_span); @@ -43,8 +53,10 @@ void iq_compression_bfp_avx2::compress(span output, unsigned rb = 0; // One AVX2 register stores 8 16-bit IQ pairs. We can process 2 PRBs at a time by using 3 AVX2 registers. - for (size_t rb_index_end = (output.size() / 2) * 2; rb != rb_index_end; rb += 2) { - span c_prbs = output.subspan(rb, 2); + for (size_t rb_index_end = (nof_prbs / 2) * 2; rb != rb_index_end; rb += 2) { + // Get view over bytes corresponding to two PRBs processed in this iteration. + span comp_prb0_buffer(&buffer[rb * prb_size], prb_size); + span comp_prb1_buffer(&buffer[(rb + 1) * prb_size], prb_size); // Load symbols. const auto* start_it = input_quantized.begin() + sample_idx; @@ -66,32 +78,51 @@ void iq_compression_bfp_avx2::compress(span output, __m256i rb01_sr_1_epi16 = _mm256_srai_epi16(rb01_epi16, exponent_1); __m256i rb01_sr_epi16 = _mm256_permute2f128_si256(rb01_sr_0_epi16, rb01_sr_1_epi16, 0x30); + // Write compression parameters to the output buffer. + std::memcpy(comp_prb0_buffer.data(), &exponent_0, sizeof(uint8_t)); + std::memcpy(comp_prb1_buffer.data(), &exponent_1, sizeof(uint8_t)); + + comp_prb0_buffer = comp_prb0_buffer.last(comp_prb0_buffer.size() - sizeof(uint8_t)); + comp_prb1_buffer = comp_prb1_buffer.last(comp_prb1_buffer.size() - sizeof(uint8_t)); + // Pack 2 PRBs using utility function and save compression parameters. - mm256::pack_prbs_big_endian(c_prbs, rb0_sr_epi16, rb01_sr_epi16, rb1_sr_epi16, params.data_width); - c_prbs[0].set_compression_param(exponent_0); - c_prbs[1].set_compression_param(exponent_1); + mm256::pack_prbs_big_endian( + comp_prb0_buffer, comp_prb1_buffer, rb0_sr_epi16, rb01_sr_epi16, rb1_sr_epi16, params.data_width); sample_idx += (NOF_SAMPLES_PER_PRB * 2); } // Use generic implementation for the remaining resource blocks. - for (; rb != output.size(); ++rb) { + for (; rb != nof_prbs; ++rb) { + // Get view over buffer bytes corresponding to one PRB. + span comp_prb_buffer(&buffer[rb * prb_size], prb_size); + const auto* start_it = input_quantized.begin() + sample_idx; - compress_prb_generic(output[rb], {start_it, NOF_SAMPLES_PER_PRB}, params.data_width); + compress_prb_generic(comp_prb_buffer, {start_it, NOF_SAMPLES_PER_PRB}, params.data_width); sample_idx += NOF_SAMPLES_PER_PRB; } } -void iq_compression_bfp_avx2::decompress(span output, - span input, +void iq_compression_bfp_avx2::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Use generic implementation if AVX2 utils don't support requested bit width. if (!mm256::iq_width_packing_supported(params.data_width)) { - iq_compression_bfp_impl::decompress(output, input, params); + iq_compression_bfp_impl::decompress(iq_data, compressed_data, params); return; } + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned comp_prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * comp_prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + const float fixp_gain = (1 << (Q_BIT_WIDTH - 1)) - 1.0f; // Determine array size so that AVX2 store operation doesn't write the data out of array bounds. @@ -102,23 +133,29 @@ void iq_compression_bfp_avx2::decompress(span output, alignas(64) std::array unpacked_iq_scaling; unsigned idx = 0; - for (const auto& c_prb : input) { - // Compute scaling factor. - uint8_t exponent = c_prb.get_compression_param(); + for (unsigned c_prb_idx = 0; c_prb_idx != nof_prbs; ++c_prb_idx) { + // Get view over compressed PRB bytes. + span comp_prb_buffer(&compressed_data[c_prb_idx * comp_prb_size], comp_prb_size); + + // Compute scaling factor, first byte contains the exponent. + uint8_t exponent = comp_prb_buffer[0]; float scaler = 1 << exponent; + // Get view over the bytes following the compression parameter. + comp_prb_buffer = comp_prb_buffer.last(comp_prb_buffer.size() - sizeof(exponent)); + // Unpack resource block. span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); - mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm256::unpack_prb_big_endian(unpacked_prb_span, comp_prb_buffer, params.data_width); // Save scaling factor. std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler / fixp_gain); idx += (NOF_SUBCARRIERS_PER_RB * 2); } - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); + span unpacked_iq_int16_span(unpacked_iq_data.data(), iq_data.size() * 2); + span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), iq_data.size() * 2); // Scale unpacked IQ samples using saved exponents and convert to complex samples. - srsvec::convert(output, unpacked_iq_int16_span, unpacked_iq_scaling_span); + srsvec::convert(iq_data, unpacked_iq_int16_span, unpacked_iq_scaling_span); } diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.h b/lib/ofh/compression/iq_compression_bfp_avx2.h index 04479ad5a1..4464955aab 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.h +++ b/lib/ofh/compression/iq_compression_bfp_avx2.h @@ -26,10 +26,11 @@ class iq_compression_bfp_avx2 : public iq_compression_bfp_impl } // See interface for the documentation. - void compress(span output, span input, const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.cpp b/lib/ofh/compression/iq_compression_bfp_avx512.cpp index 8d8561272c..bdf4a5bf88 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx512.cpp @@ -12,7 +12,10 @@ #include "avx512_helpers.h" #include "packing_utils_avx512.h" #include "quantizer.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/srsvec/prod.h" +#include "srsran/support/math_utils.h" +#include "srsran/support/units.h" using namespace srsran; using namespace ofh; @@ -32,37 +35,49 @@ static inline __m512i loadu_epi16_avx512(const void* mem_address) /// \param[in] exponent Exponent used in BFP compression. /// \param[in] data_width Bit width of resulting compressed samples. static void -compress_prb_avx512(compressed_prb& c_prb, const int16_t* uncompr_samples, uint8_t exponent, unsigned data_width) +compress_prb_avx512(span comp_prb_buffer, const int16_t* uncomp_samples, uint8_t exponent, unsigned data_width) { const __mmask32 load_mask = 0x00ffffff; // Load from memory. - __m512i rb_epi16 = _mm512_maskz_loadu_epi16(load_mask, uncompr_samples); + __m512i rb_epi16 = _mm512_maskz_loadu_epi16(load_mask, uncomp_samples); // Apply exponent (compress). __m512i rb_shifted_epi16 = _mm512_srai_epi16(rb_epi16, exponent); + // Save exponent. + std::memcpy(comp_prb_buffer.data(), &exponent, sizeof(uint8_t)); + // Pack compressed samples. - mm512::pack_prb_big_endian(c_prb, rb_shifted_epi16, data_width); + mm512::pack_prb_big_endian( + comp_prb_buffer.last(comp_prb_buffer.size() - sizeof(exponent)), rb_shifted_epi16, data_width); } -void iq_compression_bfp_avx512::compress(span output, - span input, +void iq_compression_bfp_avx512::compress(span buffer, + span iq_data, const ru_compression_params& params) { // Use generic implementation if AVX512 utils don't support requested bit width. if (!mm512::iq_width_packing_supported(params.data_width)) { - iq_compression_bfp_impl::compress(output, input, params); + iq_compression_bfp_impl::compress(buffer, iq_data, params); return; } // AVX512 register size in a number of 16-bit words. static constexpr size_t AVX512_REG_SIZE = 32; + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); span input_quantized_span(input_quantized.data(), float_samples_span.size()); // Performs conversion of input brain float values to signed 16-bit integers. quantize_input(input_quantized_span, float_samples_span); @@ -72,7 +87,7 @@ void iq_compression_bfp_avx512::compress(span output, unsigned rb = 0; // With 3 AVX512 registers we can process 4 PRBs at a time (48 16-bit IQ pairs). - for (size_t rb_index_end = (output.size() / 4) * 4; rb != rb_index_end; rb += 4) { + for (size_t rb_index_end = (nof_prbs / 4) * 4; rb != rb_index_end; rb += 4) { // Load input. __m512i r0_epi16 = loadu_epi16_avx512(&input_quantized[sample_idx]); __m512i r1_epi16 = loadu_epi16_avx512(&input_quantized[sample_idx + AVX512_REG_SIZE]); @@ -83,30 +98,37 @@ void iq_compression_bfp_avx512::compress(span output, // Exponents are stored in the first bytes of each 128bit lane of the result. const auto* exp_byte_ptr = reinterpret_cast(&exp_epu32); - output[rb].set_compression_param(exp_byte_ptr[0]); - output[rb + 1].set_compression_param(exp_byte_ptr[16]); - output[rb + 2].set_compression_param(exp_byte_ptr[32]); - output[rb + 3].set_compression_param(exp_byte_ptr[48]); - // Compress and pack the first PRB using utility function. + // Compress the first PRB. + // Save the exponent. + span output_span(&buffer[rb * prb_size], prb_size); + std::memcpy(output_span.data(), &exp_byte_ptr[0], sizeof(uint8_t)); + // Apply exponent (compress). __m512i rb0_shifted_epi16 = _mm512_srai_epi16(r0_epi16, exp_byte_ptr[0]); - mm512::pack_prb_big_endian(output[rb], rb0_shifted_epi16, params.data_width); + // Pack compressed samples. + mm512::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), rb0_shifted_epi16, params.data_width); // Compress second PRB. + output_span = span(&buffer[(rb + 1) * prb_size], prb_size); compress_prb_avx512( - output[rb + 1], &input_quantized[sample_idx + NOF_SAMPLES_PER_PRB], exp_byte_ptr[16], params.data_width); + output_span, &input_quantized[sample_idx + NOF_SAMPLES_PER_PRB], exp_byte_ptr[16], params.data_width); + // Compress third PRB. + output_span = span(&buffer[(rb + 2) * prb_size], prb_size); compress_prb_avx512( - output[rb + 2], &input_quantized[sample_idx + 2 * NOF_SAMPLES_PER_PRB], exp_byte_ptr[32], params.data_width); + output_span, &input_quantized[sample_idx + 2 * NOF_SAMPLES_PER_PRB], exp_byte_ptr[32], params.data_width); + // Compress fourth PRB. + output_span = span(&buffer[(rb + 3) * prb_size], prb_size); compress_prb_avx512( - output[rb + 3], &input_quantized[sample_idx + 3 * NOF_SAMPLES_PER_PRB], exp_byte_ptr[48], params.data_width); + output_span, &input_quantized[sample_idx + 3 * NOF_SAMPLES_PER_PRB], exp_byte_ptr[48], params.data_width); sample_idx += 4 * NOF_SAMPLES_PER_PRB; } // Process the remaining PRBs (one PRB at a time), - for (size_t rb_index_end = output.size(); rb != rb_index_end; ++rb) { + for (; rb != nof_prbs; ++rb) { const __m512i AVX512_ZERO = _mm512_set1_epi16(0); const __mmask32 load_mask = 0x00ffffff; __m512i rb_epi16 = _mm512_maskz_loadu_epi16(load_mask, &input_quantized[sample_idx]); @@ -114,26 +136,41 @@ void iq_compression_bfp_avx512::compress(span output, // Determine BFP exponent and extract it from the first byte of the first 128bit lane. __m512i exp_epu32 = mm512::determine_bfp_exponent(rb_epi16, AVX512_ZERO, AVX512_ZERO, params.data_width); const auto* exp_byte_ptr = reinterpret_cast(&exp_epu32); - output[rb].set_compression_param(exp_byte_ptr[0]); - // Shift and pack the first PRB using utility function. + span output_span(&buffer[rb * prb_size], prb_size); + + // Save exponent. + memcpy(output_span.data(), &exp_byte_ptr[0], sizeof(uint8_t)); + + // Shift and pack a PRB using utility function. __m512i rb_shifted_epi16 = _mm512_srai_epi16(rb_epi16, exp_byte_ptr[0]); - mm512::pack_prb_big_endian(output[rb], rb_shifted_epi16, params.data_width); + mm512::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), rb_shifted_epi16, params.data_width); sample_idx += NOF_SAMPLES_PER_PRB; } } -void iq_compression_bfp_avx512::decompress(span output, - span input, +void iq_compression_bfp_avx512::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Use generic implementation if AVX512 utils don't support requested bit width. if (!mm512::iq_width_packing_supported(params.data_width)) { - iq_compression_bfp_impl::decompress(output, input, params); + iq_compression_bfp_impl::decompress(iq_data, compressed_data, params); return; } + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned comp_prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * comp_prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + const float fixp_gain = (1 << (Q_BIT_WIDTH - 1)) - 1.0f; // Determine array size so that AVX512 store operation doesn't write the data out of array bounds. @@ -144,23 +181,29 @@ void iq_compression_bfp_avx512::decompress(span output, alignas(64) std::array unpacked_iq_scaling; unsigned idx = 0; - for (const auto& c_prb : input) { - // Compute scaling factor. - uint8_t exponent = c_prb.get_compression_param(); + for (unsigned c_prb_idx = 0; c_prb_idx != nof_prbs; ++c_prb_idx) { + // Get view over compressed PRB bytes. + span comp_prb_buffer(&compressed_data[c_prb_idx * comp_prb_size], comp_prb_size); + + // Compute scaling factor, first byte contains the exponent. + uint8_t exponent = comp_prb_buffer[0]; float scaler = 1 << exponent; + // Get view over the bytes following the compression parameter. + comp_prb_buffer = comp_prb_buffer.last(comp_prb_buffer.size() - sizeof(exponent)); + // Unpack resource block. span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); - mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm512::unpack_prb_big_endian(unpacked_prb_span, comp_prb_buffer, params.data_width); // Save scaling factor. std::fill(&unpacked_iq_scaling[idx], &unpacked_iq_scaling[idx + NOF_SUBCARRIERS_PER_RB * 2], scaler / fixp_gain); idx += (NOF_SUBCARRIERS_PER_RB * 2); } - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); - span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), output.size() * 2); + span unpacked_iq_int16_span(unpacked_iq_data.data(), iq_data.size() * 2); + span unpacked_iq_scaling_span(unpacked_iq_scaling.data(), iq_data.size() * 2); // Scale unpacked IQ samples using saved exponents and convert to complex samples. - srsvec::convert(output, unpacked_iq_int16_span, unpacked_iq_scaling_span); + srsvec::convert(iq_data, unpacked_iq_int16_span, unpacked_iq_scaling_span); } diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.h b/lib/ofh/compression/iq_compression_bfp_avx512.h index 2323fb8307..3869d232c8 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.h +++ b/lib/ofh/compression/iq_compression_bfp_avx512.h @@ -26,10 +26,11 @@ class iq_compression_bfp_avx512 : public iq_compression_bfp_impl } // See interface for the documentation. - void compress(span output, span input, const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_bfp_impl.cpp b/lib/ofh/compression/iq_compression_bfp_impl.cpp index b28a783f8b..41d2dd7b18 100644 --- a/lib/ofh/compression/iq_compression_bfp_impl.cpp +++ b/lib/ofh/compression/iq_compression_bfp_impl.cpp @@ -9,9 +9,10 @@ */ #include "iq_compression_bfp_impl.h" -#include "compressed_prb_packer.h" -#include "compressed_prb_unpacker.h" +#include "packing_utils_generic.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/srsvec/dot_prod.h" +#include "srsran/support/units.h" using namespace srsran; using namespace ofh; @@ -36,7 +37,7 @@ void iq_compression_bfp_impl::quantize_input(span out, span comp_prb_buffer, span input_quantized, unsigned data_width) { @@ -56,48 +57,60 @@ void iq_compression_bfp_impl::compress_prb_generic(compressed_prb& c_prb, compressed_samples[i] = input_quantized[i] >> exponent; } - c_prb.set_compression_param(exponent); + // Save exponent. + std::memcpy(comp_prb_buffer.data(), &exponent, sizeof(exponent)); + comp_prb_buffer = comp_prb_buffer.last(comp_prb_buffer.size() - sizeof(exponent)); - compressed_prb_packer packer(c_prb); - packer.pack(compressed_samples, data_width); + bit_buffer buffer = bit_buffer::from_bytes(comp_prb_buffer); + pack_bytes(buffer, compressed_samples, data_width); } -void iq_compression_bfp_impl::compress(span output, - span input, +void iq_compression_bfp_impl::compress(span buffer, + span iq_data, const ru_compression_params& params) { + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); span input_quantized_span(input_quantized.data(), float_samples_span.size()); // Performs conversion of input brain float values to signed 16-bit integers. quantize_input(input_quantized_span, float_samples_span); - unsigned sample_idx = 0; - for (auto& c_prb : output) { - const auto* start_it = input_quantized.begin() + sample_idx; + for (unsigned i = 0; i != nof_prbs; ++i) { + const auto* in_start_it = input_quantized.begin() + NOF_SAMPLES_PER_PRB * i; + auto* out_it = &buffer[i * prb_size]; // Compress one resource block. - compress_prb_generic(c_prb, {start_it, NOF_SAMPLES_PER_PRB}, params.data_width); - sample_idx += NOF_SAMPLES_PER_PRB; + compress_prb_generic({out_it, prb_size}, {in_start_it, NOF_SAMPLES_PER_PRB}, params.data_width); } } -void iq_compression_bfp_impl::decompress_prb_generic(span output, - const compressed_prb& c_prb, - const quantizer& q_in, - unsigned data_width) +void iq_compression_bfp_impl::decompress_prb_generic(span output, + span comp_prb, + const quantizer& q_in, + unsigned data_width) { // Quantizer. quantizer q_out(Q_BIT_WIDTH); - uint8_t exponent = c_prb.get_compression_param(); + // Compute scaling factor, first byte contains the exponent. + uint8_t exponent = comp_prb[0]; int16_t scaler = 1 << exponent; - compressed_prb_unpacker unpacker(c_prb); + comp_prb = comp_prb.last(comp_prb.size() - sizeof(exponent)); + auto bit_buff_reader = bit_buffer_reader::from_bytes(comp_prb); + for (unsigned i = 0, read_pos = 0; i != NOF_SUBCARRIERS_PER_RB; ++i) { - int16_t re = q_in.sign_extend(unpacker.unpack(read_pos, data_width)); - int16_t im = q_in.sign_extend(unpacker.unpack(read_pos + data_width, data_width)); + int16_t re = q_in.sign_extend(unpack_bits(bit_buff_reader, read_pos, data_width)); + int16_t im = q_in.sign_extend(unpack_bits(bit_buff_reader, read_pos + data_width, data_width)); read_pos += (data_width * 2); float scaled_re = q_out.to_float(re * scaler); @@ -106,18 +119,30 @@ void iq_compression_bfp_impl::decompress_prb_generic(span outpu } } -void iq_compression_bfp_impl::decompress(span output, - span input, +void iq_compression_bfp_impl::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Quantizer. quantizer q_in(params.data_width); + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + unsigned out_idx = 0; - for (const auto& c_prb : input) { - span out_rb_samples = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + for (unsigned c_prb_idx = 0; c_prb_idx != nof_prbs; ++c_prb_idx) { + span comp_prb(&compressed_data[c_prb_idx * prb_size], prb_size); + + span out_prb_samples = iq_data.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); // Decompress resource block. - decompress_prb_generic(out_rb_samples, c_prb, q_in, params.data_width); + decompress_prb_generic(out_prb_samples, comp_prb, q_in, params.data_width); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_bfp_impl.h b/lib/ofh/compression/iq_compression_bfp_impl.h index ad19e646a6..6524c158c2 100644 --- a/lib/ofh/compression/iq_compression_bfp_impl.h +++ b/lib/ofh/compression/iq_compression_bfp_impl.h @@ -13,6 +13,7 @@ #include "quantizer.h" #include "srsran/ofh/compression/iq_compressor.h" #include "srsran/ofh/compression/iq_decompressor.h" +#include "srsran/ran/resource_block.h" #include "srsran/srslog/logger.h" namespace srsran { @@ -30,11 +31,11 @@ class iq_compression_bfp_impl : public iq_compressor, public iq_decompressor // See interface for the documentation. virtual void - compress(span output, span input, const ru_compression_params& params) override; + compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. virtual void - decompress(span output, span input, const ru_compression_params& params) override; + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; protected: /// Number of quantized samples per resource block. @@ -70,17 +71,17 @@ class iq_compression_bfp_impl : public iq_compressor, public iq_decompressor /// \param[out] c_prb Compressed PRB. /// \param input_quantized Span of quantized IQ samples of a resource block to be compressed. /// \param data_width BFP compression bit width. - static void compress_prb_generic(compressed_prb& c_prb, span input_quantized, unsigned data_width); + static void compress_prb_generic(span c_prb, span input_quantized, unsigned data_width); /// \brief Decompresses one resource block using a generic implementation of the algorithm /// from O-RAN.WG4.CUS, Annex A.1.3. /// - /// \param[out] output Span of decompressed complex samples of a resource block (12 samples). - /// \param[in] c_prb Compressed PRB. - /// \param[in] q Quantizer object. - /// \param data_width Bit width of compressed samples. + /// \param[out] output Span of decompressed complex samples of a resource block (12 samples). + /// \param[in] comp_prb Compressed PRB IQ samples and compression parameter. + /// \param[in] q Quantizer object. + /// \param data_width Bit width of compressed samples. static void - decompress_prb_generic(span output, const compressed_prb& c_prb, const quantizer& q, unsigned data_width); + decompress_prb_generic(span output, span comp_prb, const quantizer& q, unsigned data_width); /// Quantizes complex float samples using the specified bit width. /// diff --git a/lib/ofh/compression/iq_compression_bfp_neon.cpp b/lib/ofh/compression/iq_compression_bfp_neon.cpp index 35533c9a33..27b0069871 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.cpp +++ b/lib/ofh/compression/iq_compression_bfp_neon.cpp @@ -12,6 +12,7 @@ #include "neon_helpers.h" #include "packing_utils_neon.h" #include "quantizer.h" +#include "srsran/ofh/compression/compression_properties.h" using namespace srsran; using namespace ofh; @@ -59,16 +60,24 @@ static inline void shift_right_x3vector_s16(int16x8x3_t src, int16x8x3_t& dst, u } } -void iq_compression_bfp_neon::compress(span output, - span input, +void iq_compression_bfp_neon::compress(span buffer, + span iq_data, const ru_compression_params& params) { // Use generic implementation if NEON utils don't support requested bit width. if (!neon::iq_width_packing_supported(params.data_width)) { - iq_compression_bfp_impl::compress(output, input, params); + iq_compression_bfp_impl::compress(buffer, iq_data, params); return; } + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; @@ -86,7 +95,7 @@ void iq_compression_bfp_neon::compress(span output, // registers to process one PRB. // // The loop below processes four resource blocks at a time. - for (size_t rb_index_end = (output.size() / 4) * 4; rb != rb_index_end; rb += 4) { + for (size_t rb_index_end = (nof_prbs / 4) * 4; rb != rb_index_end; rb += 4) { // Load samples. int16x8x3_t vec_s16x3_0 = vld1q_s16_x3(&input_quantized[sample_idx]); int16x8x3_t vec_s16x3_1 = vld1q_s16_x3(&input_quantized[sample_idx + NOF_SAMPLES_PER_PRB]); @@ -112,21 +121,32 @@ void iq_compression_bfp_neon::compress(span output, shift_right_x3vector_s16(vec_s16x3_2, shifted_data_2, exponent_2); shift_right_x3vector_s16(vec_s16x3_3, shifted_data_3, exponent_3); - // Pack compressed samples of the PRB using utility function and save the exponent. - neon::pack_prb_big_endian(output[rb], shifted_data_0, params.data_width); - output[rb].set_compression_param(exponent_0); - neon::pack_prb_big_endian(output[rb + 1], shifted_data_1, params.data_width); - output[rb + 1].set_compression_param(exponent_1); - neon::pack_prb_big_endian(output[rb + 2], shifted_data_2, params.data_width); - output[rb + 2].set_compression_param(exponent_2); - neon::pack_prb_big_endian(output[rb + 3], shifted_data_3, params.data_width); - output[rb + 3].set_compression_param(exponent_3); + // Pack compressed samples of the PRBs using utility function and save the exponent. + span output_span(&buffer[rb * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent_0, sizeof(uint8_t)); + neon::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data_0, params.data_width); + + output_span = span(&buffer[(rb + 1) * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent_1, sizeof(uint8_t)); + neon::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data_1, params.data_width); + + output_span = span(&buffer[(rb + 2) * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent_2, sizeof(uint8_t)); + neon::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data_2, params.data_width); + + output_span = span(&buffer[(rb + 3) * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent_3, sizeof(uint8_t)); + neon::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data_3, params.data_width); sample_idx += (4 * NOF_SAMPLES_PER_PRB); } // The loop below processes two resource blocks at a time. - for (size_t rb_index_end = (output.size() / 2) * 2; rb != rb_index_end; rb += 2) { + for (size_t rb_index_end = (nof_prbs / 2) * 2; rb != rb_index_end; rb += 2) { // Load samples. int16x8x3_t vec_s16x3_0 = vld1q_s16_x3(&input_quantized[sample_idx]); int16x8x3_t vec_s16x3_1 = vld1q_s16_x3(&input_quantized[sample_idx + NOF_SAMPLES_PER_PRB]); @@ -144,19 +164,23 @@ void iq_compression_bfp_neon::compress(span output, shift_right_x3vector_s16(vec_s16x3_0, shifted_data_0, exponent_0); shift_right_x3vector_s16(vec_s16x3_1, shifted_data_1, exponent_1); - // Pack compressed samples of the PRB using utility function. - neon::pack_prb_big_endian(output[rb], shifted_data_0, params.data_width); - // Save exponent. - output[rb].set_compression_param(exponent_0); + // Save exponent of the first compressed PRB and pack its compressed IQ samples using utility function. + span output_span(&buffer[rb * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent_0, sizeof(uint8_t)); + neon::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data_0, params.data_width); - neon::pack_prb_big_endian(output[rb + 1], shifted_data_1, params.data_width); - output[rb + 1].set_compression_param(exponent_1); + // Save exponent of the first compressed PRB and pack its compressed IQ samples using utility function. + output_span = span(&buffer[(rb + 1) * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent_1, sizeof(uint8_t)); + neon::pack_prb_big_endian( + output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data_1, params.data_width); sample_idx += (2 * NOF_SAMPLES_PER_PRB); } // Process the last resource block. - if (rb != output.size()) { + if (rb != nof_prbs) { // Load samples. int16x8x3_t vec_s16x3 = vld1q_s16_x3(&input_quantized[sample_idx]); @@ -170,40 +194,49 @@ void iq_compression_bfp_neon::compress(span output, int16x8x3_t shifted_data; shift_right_x3vector_s16(vec_s16x3, shifted_data, exponent); - // Pack compressed samples of the PRB using utility function. - neon::pack_prb_big_endian(output[rb], shifted_data, params.data_width); - // Save exponent. - output[rb].set_compression_param(exponent); + // Save exponent of the compressed PRB and pack its compressed IQ samples using utility function. + span output_span(&buffer[rb * prb_size], prb_size); + std::memcpy(output_span.data(), &exponent, sizeof(uint8_t)); + neon::pack_prb_big_endian(output_span.last(output_span.size() - sizeof(uint8_t)), shifted_data, params.data_width); sample_idx += NOF_SAMPLES_PER_PRB; ++rb; } - - // Use generic implementation if the requested compression width is not supported by neon utils. - for (; rb != output.size(); ++rb) { - const auto* start_it = input_quantized.begin() + sample_idx; - compress_prb_generic(output[rb], {start_it, NOF_SAMPLES_PER_PRB}, params.data_width); - sample_idx += NOF_SAMPLES_PER_PRB; - } } -void iq_compression_bfp_neon::decompress(span output, - span input, +void iq_compression_bfp_neon::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Use generic implementation if NEON utils don't support requested bit width. if (!neon::iq_width_packing_supported(params.data_width)) { - iq_compression_bfp_impl::decompress(output, input, params); + iq_compression_bfp_impl::decompress(iq_data, compressed_data, params); return; } + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned comp_prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * comp_prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + quantizer q_out(Q_BIT_WIDTH); unsigned out_idx = 0; - for (const compressed_prb& c_prb : input) { - // Compute scaling factor. - uint8_t exponent = c_prb.get_compression_param(); - int16_t scaler = 1 << exponent; + for (unsigned c_prb_idx = 0; c_prb_idx != nof_prbs; ++c_prb_idx) { + // Get view over compressed PRB bytes. + span comp_prb_buffer(&compressed_data[c_prb_idx * comp_prb_size], comp_prb_size); + + // Compute scaling factor, first byte contains the exponent. + uint8_t exponent = comp_prb_buffer[0]; + float scaler = 1 << exponent; + + // Get view over the bytes following the compression parameter. + comp_prb_buffer = comp_prb_buffer.last(comp_prb_buffer.size() - sizeof(exponent)); // Determine array size so that NEON store operation doesn't write the data out of array bounds. constexpr size_t neon_size_iqs = 8; @@ -211,9 +244,9 @@ void iq_compression_bfp_neon::decompress(span output, alignas(64) std::array unpacked_iq_data; // Unpack resource block. - neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); + neon::unpack_prb_big_endian(unpacked_iq_data, comp_prb_buffer, params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = iq_data.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); // Convert to complex samples. diff --git a/lib/ofh/compression/iq_compression_bfp_neon.h b/lib/ofh/compression/iq_compression_bfp_neon.h index c2cb59dce7..e8c32c7fa8 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.h +++ b/lib/ofh/compression/iq_compression_bfp_neon.h @@ -26,10 +26,11 @@ class iq_compression_bfp_neon : public iq_compression_bfp_impl } // See interface for the documentation. - void compress(span output, span input, const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_death_impl.cpp b/lib/ofh/compression/iq_compression_death_impl.cpp index 35646b9456..1fcd72c4c9 100644 --- a/lib/ofh/compression/iq_compression_death_impl.cpp +++ b/lib/ofh/compression/iq_compression_death_impl.cpp @@ -14,7 +14,7 @@ using namespace srsran; using namespace ofh; -void iq_compression_death_impl::compress(span compressed_prbs, +void iq_compression_death_impl::compress(span buffer, span iq_data, const ru_compression_params& params) { @@ -22,7 +22,7 @@ void iq_compression_death_impl::compress(span compressed } void iq_compression_death_impl::decompress(span iq_data, - span compressed_prbs, + span compressed_data, const ru_compression_params& params) { report_error("Decompression type '{}' is not supported", to_string(params.type)); diff --git a/lib/ofh/compression/iq_compression_death_impl.h b/lib/ofh/compression/iq_compression_death_impl.h index cbaffed93e..bd53d185e2 100644 --- a/lib/ofh/compression/iq_compression_death_impl.h +++ b/lib/ofh/compression/iq_compression_death_impl.h @@ -23,14 +23,11 @@ class iq_compression_death_impl : public iq_compressor, public iq_decompressor { public: // See interface for documentation. - void compress(span compressed_prbs, - span iq_data, - const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for documentation. - void decompress(span iq_data, - span compressed_prbs, - const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_none_avx2.cpp b/lib/ofh/compression/iq_compression_none_avx2.cpp index f818d6685b..602637b841 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.cpp +++ b/lib/ofh/compression/iq_compression_none_avx2.cpp @@ -10,15 +10,16 @@ #include "iq_compression_none_avx2.h" #include "avx2_helpers.h" -#include "compressed_prb_packer.h" #include "packing_utils_avx2.h" +#include "packing_utils_generic.h" #include "quantizer.h" +#include "srsran/ofh/compression/compression_properties.h" using namespace srsran; using namespace ofh; -void iq_compression_none_avx2::compress(span output, - span input, +void iq_compression_none_avx2::compress(span buffer, + span iq_data, const ru_compression_params& params) { // Number of quantized samples per resource block. @@ -31,14 +32,22 @@ void iq_compression_none_avx2::compress(span output, // Use generic implementation if AVX512 utils don't support requested bit width. if (!mm256::iq_width_packing_supported(params.data_width)) { - iq_compression_none_impl::compress(output, input, params); + iq_compression_none_impl::compress(buffer, iq_data, params); return; } + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); span input_quantized_span(input_quantized.data(), float_samples_span.size()); q.to_fixed_point(input_quantized_span, float_samples_span, iq_scaling); @@ -47,8 +56,10 @@ void iq_compression_none_avx2::compress(span output, unsigned sample_idx = 0; unsigned rb = 0; // One AVX2 register stores 8 16-bit IQ pairs. We can process 2 PRBs at a time by using 3 AVX2 registers. - for (size_t rb_index_end = (output.size() / 2) * 2; rb != rb_index_end; rb += 2) { - span c_prbs = output.subspan(rb, 2); + for (size_t rb_index_end = (nof_prbs / 2) * 2; rb != rb_index_end; rb += 2) { + // Get view over bytes corresponding to two PRBs processed in this iteration. + span comp_prb0_buffer(&buffer[rb * prb_size], prb_size); + span comp_prb1_buffer(&buffer[(rb + 1) * prb_size], prb_size); // Load symbols. const auto* start_it = input_quantized.begin() + sample_idx; @@ -57,32 +68,46 @@ void iq_compression_none_avx2::compress(span output, __m256i rb1_epi16 = _mm256_loadu_si256(reinterpret_cast(start_it + AVX2_REG_SIZE * 2)); // Pack 2 PRBs using utility function and save compression parameters. - mm256::pack_prbs_big_endian(c_prbs, rb0_epi16, rb01_epi16, rb1_epi16, params.data_width); + mm256::pack_prbs_big_endian( + comp_prb0_buffer, comp_prb1_buffer, rb0_epi16, rb01_epi16, rb1_epi16, params.data_width); sample_idx += (NOF_SAMPLES_PER_PRB * 2); } // Use generic implementation for the remaining resource blocks. - for (; rb != output.size(); ++rb) { - compressed_prb_packer packer(output[rb]); - + for (; rb != nof_prbs; ++rb) { span input_quantized_last_rb(&input_quantized[sample_idx], NOF_SAMPLES_PER_PRB); - packer.pack(input_quantized_last_rb, params.data_width); + + // View over output bytes corresponding to the current PRB. + span out_compr_prb(&buffer[rb * prb_size], prb_size); + + bit_buffer bit_buf = bit_buffer::from_bytes(out_compr_prb); + pack_bytes(bit_buf, input_quantized_last_rb, params.data_width); sample_idx += NOF_SAMPLES_PER_PRB; } } -void iq_compression_none_avx2::decompress(span output, - span input, +void iq_compression_none_avx2::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Use generic implementation if AVX2 utils don't support requested bit width. if (!mm256::iq_width_packing_supported(params.data_width)) { - iq_compression_none_impl::decompress(output, input, params); + iq_compression_none_impl::decompress(iq_data, compressed_data, params); return; } + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned comp_prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * comp_prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + // Quantizer object. quantizer q(params.data_width); @@ -91,15 +116,17 @@ void iq_compression_none_avx2::decompress(span output, alignas(64) std::array unpacked_iq_data; unsigned idx = 0; - for (const auto& c_prb : input) { + for (unsigned rb = 0; rb != nof_prbs; ++rb) { + span comp_prb_buffer(&compressed_data[rb * comp_prb_size], comp_prb_size); + // Unpack resource block. span unpacked_prb_span(&unpacked_iq_data[idx], prb_size); - mm256::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm256::unpack_prb_big_endian(unpacked_prb_span, comp_prb_buffer, params.data_width); idx += (NOF_SUBCARRIERS_PER_RB * 2); } - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_int16_span(unpacked_iq_data.data(), iq_data.size() * 2); // Convert to complex brain float samples. - q.to_brain_float(output, unpacked_iq_int16_span, 1); + q.to_brain_float(iq_data, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_avx2.h b/lib/ofh/compression/iq_compression_none_avx2.h index 75146657fb..d72f09759d 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.h +++ b/lib/ofh/compression/iq_compression_none_avx2.h @@ -26,10 +26,11 @@ class iq_compression_none_avx2 : public iq_compression_none_impl } // See interface for the documentation. - void compress(span output, span input, const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_none_avx512.cpp b/lib/ofh/compression/iq_compression_none_avx512.cpp index dac64caa52..5d8d102b4d 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.cpp +++ b/lib/ofh/compression/iq_compression_none_avx512.cpp @@ -10,16 +10,15 @@ #include "iq_compression_none_avx512.h" #include "avx512_helpers.h" -#include "compressed_prb_packer.h" #include "packing_utils_avx512.h" #include "quantizer.h" -#include "srsran/srsvec/dot_prod.h" +#include "srsran/ofh/compression/compression_properties.h" using namespace srsran; using namespace ofh; -void iq_compression_none_avx512::compress(span output, - span input, +void iq_compression_none_avx512::compress(span buffer, + span iq_data, const ru_compression_params& params) { // Number of quantized samples per resource block. @@ -30,60 +29,82 @@ void iq_compression_none_avx512::compress(span output, // Use generic implementation if AVX512 utils don't support requested bit width. if (!mm512::iq_width_packing_supported(params.data_width)) { - iq_compression_none_impl::compress(output, input, params); + iq_compression_none_impl::compress(buffer, iq_data, params); return; } + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); - span input_quantized_span(input_quantized.data(), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); + span input_quantized_span(input_quantized.data(), iq_data.size() * 2U); q.to_fixed_point(input_quantized_span, float_samples_span, iq_scaling); log_post_quantization_rms(input_quantized_span); unsigned sample_idx = 0; - unsigned rb = 0; const __mmask32 load_mask = 0x00ffffff; // Process one PRB at a time. - for (size_t rb_index_end = output.size(); rb != rb_index_end; ++rb) { + for (unsigned rb = 0; rb != nof_prbs; ++rb) { + // View over output bytes corresponding to the current PRB. + span out_compr_prb(&buffer[rb * prb_size], prb_size); + // Load 16-bit IQ samples from non-aligned memory. __m512i rb_epi16 = _mm512_maskz_loadu_epi16(load_mask, &input_quantized[sample_idx]); // Pack using utility function. - mm512::pack_prb_big_endian(output[rb], rb_epi16, params.data_width); + mm512::pack_prb_big_endian(out_compr_prb, rb_epi16, params.data_width); sample_idx += NOF_SAMPLES_PER_PRB; } } -void iq_compression_none_avx512::decompress(span output, - span input, +void iq_compression_none_avx512::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Use generic implementation if AVX512 utils don't support requested bit width. if (!mm512::iq_width_packing_supported(params.data_width)) { - iq_compression_none_impl::decompress(output, input, params); + iq_compression_none_impl::decompress(iq_data, compressed_data, params); return; } + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned comp_prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * comp_prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + // Quantizer object. quantizer q_out(params.data_width); std::array unpacked_iq_data; unsigned idx = 0; - for (const compressed_prb& c_prb : input) { + for (unsigned rb = 0; rb != nof_prbs; ++rb) { + span comp_prb_buffer(&compressed_data[rb * comp_prb_size], comp_prb_size); + // Unpack resource block. span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); - mm512::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + mm512::unpack_prb_big_endian(unpacked_prb_span, comp_prb_buffer, params.data_width); idx += (NOF_SUBCARRIERS_PER_RB * 2); } - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_int16_span(unpacked_iq_data.data(), iq_data.size() * 2); // Convert to complex brain float samples. - q_out.to_brain_float(output, unpacked_iq_int16_span, 1); + q_out.to_brain_float(iq_data, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_avx512.h b/lib/ofh/compression/iq_compression_none_avx512.h index 6dcb60301e..a9e1103337 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.h +++ b/lib/ofh/compression/iq_compression_none_avx512.h @@ -26,10 +26,11 @@ class iq_compression_none_avx512 : public iq_compression_none_impl } // See interface for the documentation. - void compress(span output, span input, const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_none_impl.cpp b/lib/ofh/compression/iq_compression_none_impl.cpp index f2dd72253b..f170937ff6 100644 --- a/lib/ofh/compression/iq_compression_none_impl.cpp +++ b/lib/ofh/compression/iq_compression_none_impl.cpp @@ -9,51 +9,74 @@ */ #include "iq_compression_none_impl.h" -#include "compressed_prb_packer.h" -#include "compressed_prb_unpacker.h" +#include "packing_utils_generic.h" #include "quantizer.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/srsvec/dot_prod.h" +#include "srsran/support/units.h" using namespace srsran; using namespace ofh; -void iq_compression_none_impl::compress(span output, - span input, +void iq_compression_none_impl::compress(span buffer, + span iq_data, const ru_compression_params& params) { // Quantizer object. quantizer q(params.data_width); - span float_samples(reinterpret_cast(input.data()), input.size() * 2); + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + + span float_samples(reinterpret_cast(iq_data.data()), iq_data.size() * 2); unsigned in_sample_idx = 0; - for (compressed_prb& c_prb : output) { - // Auxiliary buffer used for float to int16_t conversion. + for (unsigned rb = 0; rb != nof_prbs; ++rb) { + // Auxiliary buffer used for brain float to int16_t conversion. std::array conv_buffer; // Scale input IQ data to the range [-1: +1) and convert it to int16_t. q.to_fixed_point(conv_buffer, float_samples.subspan(in_sample_idx, NOF_SUBCARRIERS_PER_RB * 2), iq_scaling); - compressed_prb_packer packer(c_prb); - packer.pack(conv_buffer, params.data_width); + // View over output bytes corresponding to the current PRB. + span out_compr_prb(&buffer[rb * prb_size], prb_size); + + bit_buffer bit_buf = bit_buffer::from_bytes(out_compr_prb); + pack_bytes(bit_buf, conv_buffer, params.data_width); in_sample_idx += (NOF_SUBCARRIERS_PER_RB * 2); } } void iq_compression_none_impl::decompress(span output, - span input, + span input, const ru_compression_params& params) { // Quantizer object. quantizer q(params.data_width); + // Number of output PRBs. + unsigned nof_prbs = output.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert( + input.size() >= nof_prbs * prb_size, "Input does not contain enough bytes to decompress {} PRBs", nof_prbs); + unsigned out_idx = 0; - for (const auto& c_prb : input) { - compressed_prb_unpacker unpacker(c_prb); + for (unsigned c_prb_idx = 0, e = nof_prbs; c_prb_idx != e; ++c_prb_idx) { + span c_prb(&input[c_prb_idx * prb_size], prb_size); + + bit_buffer_reader bits_reader = bit_buffer_reader::from_bytes(c_prb); for (unsigned i = 0, read_pos = 0; i != NOF_SUBCARRIERS_PER_RB; ++i) { - int16_t re = q.sign_extend(unpacker.unpack(read_pos, params.data_width)); - int16_t im = q.sign_extend(unpacker.unpack(read_pos + params.data_width, params.data_width)); + int16_t re = q.sign_extend(unpack_bits(bits_reader, read_pos, params.data_width)); + int16_t im = q.sign_extend(unpack_bits(bits_reader, read_pos + params.data_width, params.data_width)); read_pos += (params.data_width * 2); output[out_idx++] = {q.to_float(re), q.to_float(im)}; } diff --git a/lib/ofh/compression/iq_compression_none_impl.h b/lib/ofh/compression/iq_compression_none_impl.h index 54a654515c..26a6a969c9 100644 --- a/lib/ofh/compression/iq_compression_none_impl.h +++ b/lib/ofh/compression/iq_compression_none_impl.h @@ -29,11 +29,11 @@ class iq_compression_none_impl : public iq_compressor, public iq_decompressor // See interface for the documentation. virtual void - compress(span output, span input, const ru_compression_params& params) override; + compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. virtual void - decompress(span output, span input, const ru_compression_params& params) override; + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; protected: /// \brief Prints to the log the root mean square (RMS) value of the given samples. diff --git a/lib/ofh/compression/iq_compression_none_neon.cpp b/lib/ofh/compression/iq_compression_none_neon.cpp index 38182270c1..e4486c6393 100644 --- a/lib/ofh/compression/iq_compression_none_neon.cpp +++ b/lib/ofh/compression/iq_compression_none_neon.cpp @@ -9,37 +9,45 @@ */ #include "iq_compression_none_neon.h" -#include "compressed_prb_packer.h" #include "neon_helpers.h" #include "packing_utils_neon.h" #include "quantizer.h" +#include "srsran/ofh/compression/compression_properties.h" using namespace srsran; using namespace ofh; -void iq_compression_none_neon::compress(span output, - span input, - const srsran::ofh::ru_compression_params& params) +void iq_compression_none_neon::compress(span buffer, + span iq_data, + const ru_compression_params& params) { // Number of quantized samples per resource block. static constexpr size_t NOF_SAMPLES_PER_PRB = 2 * NOF_SUBCARRIERS_PER_RB; // Use generic implementation if NEON utils don't support requested bit width. if (!neon::iq_width_packing_supported(params.data_width)) { - iq_compression_none_impl::compress(output, input, params); + iq_compression_none_impl::compress(buffer, iq_data, params); return; } + // Number of input PRBs. + unsigned nof_prbs = (iq_data.size() / NOF_SUBCARRIERS_PER_RB); + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(buffer.size() >= prb_size * nof_prbs, "Output buffer doesn't have enough space to decompress PRBs"); + // Quantizer object. quantizer q(params.data_width); // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); span input_quantized_span(input_quantized.data(), float_samples_span.size()); - q.to_fixed_point(input_quantized_span, float_samples_span, iq_scaling); + q.to_fixed_point(input_quantized_span, float_samples_span, iq_scaling); log_post_quantization_rms(input_quantized_span); unsigned sample_idx = 0; @@ -48,7 +56,7 @@ void iq_compression_none_neon::compress(span // registers to process one PRB. // // The loop below processes four resource blocks at a time. - for (size_t rb_index_end = (output.size() / 4) * 4; rb != rb_index_end; rb += 4) { + for (size_t rb_index_end = (nof_prbs / 4) * 4; rb != rb_index_end; rb += 4) { // Load samples. int16x8x3_t vec_s16x3_0 = vld1q_s16_x3(&input_quantized[sample_idx]); int16x8x3_t vec_s16x3_1 = vld1q_s16_x3(&input_quantized[sample_idx + NOF_SAMPLES_PER_PRB]); @@ -56,69 +64,74 @@ void iq_compression_none_neon::compress(span int16x8x3_t vec_s16x3_3 = vld1q_s16_x3(&input_quantized[sample_idx + NOF_SAMPLES_PER_PRB * 3]); // Pack samples of the PRB using utility function. - neon::pack_prb_big_endian(output[rb], vec_s16x3_0, params.data_width); - neon::pack_prb_big_endian(output[rb + 1], vec_s16x3_1, params.data_width); - neon::pack_prb_big_endian(output[rb + 2], vec_s16x3_2, params.data_width); - neon::pack_prb_big_endian(output[rb + 3], vec_s16x3_3, params.data_width); + neon::pack_prb_big_endian({&buffer[rb * prb_size], prb_size}, vec_s16x3_0, params.data_width); + neon::pack_prb_big_endian({&buffer[(rb + 1) * prb_size], prb_size}, vec_s16x3_1, params.data_width); + neon::pack_prb_big_endian({&buffer[(rb + 2) * prb_size], prb_size}, vec_s16x3_2, params.data_width); + neon::pack_prb_big_endian({&buffer[(rb + 3) * prb_size], prb_size}, vec_s16x3_3, params.data_width); sample_idx += (4 * NOF_SAMPLES_PER_PRB); } // The loop below processes two resource blocks at a time. - for (size_t rb_index_end = (output.size() / 2) * 2; rb != rb_index_end; rb += 2) { + for (size_t rb_index_end = (nof_prbs / 2) * 2; rb != rb_index_end; rb += 2) { // Load samples. int16x8x3_t vec_s16x3_0 = vld1q_s16_x3(&input_quantized[sample_idx]); int16x8x3_t vec_s16x3_1 = vld1q_s16_x3(&input_quantized[sample_idx + NOF_SAMPLES_PER_PRB]); // Pack samples of the PRB using utility function. - neon::pack_prb_big_endian(output[rb], vec_s16x3_0, params.data_width); - neon::pack_prb_big_endian(output[rb + 1], vec_s16x3_1, params.data_width); + neon::pack_prb_big_endian({&buffer[rb * prb_size], prb_size}, vec_s16x3_0, params.data_width); + neon::pack_prb_big_endian({&buffer[(rb + 1) * prb_size], prb_size}, vec_s16x3_1, params.data_width); sample_idx += (2 * NOF_SAMPLES_PER_PRB); } // Process the last resource block. - if (rb != output.size()) { + if (rb != nof_prbs) { // Load samples. int16x8x3_t vec_s16x3 = vld1q_s16_x3(&input_quantized[sample_idx]); // Pack samples of the PRB using utility function. - neon::pack_prb_big_endian(output[rb], vec_s16x3, params.data_width); + neon::pack_prb_big_endian({&buffer[rb * prb_size], prb_size}, vec_s16x3, params.data_width); sample_idx += NOF_SAMPLES_PER_PRB; ++rb; } - - // Use generic implementation if the requested compression width is not supported by neon utils. - for (; rb != output.size(); ++rb) { - compressed_prb_packer packer(output[rb]); - packer.pack({&input_quantized[sample_idx], NOF_SAMPLES_PER_PRB}, params.data_width); - sample_idx += NOF_SAMPLES_PER_PRB; - } } -void iq_compression_none_neon::decompress(span output, - span input, +void iq_compression_none_neon::decompress(span iq_data, + span compressed_data, const ru_compression_params& params) { // Use generic implementation if NEON utils don't support requested bit width. if (!neon::iq_width_packing_supported(params.data_width)) { - iq_compression_none_impl::decompress(output, input, params); + iq_compression_none_impl::decompress(iq_data, compressed_data, params); return; } + // Number of output PRBs. + unsigned nof_prbs = iq_data.size() / NOF_SUBCARRIERS_PER_RB; + + // Size in bytes of one compressed PRB using the given compression parameters. + unsigned comp_prb_size = get_compressed_prb_size(params).value(); + + srsran_assert(compressed_data.size() >= nof_prbs * comp_prb_size, + "Input does not contain enough bytes to decompress {} PRBs", + nof_prbs); + quantizer q_out(params.data_width); std::array unpacked_iq_data; unsigned idx = 0; - for (const compressed_prb& c_prb : input) { + for (unsigned rb = 0; rb != nof_prbs; ++rb) { + span comp_prb_buffer(&compressed_data[rb * comp_prb_size], comp_prb_size); + // Unpack resource block. span unpacked_prb_span(&unpacked_iq_data[idx], NOF_SUBCARRIERS_PER_RB * 2); - neon::unpack_prb_big_endian(unpacked_prb_span, c_prb.get_packed_data(), params.data_width); + neon::unpack_prb_big_endian(unpacked_prb_span, comp_prb_buffer, params.data_width); idx += (NOF_SUBCARRIERS_PER_RB * 2); } - span unpacked_iq_int16_span(unpacked_iq_data.data(), output.size() * 2); + span unpacked_iq_int16_span(unpacked_iq_data.data(), iq_data.size() * 2); // Convert to complex brain float samples. - q_out.to_brain_float(output, unpacked_iq_int16_span, 1); + q_out.to_brain_float(iq_data, unpacked_iq_int16_span, 1); } diff --git a/lib/ofh/compression/iq_compression_none_neon.h b/lib/ofh/compression/iq_compression_none_neon.h index b91440e04c..211b25b3f2 100644 --- a/lib/ofh/compression/iq_compression_none_neon.h +++ b/lib/ofh/compression/iq_compression_none_neon.h @@ -26,10 +26,11 @@ class iq_compression_none_neon : public iq_compression_none_impl } // See interface for the documentation. - void compress(span output, span input, const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compressor_selector.cpp b/lib/ofh/compression/iq_compressor_selector.cpp index f3548079a9..9edf2cdaf0 100644 --- a/lib/ofh/compression/iq_compressor_selector.cpp +++ b/lib/ofh/compression/iq_compressor_selector.cpp @@ -26,10 +26,10 @@ iq_compressor_selector::iq_compressor_selector( } } -void iq_compressor_selector::compress(span compressed_prbs, +void iq_compressor_selector::compress(span buffer, span iq_data, const ru_compression_params& params) { auto& compressor = compressors[static_cast(params.type)]; - compressor->compress(compressed_prbs, iq_data, params); + compressor->compress(buffer, iq_data, params); } diff --git a/lib/ofh/compression/iq_compressor_selector.h b/lib/ofh/compression/iq_compressor_selector.h index f9feda16a8..13ff6cdc23 100644 --- a/lib/ofh/compression/iq_compressor_selector.h +++ b/lib/ofh/compression/iq_compressor_selector.h @@ -26,9 +26,7 @@ class iq_compressor_selector : public iq_compressor std::array, NOF_COMPRESSION_TYPES_SUPPORTED> compressors_); // See interface for documentation. - void compress(span compressed_prbs, - span iq_data, - const ru_compression_params& params) override; + void compress(span buffer, span iq_data, const ru_compression_params& params) override; private: std::array, NOF_COMPRESSION_TYPES_SUPPORTED> compressors; diff --git a/lib/ofh/compression/iq_decompressor_selector.cpp b/lib/ofh/compression/iq_decompressor_selector.cpp index 68147683e6..cd41e58fab 100644 --- a/lib/ofh/compression/iq_decompressor_selector.cpp +++ b/lib/ofh/compression/iq_decompressor_selector.cpp @@ -27,8 +27,8 @@ iq_decompressor_selector::iq_decompressor_selector( } void iq_decompressor_selector::decompress(span iq_data, - span compressed_prbs, + span compressed_data, const ru_compression_params& params) { - return decompressors[static_cast(params.type)]->decompress(iq_data, compressed_prbs, params); + return decompressors[static_cast(params.type)]->decompress(iq_data, compressed_data, params); } diff --git a/lib/ofh/compression/iq_decompressor_selector.h b/lib/ofh/compression/iq_decompressor_selector.h index e54a85bd79..a1ef595106 100644 --- a/lib/ofh/compression/iq_decompressor_selector.h +++ b/lib/ofh/compression/iq_decompressor_selector.h @@ -26,9 +26,8 @@ class iq_decompressor_selector : public iq_decompressor std::array, NOF_COMPRESSION_TYPES_SUPPORTED> decompressors_); // See interface for documentation. - void decompress(span iq_data, - span compressed_prbs, - const ru_compression_params& params) override; + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override; private: std::array, NOF_COMPRESSION_TYPES_SUPPORTED> decompressors; diff --git a/lib/ofh/compression/packing_utils_avx2.h b/lib/ofh/compression/packing_utils_avx2.h index c85ba85bd1..951a59bc7e 100644 --- a/lib/ofh/compression/packing_utils_avx2.h +++ b/lib/ofh/compression/packing_utils_avx2.h @@ -11,7 +11,6 @@ #pragma once #include "srsran/adt/span.h" -#include "srsran/ofh/compression/compressed_prb.h" #include "srsran/support/error_handling.h" #include @@ -78,16 +77,24 @@ inline __m256i pack_avx2_register_9b_be(__m256i cmp_data_epi16) /// | \c r1: | RB0 RB0 | RB0 RB0 | RB1 RB1 | RB1 RB1 | /// | \c r2: | RB1 RB1 | RB1 RB1 | RB1 RB1 | RB1 RB1 | /// -/// \param[out] c_prbs Span of two compressed PRBs. -/// \param[in] r0 AVX2 register storing 16bit IQ samples of the first RB. -/// \param[in] r1 AVX2 register storing 16bit IQ samples of the first and second RB. -/// \param[in] r2 AVX2 register storing 16bit IQ samples of the second RB. -inline void avx2_pack_prbs_9b_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2) +/// \param[out] comp_prb0_buffer Buffer dedicated for storing compressed packed bytes of the first PRB. +/// \param[out] comp_prb1_buffer Buffer dedicated for storing compressed packed bytes of the second PRB. +/// \param[in] r0 AVX2 register storing 16bit IQ samples of the first RB. +/// \param[in] r1 AVX2 register storing 16bit IQ samples of the first and second RB. +/// \param[in] r2 AVX2 register storing 16bit IQ samples of the second RB. +inline void avx2_pack_prbs_9b_big_endian(span comp_prb0_buffer, + span comp_prb1_buffer, + __m256i r0, + __m256i r1, + __m256i r2) { /// Number of bytes used by 1 packed resource block with IQ samples compressed to 9 bits. static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; - srsran_assert(c_prbs.size() == 2, "Output span must contain 2 resource blocks"); + srsran_assert(comp_prb0_buffer.size() == BYTES_PER_PRB_9BIT_COMPRESSION, + "Output buffer corresponding to the first PRB has incorrect size"); + srsran_assert(comp_prb1_buffer.size() == BYTES_PER_PRB_9BIT_COMPRESSION, + "Output buffer corresponding to the second PRB has incorrect size"); // Returns first 18 packed bytes out of 27 for the first RB (9 bytes in each 128bit lane - same applies below). __m256i reg0_packed_epi8 = pack_avx2_register_9b_be(r0); @@ -142,12 +149,13 @@ inline void avx2_pack_prbs_9b_big_endian(span c_prbs, __m256i r0 __m256i prb1_tmp1_epi8 = _mm256_or_si256(reg2_tmp0_epi8, reg2_tmp1_epi8); __m256i prb1_epi8 = _mm256_blendv_epi8(prb1_tmp0_epi8, prb1_tmp1_epi8, sel_mask_1_epi8); - // Write resource blocks to the memory. - _mm256_storeu_si256(reinterpret_cast<__m256i*>(c_prbs[0].get_byte_buffer().data()), prb0_epi8); - c_prbs[0].set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); + // Write the compressed resource blocks to the memory. + uint8_t avx2_tmp_buffer[32]; + _mm256_storeu_si256(reinterpret_cast<__m256i*>(avx2_tmp_buffer), prb0_epi8); + std::memcpy(comp_prb0_buffer.data(), avx2_tmp_buffer, BYTES_PER_PRB_9BIT_COMPRESSION); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(c_prbs[1].get_byte_buffer().data()), prb1_epi8); - c_prbs[1].set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(avx2_tmp_buffer), prb1_epi8); + std::memcpy(comp_prb1_buffer.data(), avx2_tmp_buffer, BYTES_PER_PRB_9BIT_COMPRESSION); } /// \brief Packs 16bit IQ values of the two input RBs using 16bit big-endian format. @@ -160,16 +168,24 @@ inline void avx2_pack_prbs_9b_big_endian(span c_prbs, __m256i r0 /// | \c r1: | RB0 RB0 | RB0 RB0 | RB1 RB1 | RB1 RB1 | /// | \c r2: | RB1 RB1 | RB1 RB1 | RB1 RB1 | RB1 RB1 | /// -/// \param[out] c_prbs Span of two compressed PRBs. -/// \param[in] r0 AVX2 register storing 16bit IQ samples of the first RB. -/// \param[in] r1 AVX2 register storing 16bit IQ samples of the first and second RB. -/// \param[in] r2 AVX2 register storing 16bit IQ samples of the second RB. -inline void avx2_pack_prbs_16b_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2) +/// \param[out] comp_prb0_buffer Buffer dedicated for storing compressed packed bytes of the first PRB. +/// \param[out] comp_prb1_buffer Buffer dedicated for storing compressed packed bytes of the second PRB. +/// \param[in] r0 AVX2 register storing 16bit IQ samples of the first RB. +/// \param[in] r1 AVX2 register storing 16bit IQ samples of the first and second RB. +/// \param[in] r2 AVX2 register storing 16bit IQ samples of the second RB. +inline void avx2_pack_prbs_16b_big_endian(span comp_prb0_buffer, + span comp_prb1_buffer, + __m256i r0, + __m256i r1, + __m256i r2) { - srsran_assert(c_prbs.size() == 2, "Output span must contain 2 resource blocks"); - static constexpr unsigned BYTES_PER_PRB_NO_COMPRESSION = 48; + srsran_assert(comp_prb0_buffer.size() == BYTES_PER_PRB_NO_COMPRESSION, + "Output buffer corresponding to the first PRB has incorrect size"); + srsran_assert(comp_prb1_buffer.size() == BYTES_PER_PRB_NO_COMPRESSION, + "Output buffer corresponding to the second PRB has incorrect size"); + // Swap bytes to convert from big-endian format and write them directly to the output memory. const __m256i shuffle_mask_epi8 = _mm256_setr_epi64x(0x0607040502030001, 0x0e0f0c0d0a0b0809, 0x0607040502030001, 0x0e0f0c0d0a0b0809); @@ -178,20 +194,17 @@ inline void avx2_pack_prbs_16b_big_endian(span c_prbs, __m256i r __m256i reg1_swp_epi16 = _mm256_shuffle_epi8(r1, shuffle_mask_epi8); __m256i reg2_swp_epi16 = _mm256_shuffle_epi8(r2, shuffle_mask_epi8); - uint8_t* data = c_prbs[0].get_byte_buffer().data(); + uint8_t* data = comp_prb0_buffer.data(); _mm256_storeu_si256(reinterpret_cast<__m256i*>(data), reg0_swp_epi16); _mm256_maskstore_epi32(reinterpret_cast(data + 32), _mm256_setr_epi32(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0), reg1_swp_epi16); - data = c_prbs[1].get_byte_buffer().data(); + data = comp_prb1_buffer.data(); _mm_maskstore_epi32(reinterpret_cast(data), _mm_set_epi32(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff), _mm256_extracti128_si256(reg1_swp_epi16, 0x1)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(data + 16), reg2_swp_epi16); - - c_prbs[0].set_stored_size(BYTES_PER_PRB_NO_COMPRESSION); - c_prbs[1].set_stored_size(BYTES_PER_PRB_NO_COMPRESSION); } /// \brief Packs 16bit IQ values of the two RBs using the specified width and big-endian format. @@ -204,19 +217,24 @@ inline void avx2_pack_prbs_16b_big_endian(span c_prbs, __m256i r /// | \c r1: | RB0 RB0 | RB0 RB0 | RB1 RB1 | RB1 RB1 | /// | \c r2: | RB1 RB1 | RB1 RB1 | RB1 RB1 | RB1 RB1 | /// -/// \param[out] c_prbs Span of two output compressed PRBs storing packed bytes. -/// \param[in] r0 AVX2 register storing 16bit IQ pairs of the first PRB. -/// \param[in] r1 AVX2 register storing 16bit IQ pairs of the first and second PRB. -/// \param[in] r2 AVX2 register storing 16bit IQ pairs of the second PRB. -/// \param[in] iq_width Bit width of the resulting packed IQ samples. -inline void -pack_prbs_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2, unsigned iq_width) +/// \param[out] comp_prb0_buffer Buffer dedicated for storing compressed packed bytes of the first PRB. +/// \param[out] comp_prb1_buffer Buffer dedicated for storing compressed packed bytes of the second PRB. +/// \param[in] r0 AVX2 register storing 16bit IQ pairs of the first PRB. +/// \param[in] r1 AVX2 register storing 16bit IQ pairs of the first and second PRB. +/// \param[in] r2 AVX2 register storing 16bit IQ pairs of the second PRB. +/// \param[in] iq_width Bit width of the resulting packed IQ samples. +inline void pack_prbs_big_endian(span comp_prb0_buffer, + span comp_prb1_buffer, + __m256i r0, + __m256i r1, + __m256i r2, + unsigned iq_width) { switch (iq_width) { case 9: - return avx2_pack_prbs_9b_big_endian(c_prbs, r0, r1, r2); + return avx2_pack_prbs_9b_big_endian(comp_prb0_buffer, comp_prb1_buffer, r0, r1, r2); case 16: - return avx2_pack_prbs_16b_big_endian(c_prbs, r0, r1, r2); + return avx2_pack_prbs_16b_big_endian(comp_prb0_buffer, comp_prb1_buffer, r0, r1, r2); default: report_fatal_error("Unsupported bit width"); } @@ -235,7 +253,12 @@ inline void avx2_unpack_prb_9b_be(span unpacked_iq_data, span= avx2_size_short_words * 2, "Wrong unpacked data span size"); // Load input, 27 bytes (fits in one AVX2 register). - __m256i packed_data_epi8 = _mm256_loadu_si256(reinterpret_cast(packed_data.data())); + // Mask-load for epi8 is not available, so we do in a few steps. + __m128i packed_data_high = + _mm_srli_si128(_mm_loadu_si128(reinterpret_cast(packed_data.data() + 11)), 5); + __m128i packed_data_low = _mm_loadu_si128(reinterpret_cast(packed_data.data())); + __m256i packed_data_epi8 = _mm256_permute2f128_si256( + _mm256_castsi128_si256(packed_data_low), _mm256_castsi128_si256(packed_data_high), 0x20); // Duplicate input words (it is required since below in the code every byte will be used twice: // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). diff --git a/lib/ofh/compression/packing_utils_avx512.h b/lib/ofh/compression/packing_utils_avx512.h index fb00e6c372..7726484bde 100644 --- a/lib/ofh/compression/packing_utils_avx512.h +++ b/lib/ofh/compression/packing_utils_avx512.h @@ -11,7 +11,6 @@ #pragma once #include "avx512_helpers.h" -#include "srsran/ofh/compression/compressed_prb.h" #include "srsran/support/error_handling.h" namespace srsran { @@ -20,14 +19,17 @@ namespace mm512 { /// \brief Packs 16bit IQ values of the PRB as 9 bit values in big-endian format. /// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. -inline void avx512_pack_prb_9b_big_endian(compressed_prb& c_prb, __m512i reg) +/// \param[out] comp_prb_buffer Buffer dedicated for storing compressed packed bytes of the PRB. +/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. +inline void avx512_pack_prb_9b_big_endian(span comp_prb_buffer, __m512i reg) { static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; static constexpr unsigned bytes_per_lane = BYTES_PER_PRB_9BIT_COMPRESSION / 3; static constexpr unsigned lane_write_mask = 0x01ff; + srsran_assert(comp_prb_buffer.size() == BYTES_PER_PRB_9BIT_COMPRESSION, + "Output buffer has incorrect size for packing compressed samples"); + // Input IQ samples need to be shifted in order to align bits before final packing. // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 @@ -80,25 +82,28 @@ inline void avx512_pack_prb_9b_big_endian(compressed_prb& c_prb, __m512i reg) __m512i iq_packed_epi8 = _mm512_or_si512(tmp_iq_0_epi8, tmp_iq_1_epi8); // Store first 9 bytes of the first three 128bit lanes of the AVX512 register. - uint8_t* data = c_prb.get_byte_buffer().data(); + uint8_t* data = comp_prb_buffer.data(); _mm_mask_storeu_epi8(data, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 0)); _mm_mask_storeu_epi8(data + bytes_per_lane, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 1)); _mm_mask_storeu_epi8(data + bytes_per_lane * 2, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 2)); - - c_prb.set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); } /// \brief Packs 16bit IQ values of the PRB using big-endian format. /// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. -inline void avx512_pack_prb_16b_big_endian(compressed_prb& c_prb, __m512i reg) +/// \param[out] comp_prb_buffer Buffer dedicated for storing compressed packed bytes of the PRB. +/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. +inline void avx512_pack_prb_16b_big_endian(span comp_prb_buffer, __m512i reg) { - static constexpr unsigned BYTES_PER_PRB_NO_COMPRESSION = 48; - static constexpr unsigned write_mask = 0xffffff; + /// Number of bytes used by 1 packed PRB with IQ samples compressed to 16 bits. + static constexpr unsigned BYTES_PER_PRB_16BIT_COMPRESSION = 48; + + static constexpr unsigned write_mask = 0xffffff; + + srsran_assert(comp_prb_buffer.size() == BYTES_PER_PRB_16BIT_COMPRESSION, + "Output buffer has incorrect size for packing compressed samples"); // Input contains 24 16 bit Iand Q samples. - uint8_t* data = c_prb.get_byte_buffer().data(); + uint8_t* data = comp_prb_buffer.data(); // Swap bytes to convert from big-endian format and write them directly to the output memory. const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0607040502030001, @@ -112,21 +117,20 @@ inline void avx512_pack_prb_16b_big_endian(compressed_prb& c_prb, __m512i reg) __m512i reg_swp_epi16 = _mm512_shuffle_epi8(reg, shuffle_mask_epi8); _mm512_mask_storeu_epi16(data, write_mask, reg_swp_epi16); - c_prb.set_stored_size(BYTES_PER_PRB_NO_COMPRESSION); } /// \brief Packs 16bit IQ values of a resource block using the specified width and big-endian format. /// -/// \param[out] c_prb Output PRB storing compressed packed bytes. -/// \param[in] reg AVX512 register storing 16bit IQ pairs of the PRB. -/// \param[in] iq_width Bit width of the resulting packed IQ samples. -inline void pack_prb_big_endian(ofh::compressed_prb& c_prb, __m512i reg, unsigned iq_width) +/// \param[out] comp_prb_buffer Buffer dedicated for storing compressed packed bytes of the PRB. +/// \param[in] reg AVX512 register storing 16bit IQ pairs of the PRB. +/// \param[in] iq_width Bit width of the resulting packed IQ samples. +inline void pack_prb_big_endian(span comp_prb_buffer, __m512i reg, unsigned iq_width) { if (iq_width == 9) { - return avx512_pack_prb_9b_big_endian(c_prb, reg); + return avx512_pack_prb_9b_big_endian(comp_prb_buffer, reg); } if (iq_width == 16) { - return avx512_pack_prb_16b_big_endian(c_prb, reg); + return avx512_pack_prb_16b_big_endian(comp_prb_buffer, reg); } report_fatal_error("Unsupported bit width"); } diff --git a/lib/ofh/compression/compressed_prb_packer.cpp b/lib/ofh/compression/packing_utils_generic.cpp similarity index 50% rename from lib/ofh/compression/compressed_prb_packer.cpp rename to lib/ofh/compression/packing_utils_generic.cpp index f739c9916d..d633149753 100644 --- a/lib/ofh/compression/compressed_prb_packer.cpp +++ b/lib/ofh/compression/packing_utils_generic.cpp @@ -8,32 +8,27 @@ * */ -#include "compressed_prb_packer.h" -#include "srsran/support/units.h" +#include "packing_utils_generic.h" using namespace srsran; using namespace ofh; -void compressed_prb_packer::pack(span compressed_iq, unsigned iq_width) +void srsran::ofh::pack_bytes(bit_buffer& buffer, span compressed_iq, unsigned iq_width) { - srsran_assert(compressed_iq.size() == NOF_SUBCARRIERS_PER_RB * 2, "Compressed data must contain 12 IQ samples"); - srsran_assert(iq_width <= MAX_IQ_WIDTH, "Requested width can not exceed 16"); static constexpr unsigned NUM_BITS_IN_BYTE = units::bytes(1).to_bits().value(); - auto& bit_buffer = prb.get_bit_buffer(); - unsigned start_pos = 0; for (int16_t sample : compressed_iq) { unsigned left_to_pack = iq_width; while (left_to_pack != 0) { unsigned nbits = std::min(NUM_BITS_IN_BYTE, left_to_pack); - uint8_t masked = sample; + uint8_t masked = static_cast(sample & 0x00ff); if (left_to_pack > NUM_BITS_IN_BYTE) { masked = sample >> (left_to_pack - NUM_BITS_IN_BYTE); sample &= mask_lsb_ones(left_to_pack - NUM_BITS_IN_BYTE); } - bit_buffer.insert(masked, start_pos, nbits); + buffer.insert(masked, start_pos, nbits); start_pos += nbits; left_to_pack -= nbits; } @@ -42,9 +37,28 @@ void compressed_prb_packer::pack(span compressed_iq, unsigned iq_ // Clear tail bits of the last used byte. if (start_pos % NUM_BITS_IN_BYTE) { unsigned nbits = NUM_BITS_IN_BYTE - start_pos % NUM_BITS_IN_BYTE; - bit_buffer.insert(uint8_t(0), start_pos, nbits); + buffer.insert(uint8_t(0), start_pos, nbits); } +} + +int16_t srsran::ofh::unpack_bits(const bit_buffer_reader& buffer, unsigned offset, unsigned length) +{ + static constexpr unsigned NUM_BITS_IN_BYTE = units::bytes(1).to_bits().value(); - prb.set_stored_size((compressed_iq.size() * iq_width / NUM_BITS_IN_BYTE) + - ((compressed_iq.size() * iq_width % NUM_BITS_IN_BYTE) ? 1U : 0)); + int16_t value = 0; + unsigned bits_left_to_read = length; + + while (bits_left_to_read) { + if (bits_left_to_read > NUM_BITS_IN_BYTE) { + value = buffer.extract(offset, NUM_BITS_IN_BYTE); + value <<= (bits_left_to_read - NUM_BITS_IN_BYTE); + bits_left_to_read -= NUM_BITS_IN_BYTE; + offset += NUM_BITS_IN_BYTE; + continue; + } + + value |= buffer.extract(offset, bits_left_to_read); + bits_left_to_read = 0; + } + return value; } diff --git a/lib/ofh/compression/packing_utils_generic.h b/lib/ofh/compression/packing_utils_generic.h new file mode 100644 index 0000000000..f889666ef9 --- /dev/null +++ b/lib/ofh/compression/packing_utils_generic.h @@ -0,0 +1,27 @@ +/* + * + * 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/bit_buffer.h" +#include "srsran/adt/span.h" +#include "srsran/support/units.h" + +namespace srsran { +namespace ofh { + +/// Packs the given IQ samples into the given bit buffer object. +void pack_bytes(bit_buffer& buffer, span compressed_iq, unsigned iq_width); + +/// Extract \c length bits from the provided bit buffer starting from offset \c offset. +int16_t unpack_bits(const bit_buffer_reader& buffer, unsigned offset, unsigned length); + +} // namespace ofh +} // namespace srsran \ No newline at end of file diff --git a/lib/ofh/compression/packing_utils_neon.h b/lib/ofh/compression/packing_utils_neon.h index 835278981e..84c1ca53dd 100644 --- a/lib/ofh/compression/packing_utils_neon.h +++ b/lib/ofh/compression/packing_utils_neon.h @@ -11,7 +11,6 @@ #pragma once #include "neon_helpers.h" -#include "srsran/ofh/compression/compressed_prb.h" #include "srsran/support/error_handling.h" namespace srsran { @@ -58,23 +57,26 @@ inline uint8x16_t pack_neon_register_9b_big_endian(int16x8_t reg) /// \brief Packs 16bit IQ values of the PRB using given bit width and big-endian format. /// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] regs NEON registers storing 16bit IQ samples of the PRB. +/// \param[out] comp_prb_buffer Buffer dedicated for storing compressed packed bytes of the PRB. +/// \param[in] regs NEON registers storing 16bit IQ samples of the PRB. /// /// \note Each of the input registers stores four unique REs. -inline void pack_prb_9b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) +inline void pack_prb_9b_big_endian(span comp_prb_buffer, int16x8x3_t regs) { /// Number of bytes used by 1 packed PRB with IQ samples compressed to 9 bits. static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; static constexpr unsigned bytes_per_half_reg = 8; + srsran_assert(comp_prb_buffer.size() == BYTES_PER_PRB_9BIT_COMPRESSION, + "Output buffer has incorrect size for packing compressed samples"); + // Pack input registers. uint8x16_t res_packed_bytes_0_u8 = pack_neon_register_9b_big_endian(regs.val[0]); uint8x16_t res_packed_bytes_1_u8 = pack_neon_register_9b_big_endian(regs.val[1]); uint8x16_t res_packed_bytes_2_u8 = pack_neon_register_9b_big_endian(regs.val[2]); - uint8_t* data = c_prb.get_byte_buffer().data(); + uint8_t* data = comp_prb_buffer.data(); // Store first 9 bytes of every register storing packed bytes. vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_0_u8))); @@ -87,22 +89,23 @@ inline void pack_prb_9b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_2_u8))); vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_2_u8, bytes_per_half_reg); - - c_prb.set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); } /// \brief Packs 16bit IQ values of the PRB using given bit width and big-endian format. /// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] regs NEON registers storing 16bit IQ samples of the PRB. +/// \param[out] comp_prb_buffer Buffer dedicated for storing compressed packed bytes of the PRB. +/// \param[in] regs NEON registers storing 16bit IQ samples of the PRB. /// /// \note Each of the input registers stores four unique REs. -inline void pack_prb_16b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) +inline void pack_prb_16b_big_endian(span comp_prb_buffer, int16x8x3_t regs) { /// Number of bytes used by 1 packed PRB with IQ samples compressed to 16 bits. static constexpr unsigned BYTES_PER_PRB_16BIT_COMPRESSION = 48; static constexpr unsigned NEON_REG_SIZE_BYTES = 16; + srsran_assert(comp_prb_buffer.size() == BYTES_PER_PRB_16BIT_COMPRESSION, + "Output buffer has incorrect size for packing compressed samples"); + static const uint8x16_t shuffle_mask_u8 = vcombine_u8(vcreate_u8(0x0607040502030001), vcreate_u8(0x0e0f0c0d0a0b0809)); int8x16x3_t regs_shuffled_s16; @@ -110,25 +113,24 @@ inline void pack_prb_16b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) regs_shuffled_s16.val[1] = vqtbl1q_s8(vreinterpretq_s8_s16(regs.val[1]), shuffle_mask_u8); regs_shuffled_s16.val[2] = vqtbl1q_s8(vreinterpretq_s8_s16(regs.val[2]), shuffle_mask_u8); - int8_t* data = reinterpret_cast(c_prb.get_byte_buffer().data()); + int8_t* data = reinterpret_cast(comp_prb_buffer.data()); vst1q_s8(data, regs_shuffled_s16.val[0]); vst1q_s8(data + NEON_REG_SIZE_BYTES, regs_shuffled_s16.val[1]); vst1q_s8(data + NEON_REG_SIZE_BYTES * 2, regs_shuffled_s16.val[2]); - c_prb.set_stored_size(BYTES_PER_PRB_16BIT_COMPRESSION); } /// \brief Packs 16bit IQ values of a resource block using the specified width and big-endian format. /// -/// \param[out] c_prb Output PRB storing compressed packed bytes. -/// \param[in] reg Vector of three NEON registers storing 16bit IQ pairs of the PRB. -/// \param[in] iq_width Bit width of the resulting packed IQ samples. -inline void pack_prb_big_endian(ofh::compressed_prb& c_prb, int16x8x3_t regs, unsigned iq_width) +/// \param[out] comp_prb_buffer Buffer dedicated for storing compressed packed bytes of the PRB. +/// \param[in] reg Vector of three NEON registers storing 16bit IQ pairs of the PRB. +/// \param[in] iq_width Bit width of the resulting packed IQ samples. +inline void pack_prb_big_endian(span comp_prb_buffer, int16x8x3_t regs, unsigned iq_width) { if (iq_width == 9) { - return pack_prb_9b_big_endian(c_prb, regs); + return pack_prb_9b_big_endian(comp_prb_buffer, regs); } if (iq_width == 16) { - return pack_prb_16b_big_endian(c_prb, regs); + return pack_prb_16b_big_endian(comp_prb_buffer, regs); } report_fatal_error("Unsupported bit width"); } diff --git a/lib/ofh/serdes/ofh_uplane_message_builder_impl.cpp b/lib/ofh/serdes/ofh_uplane_message_builder_impl.cpp index f8b968ad4c..5106a707d5 100644 --- a/lib/ofh/serdes/ofh_uplane_message_builder_impl.cpp +++ b/lib/ofh/serdes/ofh_uplane_message_builder_impl.cpp @@ -11,6 +11,7 @@ #include "ofh_uplane_message_builder_impl.h" #include "../serdes/ofh_cuplane_constants.h" #include "../support/network_order_binary_serializer.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/ofh/compression/iq_compressor.h" #include "srsran/ran/resource_block.h" @@ -105,10 +106,6 @@ void uplane_message_builder_impl::serialize_iq_data(network_order_binary_seriali to_string(compr_params.type), compr_params.data_width); - std::array compressed_prbs_buffer; - span compressed_prbs(compressed_prbs_buffer.data(), nof_prbs); - compressor.compress(compressed_prbs, iq_data, compr_params); - // Serialize compression header. serialize_compression_header(serializer, compr_params); @@ -122,14 +119,12 @@ void uplane_message_builder_impl::serialize_iq_data(network_order_binary_seriali } } - for (const auto& c_prb : compressed_prbs) { - // Serialize compression parameter. - if (compr_params.type != compression_type::none && compr_params.type != compression_type::modulation) { - serializer.write(c_prb.get_compression_param()); - } - // Serialize compressed data. - serializer.write(c_prb.get_packed_data()); - } + // Size in bytes of one compressed PRB using the given compression parameters. + units::bytes prb_size = get_compressed_prb_size(compr_params); + units::bytes bytes_to_serialize = prb_size * nof_prbs; + + span compr_prb_view = serializer.get_view_and_advance(bytes_to_serialize.value()); + compressor.compress(compr_prb_view, iq_data, compr_params); } unsigned uplane_message_builder_impl::build_message(span buffer, diff --git a/lib/ofh/serdes/ofh_uplane_message_decoder_impl.cpp b/lib/ofh/serdes/ofh_uplane_message_decoder_impl.cpp index 61c0ae1039..3c73bb5cee 100644 --- a/lib/ofh/serdes/ofh_uplane_message_decoder_impl.cpp +++ b/lib/ofh/serdes/ofh_uplane_message_decoder_impl.cpp @@ -11,6 +11,7 @@ #include "ofh_uplane_message_decoder_impl.h" #include "../serdes/ofh_cuplane_constants.h" #include "../support/network_order_binary_deserializer.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/ofh/compression/iq_decompressor.h" #include "srsran/support/units.h" @@ -185,26 +186,6 @@ static void fill_results_from_decoder_section(uplane_section_params& results.ud_comp_param = decoded_results.ud_comp_param; } -/// Returns true if the compression parameter is present based on the given compression type. -static bool is_ud_comp_param_present(compression_type comp) -{ - switch (comp) { - case compression_type::BFP: - case compression_type::block_scaling: - case compression_type::mu_law: - case compression_type::bfp_selective: - case compression_type::mod_selective: - return true; - case compression_type::none: - case compression_type::modulation: - return false; - default: - srsran_assert(0, "Invalid compression type '{}'", comp); - } - - SRSRAN_UNREACHABLE; -} - /// \brief Returns true when the given deserializer contains enough bytes to decode the IQ samples defined by PRB IQ /// data size, otherwise false. /// @@ -222,7 +203,7 @@ static bool check_iq_data_size(unsigned nof_prb, units::bits(NOF_SUBCARRIERS_PER_RB * 2 * compression_params.data_width).round_up_to_bytes().value()); // Add one byte when the udCompParam is present. - if (is_ud_comp_param_present(compression_params.type)) { + if (is_compression_param_present(compression_params.type)) { prb_iq_data_size = prb_iq_data_size + units::bytes(1); } @@ -310,53 +291,6 @@ uplane_message_decoder_impl::decode_section_header(decoder_uplane_section_params return decoded_section_status::ok; } -/// \brief Decodes the compressed PRBs from the deserializer. -/// -/// This function skips the udCompParam field. -/// -/// \param[out] comp_prb Compressed PRBs to decode. -/// \param[in] deserializer Deserializer. -/// \param[in] prb_iq_data_size PRB size in bits. -static void decode_prbs_no_ud_comp_param_field(span comp_prb, - network_order_binary_deserializer& deserializer, - units::bits prb_iq_data_size) -{ - unsigned nof_bytes = prb_iq_data_size.round_up_to_bytes().value(); - - // Read the samples from the deserializer. - for (auto& prb : comp_prb) { - // No need to read the udCompParam field. - prb.set_compression_param(0); - - deserializer.read(prb.get_byte_buffer().first(nof_bytes)); - prb.set_stored_size(nof_bytes); - } -} - -/// \brief Decodes the compressed PRBs from the deserializer. -/// -/// This function decodes the udCompParam field. -/// -/// \param[out] comp_prb Compressed PRBs to decode. -/// \param[in] deserializer Deserializer. -/// \param[in] prb_iq_data_size PRB size in bits. -static void decode_prbs_with_ud_comp_param_field(span comp_prb, - network_order_binary_deserializer& deserializer, - units::bits prb_iq_data_size) -{ - unsigned nof_bytes = prb_iq_data_size.round_up_to_bytes().value(); - - // For each PRB, udCompParam must be decoded. - for (auto& prb : comp_prb) { - // Decode udComParam. - prb.set_compression_param(deserializer.read()); - - // Decode IQ data. - deserializer.read(prb.get_byte_buffer().first(nof_bytes)); - prb.set_stored_size(nof_bytes); - } -} - uplane_message_decoder_impl::decoded_section_status uplane_message_decoder_impl::decode_compression_length(decoder_uplane_section_params& results, network_order_binary_deserializer& deserializer, @@ -390,20 +324,18 @@ void uplane_message_decoder_impl::decode_iq_data(uplane_section_params& network_order_binary_deserializer& deserializer, const ru_compression_params& compression_params) { - std::array comp_prbs_buffer; - span comp_prbs(comp_prbs_buffer.data(), results.nof_prbs); units::bits prb_iq_data_size_bits(NOF_SUBCARRIERS_PER_RB * 2 * compression_params.data_width); // udCompParam field is not present when compression type is none or modulation. - if (is_ud_comp_param_present(compression_params.type)) { - decode_prbs_with_ud_comp_param_field(comp_prbs, deserializer, prb_iq_data_size_bits); - } else { - decode_prbs_no_ud_comp_param_field(comp_prbs, deserializer, prb_iq_data_size_bits); + if (is_compression_param_present(compression_params.type)) { + prb_iq_data_size_bits += units::bits(8); } + span compressed_data = + deserializer.get_view_and_advance(results.nof_prbs * prb_iq_data_size_bits.round_up_to_bytes().value()); // Decompress the samples. results.iq_samples.resize(results.nof_prbs * NOF_SUBCARRIERS_PER_RB); - decompressor->decompress(results.iq_samples, comp_prbs, compression_params); + decompressor->decompress(results.iq_samples, compressed_data, compression_params); } filter_index_type srsran::ofh::uplane_peeker::peek_filter_index(span message) diff --git a/lib/ofh/support/network_order_binary_deserializer.h b/lib/ofh/support/network_order_binary_deserializer.h index c18382a5d4..5f23fef264 100644 --- a/lib/ofh/support/network_order_binary_deserializer.h +++ b/lib/ofh/support/network_order_binary_deserializer.h @@ -73,6 +73,14 @@ class network_order_binary_deserializer offset += x; } + /// Returns a view over the given number of bytes and advances the offset by this amount. + span get_view_and_advance(unsigned x) + { + span view(ptr, x); + advance(x); + return view; + } + /// Returns the current offset. unsigned get_offset() const { return offset; } diff --git a/lib/ofh/support/network_order_binary_serializer.h b/lib/ofh/support/network_order_binary_serializer.h index ae7e6a21e6..34c9e526d2 100644 --- a/lib/ofh/support/network_order_binary_serializer.h +++ b/lib/ofh/support/network_order_binary_serializer.h @@ -79,6 +79,14 @@ class network_order_binary_serializer offset += x; } + /// Returns a view over the given number of bytes and advances the offset by this amount. + span get_view_and_advance(unsigned x) + { + span view(ptr, x); + advance(x); + return view; + } + /// Returns the current offset. unsigned get_offset() const { return offset; } diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp index bf7ded9924..22bb871e9e 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp @@ -13,6 +13,7 @@ #include "scoped_frame_buffer.h" #include "srsran/phy/support/resource_grid_context.h" #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/ran/resource_block.h" #include "srsran/srsvec/conversion.h" #include diff --git a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp index 167ca92d0f..78a009dfc8 100644 --- a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp +++ b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp @@ -9,8 +9,10 @@ */ #include "srsran/ofh/compression/compression_factory.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/ran/bs_channel_bandwidth.h" #include "srsran/ran/cyclic_prefix.h" +#include "srsran/ran/resource_block.h" #include "srsran/ran/slot_point.h" #include "srsran/srslog/srslog.h" #include "srsran/support/benchmark_utils.h" @@ -186,13 +188,15 @@ int main(int argc, char** argv) std::string meas_descr_compression = common_meas_name + " compression"; std::string meas_descr_decompression = common_meas_name + " decompression"; - std::vector> test_data(nof_ports); - std::vector> decompressed_data(nof_ports); - std::vector> compressed_data(nof_ports); + std::vector> test_data(nof_ports); + std::vector> decompressed_data(nof_ports); + std::vector> compressed_data(nof_ports); + + unsigned comp_prb_size = ofh::get_compressed_prb_size(params).value(); for (unsigned i = 0; i != nof_ports; ++i) { test_data[i].resize(nof_prbs * NOF_SUBCARRIERS_PER_RB); decompressed_data[i].resize(nof_prbs * NOF_SUBCARRIERS_PER_RB); - compressed_data[i].resize(nof_prbs); + compressed_data[i].resize(nof_prbs * comp_prb_size); } // Generate input random data. diff --git a/tests/unittests/ofh/compression/ofh_compression_test.cpp b/tests/unittests/ofh/compression/ofh_compression_test.cpp index ab42fba35a..f60af937ca 100644 --- a/tests/unittests/ofh/compression/ofh_compression_test.cpp +++ b/tests/unittests/ofh/compression/ofh_compression_test.cpp @@ -8,11 +8,13 @@ * */ -#include "../../../../lib/ofh/compression/compressed_prb_unpacker.h" +#include "../../../../lib/ofh/compression/packing_utils_generic.h" #include "../../../../lib/ofh/compression/quantizer.h" #include "ofh_compression_test_data.h" #include "srsran/ofh/compression/compression_factory.h" +#include "srsran/ofh/compression/compression_properties.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/units.h" #include using namespace srsran; @@ -72,22 +74,29 @@ TEST_P(OFHCompressionFixture, match_test_case_result_and_decompress_to_original) std::vector test_data_cbf16(test_data.size()); srsvec::convert(test_data_cbf16, test_data); + unsigned prb_size = get_compressed_prb_size(params).value(); + // Prepare vectors to store compression/decompression results. - std::vector compressed_data(nof_prb); - std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); + std::vector compressed_data(nof_prb * prb_size); + std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); // Compress input test data. compressor->compress(compressed_data, test_data_cbf16, params); // Verify compressed IQs. for (unsigned j = 0; j != nof_prb; ++j) { - // Parameter should match. - ASSERT_EQ(compressed_data[j].get_compression_param(), test_compr_param[j]) << fmt::format("wrong PRB={} param", j); + unsigned prb_iq_data_offset = 0; + if (params.type == srsran::ofh::compression_type::BFP) { + // Parameter should match, it is serialized in the first byte. + ASSERT_EQ(compressed_data[j * prb_size], test_compr_param[j]) << fmt::format("wrong PRB={} param", j); + prb_iq_data_offset = 1; + } // Data should match. - compressed_prb& c_prb = compressed_data[j]; - compressed_prb_unpacker unpacker(c_prb); + bit_buffer_reader buffer = bit_buffer_reader::from_bytes( + {&compressed_data[j * prb_size + prb_iq_data_offset], prb_size - prb_iq_data_offset}); + for (unsigned i = 0, read_pos = 0; i != NOF_SUBCARRIERS_PER_RB * 2; ++i) { - int16_t sample = q.sign_extend(unpacker.unpack(read_pos, params.data_width)); + int16_t sample = q.sign_extend(unpack_bits(buffer, read_pos, params.data_width)); read_pos += params.data_width; constexpr uint16_t err_tolerance = 1; @@ -132,8 +141,10 @@ TEST_P(OFHCompressionFixture, zero_input_compression_is_correct) std::vector test_data_cbf16(test_data.size()); srsvec::convert(test_data_cbf16, test_data); - std::vector compressed_data(nof_prb); - std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); + unsigned prb_size = get_compressed_prb_size(params).value(); + + std::vector compressed_data(nof_prb * prb_size); + std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); // Compress it. compressor->compress(compressed_data, test_data_cbf16, params); @@ -165,7 +176,8 @@ TEST(ru_compression_test, bpsk_input_compression_is_correct) std::unique_ptr compressor = create_iq_compressor(compression_type::BFP, logger, 1.0, "generic"); ru_compression_params params = {compression_type::BFP, 9}; - std::vector compressed_data(4); + unsigned prb_size = get_compressed_prb_size(params).value(); + std::vector compressed_data(4 * prb_size); // Compress it. std::vector test_data_cbf16(test_data.size()); @@ -174,14 +186,16 @@ TEST(ru_compression_test, bpsk_input_compression_is_correct) for (unsigned j = 0; j != 4; ++j) { // Parameter should match. - ASSERT_EQ(compressed_data[j].get_compression_param(), test_compr_param[j]) << fmt::format("wrong PRB={} param", j); + ASSERT_EQ(compressed_data[j * prb_size], test_compr_param[j]) << fmt::format("wrong PRB={} param", j); + + // Skip first byte storing the compression parameter. + bit_buffer_reader buffer = bit_buffer_reader::from_bytes({&compressed_data[j * prb_size + 1], prb_size - 1}); + // Data should match. - compressed_prb& c_prb = compressed_data[j]; - compressed_prb_unpacker unpacker(c_prb); for (unsigned i = 0, read_pos = 0; i != NOF_SUBCARRIERS_PER_RB; ++i) { - int16_t re = q.sign_extend(unpacker.unpack(read_pos, 9)); + int16_t re = q.sign_extend(unpack_bits(buffer, read_pos, 9)); read_pos += params.data_width; - int16_t im = q.sign_extend(unpacker.unpack(read_pos, 9)); + int16_t im = q.sign_extend(unpack_bits(buffer, read_pos, 9)); read_pos += params.data_width; ASSERT_TRUE(std::abs(re - std::real(test_compressed_prbs[j][i])) <= 1) diff --git a/tests/unittests/ofh/compression/ofh_iq_compressor_test_doubles.h b/tests/unittests/ofh/compression/ofh_iq_compressor_test_doubles.h index 3f341833ca..e6b693b39c 100644 --- a/tests/unittests/ofh/compression/ofh_iq_compressor_test_doubles.h +++ b/tests/unittests/ofh/compression/ofh_iq_compressor_test_doubles.h @@ -21,11 +21,7 @@ class iq_compressor_dummy : public iq_compressor { public: // See interface for documentation. - void compress(span compressed_prbs, - span iq_data, - const ru_compression_params& params) override - { - } + void compress(span buffer, span iq_data, const ru_compression_params& params) override {} }; } // namespace testing diff --git a/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h b/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h index 161134f1fb..4ac8582956 100644 --- a/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h +++ b/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h @@ -21,9 +21,8 @@ class iq_decompressor_dummy : public iq_decompressor { public: // See interface for documentation. - void decompress(span iq_data, - span compressed_prbs, - const ru_compression_params& params) override + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override { } }; diff --git a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp index 4d43453e12..b68242b6e0 100644 --- a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp +++ b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp @@ -23,9 +23,8 @@ namespace { class iq_decompressor_dummy : public iq_decompressor { public: - void decompress(span iq_data, - span compressed_prbs, - const ru_compression_params& params) override + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override { } }; diff --git a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp index 41cbefa28b..11970f9a00 100644 --- a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp +++ b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp @@ -23,9 +23,8 @@ namespace { class iq_decompressor_dummy : public iq_decompressor { public: - void decompress(span iq_data, - span compressed_prbs, - const ru_compression_params& params) override + void + decompress(span iq_data, span compressed_data, const ru_compression_params& params) override { } }; diff --git a/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp index 16134b3d6f..7dca2785ba 100644 --- a/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp @@ -16,6 +16,7 @@ #include "srsran/adt/interval.h" #include "srsran/ofh/ethernet/ethernet_frame_pool.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/ran/resource_block.h" #include #include From 71b8644ff96ea09652c9fc88dade9b56fbb55876 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 18:58:36 +0200 Subject: [PATCH 225/407] Support: Move type_list header into async/detail where it is used While there, cleanup some documentation. --- .../srsran/support/async/detail/base_task.h | 20 ++++++------- .../srsran/support/async/detail/event_impl.h | 30 +++++++++---------- .../support/async/detail/function_signature.h | 4 +-- .../support/async/detail/promise_data.h | 11 ++++--- .../support/{ => async}/detail/type_list.h | 15 ++++------ .../support/async/detail/unique_coroutine.h | 2 +- 6 files changed, 38 insertions(+), 44 deletions(-) rename include/srsran/support/{ => async}/detail/type_list.h (87%) diff --git a/include/srsran/support/async/detail/base_task.h b/include/srsran/support/async/detail/base_task.h index fab4cf3abe..59165fd15c 100644 --- a/include/srsran/support/async/detail/base_task.h +++ b/include/srsran/support/async/detail/base_task.h @@ -10,17 +10,18 @@ #pragma once -#include "../coroutine.h" -#include "promise_data.h" -#include "unique_coroutine.h" +#include "srsran/support/async/coroutine.h" +#include "srsran/support/async/detail/promise_data.h" +#include "srsran/support/async/detail/unique_coroutine.h" namespace srsran { - namespace detail { struct task_promise_base { - bool has_value = false; ///< If result of task has been stored - coro_handle<> continuation; ///< Pending continuation task + /// True if the result of task has been stored. + bool has_value = false; + /// Pending continuation task. + coro_handle<> continuation; /// Check if return has been stored bool ready() const { return has_value; } @@ -39,14 +40,14 @@ class common_task_crtp /// Returns true if base_task is complete bool ready() const { return empty() or derived().handle.promise().ready(); } - /// Called to get result of task once it is complete - template , std::enable_if_t::value, bool> = true> + /// Called to get result of task once it is complete. + template , std::enable_if_t, bool> = true> const Res& get() const& { srsran_assert(not empty() and derived().handle.promise().ready(), "Called task::get() for task that is not ready"); return derived().handle.promise().get(); } - template , std::enable_if_t::value, bool> = true> + template , std::enable_if_t, bool> = true> Res get() && { srsran_assert(not empty() and derived().handle.promise().ready(), "Called task::get() for task that is not ready"); @@ -73,5 +74,4 @@ class common_task_crtp }; } // namespace detail - } // namespace srsran diff --git a/include/srsran/support/async/detail/event_impl.h b/include/srsran/support/async/detail/event_impl.h index b2827be905..998204a436 100644 --- a/include/srsran/support/async/detail/event_impl.h +++ b/include/srsran/support/async/detail/event_impl.h @@ -10,14 +10,13 @@ #pragma once -#include "../coroutine.h" +#include "srsran/support/async/coroutine.h" #include namespace srsran { - namespace detail { -/// Iterates over linked list of awaiters and calls resume for each awaiter stored coroutine handle +/// Iterates over linked list of awaiters and calls resume for each awaiter stored coroutine handle. template void flush_awaiter_list(AwaiterType* current) { @@ -28,9 +27,10 @@ void flush_awaiter_list(AwaiterType* current) } } -/// Base class implementation with functionality that is common to manual_event and manual_event_flag -/// Awaiters for the event are stored in an intrusive linked list, where each awaiter is stored in the embedded -/// memory buffer of the coroutine frame +/// \brief Base class implementation with functionality that is common to manual_event and manual_event_flag. +/// +/// Awaiters for the event are stored in an intrusive linked list, where each awaiter is stored in the embedded memory +/// buffer of the coroutine frame class manual_event_common { public: @@ -54,9 +54,9 @@ class manual_event_common manual_event_common() = default; manual_event_common(const manual_event_common& event_) = delete; manual_event_common& operator=(const manual_event_common& event_) = delete; - ~manual_event_common() {} + ~manual_event_common() = default; - /// Resets event state + /// Resets event state. void reset() { if (is_set()) { @@ -64,23 +64,23 @@ class manual_event_common } } - /// Check if event value is set + /// Check if event value is set. bool is_set() const { return state == this; } protected: - // Event state. Can be in 3 states: - // - this - event is set - // - nullptr - event is not set and with no awaiters pending - // - other - state is not set. Points to first element in linked list of awaiters + /// Event state. Can be in 3 states: + /// - this - event is set + /// - nullptr - event is not set and with no awaiters pending + /// - other - state is not set. Points to first element in linked list of awaiters void* state = nullptr; - /// triggers all awaiting coroutines after event is set + /// Triggers all awaiting coroutines after event is set. void flush() { if (is_set()) { return; } - auto old_state = std::exchange(state, this); + auto* old_state = std::exchange(state, this); flush_awaiter_list(static_cast(old_state)); } }; diff --git a/include/srsran/support/async/detail/function_signature.h b/include/srsran/support/async/detail/function_signature.h index d0c2731ca8..dc2bd0d4b6 100644 --- a/include/srsran/support/async/detail/function_signature.h +++ b/include/srsran/support/async/detail/function_signature.h @@ -10,10 +10,9 @@ #pragma once -#include "srsran/support/detail/type_list.h" +#include "srsran/support/async/detail/type_list.h" namespace srsran { - namespace detail { /// Type to store arguments and return of callable type Sig. @@ -65,5 +64,4 @@ template auto callable_arguments() -> typename function_signature::operator())>::arg_types; } // namespace detail - } // namespace srsran diff --git a/include/srsran/support/async/detail/promise_data.h b/include/srsran/support/async/detail/promise_data.h index 9251c055f8..79a42fc345 100644 --- a/include/srsran/support/async/detail/promise_data.h +++ b/include/srsran/support/async/detail/promise_data.h @@ -15,10 +15,9 @@ #include namespace srsran { - namespace detail { -/// Class that holds promise result value +/// Class that holds promise result value. template struct promise_data : public Base { promise_data() = default; @@ -33,7 +32,7 @@ struct promise_data : public Base { } } - /// Set Return value + /// Set Return value. template void return_value(U&& u) { @@ -42,7 +41,7 @@ struct promise_data : public Base { Base::has_value = true; } - /// Get Return value + /// Get Return value. const R& get() const& { srsran_assert(Base::has_value, "Trying to extract result from unset Promise"); @@ -55,11 +54,11 @@ struct promise_data : public Base { } private: - /// result storage. + /// Result storage. std::aligned_storage_t mem; }; -/// Specialization for when Return type is void +/// Specialization for when Return type is void. template struct promise_data : public Base { void return_value() { Base::has_value = true; } diff --git a/include/srsran/support/detail/type_list.h b/include/srsran/support/async/detail/type_list.h similarity index 87% rename from include/srsran/support/detail/type_list.h rename to include/srsran/support/async/detail/type_list.h index 8d96cc0727..e9f7642b00 100644 --- a/include/srsran/support/detail/type_list.h +++ b/include/srsran/support/async/detail/type_list.h @@ -13,7 +13,6 @@ #include namespace srsran { - namespace detail { template @@ -29,29 +28,28 @@ struct get_type_from_index_helper { using type = T; }; -/// List of types +/// List of types. template -struct type_list { -}; +struct type_list {}; -/// Get size of type_list +/// Get size of type_list. template constexpr std::size_t type_list_size(type_list t) { return sizeof...(Args); } -/// Metafunction to extract type from variadic template arguments based on provided Index +/// Metafunction to extract type from variadic template arguments based on provided Index. template class get_type_from_index { - static_assert(Index < sizeof...(Types), "index out of bounds"); + static_assert(Index < sizeof...(Types), "Index out of bounds"); public: using type = typename get_type_from_index_helper<0, Index, Types...>::type; }; -/// Specialization when argument is a type_list +/// Specialization when argument is a type_list. template class get_type_from_index> { @@ -63,5 +61,4 @@ template using get_type_from_index_t = typename get_type_from_index::type; } // namespace detail - } // namespace srsran diff --git a/include/srsran/support/async/detail/unique_coroutine.h b/include/srsran/support/async/detail/unique_coroutine.h index 2e80fb0210..251db4c58d 100644 --- a/include/srsran/support/async/detail/unique_coroutine.h +++ b/include/srsran/support/async/detail/unique_coroutine.h @@ -10,7 +10,7 @@ #pragma once -#include "../coroutine.h" +#include "srsran/support/async/coroutine.h" #include namespace srsran { From 4b1d83f65e7278039c6f8ebdd691d30f92d1be8e Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 19:09:37 +0200 Subject: [PATCH 226/407] Support: Place together build and version headers into a new "versioning" folder --- .gitlab-ci.yml | 2 +- apps/cu/CMakeLists.txt | 3 +-- apps/cu/cu.cpp | 4 ++-- apps/du/CMakeLists.txt | 3 +-- apps/du/du.cpp | 4 ++-- apps/gnb/CMakeLists.txt | 3 +-- apps/gnb/gnb.cpp | 4 ++-- apps/services/application_message_banners.h | 2 +- cmake/modules/build_info.cmake.in | 4 ++-- .../{build_info => versioning}/build_info.h | 8 ++++---- .../support/{version => versioning}/version.h | 4 ++-- lib/support/CMakeLists.txt | 3 +-- lib/support/version/CMakeLists.txt | 14 -------------- .../{build_info => versioning}/CMakeLists.txt | 7 ++++--- .../{build_info => versioning}/build_info.cpp | 12 +++++------- lib/support/{build_info => versioning}/hashes.h.in | 14 +++++++------- lib/support/{version => versioning}/version.cpp | 4 ++-- .../{version => versioning}/version_info.h.in | 0 18 files changed, 38 insertions(+), 57 deletions(-) rename include/srsran/support/{build_info => versioning}/build_info.h (59%) rename include/srsran/support/{version => versioning}/version.h (75%) delete mode 100644 lib/support/version/CMakeLists.txt rename lib/support/{build_info => versioning}/CMakeLists.txt (53%) rename lib/support/{build_info => versioning}/build_info.cpp (63%) rename lib/support/{build_info => versioning}/hashes.h.in (54%) rename lib/support/{version => versioning}/version.cpp (88%) rename lib/support/{version => versioning}/version_info.h.in (100%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04cb9e0e65..222dd0f470 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -192,7 +192,7 @@ full-code-format: mkdir -p build cd build || exit cmake -DASSERT_LEVEL=PARANOID -DMARCH=x86-64-v3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTS=False .. - make srsran_build_info # needed to generate hashes.h + make srsran_versioning # needed to generate hashes.h - | monitor_child_process() { while true; do diff --git a/apps/cu/CMakeLists.txt b/apps/cu/CMakeLists.txt index 760c30e037..6c0634b040 100644 --- a/apps/cu/CMakeLists.txt +++ b/apps/cu/CMakeLists.txt @@ -20,8 +20,7 @@ install(TARGETS srscu target_link_libraries(srscu srsran_app_services srsran_support - srsran_version - srsran_build_info + srsran_versioning srsran_cu_cp_app_unit srsran_cu_up_app_unit srsran_ngap diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index ab9cbba566..0361d65209 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -18,7 +18,6 @@ #include "srsran/gtpu/ngu_gateway.h" #include "srsran/pcap/dlt_pcap.h" #include "srsran/support/backtrace.h" -#include "srsran/support/build_info/build_info.h" #include "srsran/support/config_parsers.h" #include "srsran/support/cpu_features.h" #include "srsran/support/error_handling.h" @@ -29,7 +28,8 @@ #include "srsran/support/signal_handling.h" #include "srsran/support/sysinfo.h" #include "srsran/support/timers.h" -#include "srsran/support/version/version.h" +#include "srsran/support/versioning/build_info.h" +#include "srsran/support/versioning/version.h" #include "apps/cu/cu_appconfig_cli11_schema.h" #include "apps/cu/cu_worker_manager.h" diff --git a/apps/du/CMakeLists.txt b/apps/du/CMakeLists.txt index a5d9ace5f9..4b83471e2e 100644 --- a/apps/du/CMakeLists.txt +++ b/apps/du/CMakeLists.txt @@ -27,8 +27,7 @@ target_link_libraries(srsdu e2ap_asn1 srsran_pcap srsran_support - srsran_version - srsran_build_info + srsran_versioning srsran_flexible_du_dynamic srsran_f1c_gateway srsran_cu_up # TODO: Delete diff --git a/apps/du/du.cpp b/apps/du/du.cpp index e2f4263764..2a62ba2009 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -9,11 +9,11 @@ */ #include "srsran/gtpu/gtpu_config.h" -#include "srsran/support/build_info/build_info.h" #include "srsran/support/cpu_features.h" #include "srsran/support/event_tracing.h" #include "srsran/support/signal_handling.h" -#include "srsran/support/version/version.h" +#include "srsran/support/versioning/build_info.h" +#include "srsran/support/versioning/version.h" #include "srsran/f1u/du/split_connector/f1u_split_connector_factory.h" #include "srsran/gtpu/gtpu_demux_factory.h" diff --git a/apps/gnb/CMakeLists.txt b/apps/gnb/CMakeLists.txt index 092ecd70fc..8c526dc122 100644 --- a/apps/gnb/CMakeLists.txt +++ b/apps/gnb/CMakeLists.txt @@ -30,8 +30,7 @@ target_link_libraries(gnb srsran_gateway srsran_pcap srsran_support - srsran_version - srsran_build_info + srsran_versioning srsran_flexible_du_dynamic srsran_f1c_gateway srsran_e1_gateway diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 3f1d2df49d..2658c7a4f4 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -8,11 +8,11 @@ * */ -#include "srsran/support/build_info/build_info.h" #include "srsran/support/cpu_features.h" #include "srsran/support/event_tracing.h" #include "srsran/support/signal_handling.h" -#include "srsran/support/version/version.h" +#include "srsran/support/versioning/build_info.h" +#include "srsran/support/versioning/version.h" #include "srsran/f1u/local_connector/f1u_local_connector.h" diff --git a/apps/services/application_message_banners.h b/apps/services/application_message_banners.h index 977abf89dd..2619030717 100644 --- a/apps/services/application_message_banners.h +++ b/apps/services/application_message_banners.h @@ -11,7 +11,7 @@ #pragma once #include "external/fmt/include/fmt/core.h" -#include "srsran/support/build_info/build_info.h" +#include "srsran/support/versioning/build_info.h" namespace srsran { namespace app_services { diff --git a/cmake/modules/build_info.cmake.in b/cmake/modules/build_info.cmake.in index bcc585d74b..7d8b736243 100644 --- a/cmake/modules/build_info.cmake.in +++ b/cmake/modules/build_info.cmake.in @@ -15,6 +15,6 @@ OUTPUT_STRIP_TRAILING_WHITESPACE message(STATUS "Generating build information") configure_file( - @PROJECT_SOURCE_DIR@/lib/support/build_info/hashes.h.in + @PROJECT_SOURCE_DIR@/lib/support/versioning/hashes.h.in @CMAKE_BINARY_DIR@/hashes.h -) \ No newline at end of file +) diff --git a/include/srsran/support/build_info/build_info.h b/include/srsran/support/versioning/build_info.h similarity index 59% rename from include/srsran/support/build_info/build_info.h rename to include/srsran/support/versioning/build_info.h index 9232551080..6bb86a19a0 100644 --- a/include/srsran/support/build_info/build_info.h +++ b/include/srsran/support/versioning/build_info.h @@ -14,13 +14,13 @@ namespace srsran { -/// \brief Returns a formatted string containing the current commit hash. +/// Returns a formatted string containing the current commit hash. const char* get_build_hash(); -/// \brief Returns a formatted string containing the current commit hash and branch name (if available). +/// Returns a formatted string containing the current commit hash and branch name (if available). const char* get_build_info(); -/// \brief Returns the selected (CMake) build mode as string. +/// Returns the selected (CMake) build mode as string. const char* get_build_mode(); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/support/version/version.h b/include/srsran/support/versioning/version.h similarity index 75% rename from include/srsran/support/version/version.h rename to include/srsran/support/versioning/version.h index ab2792d2ee..15ec6a8c97 100644 --- a/include/srsran/support/version/version.h +++ b/include/srsran/support/versioning/version.h @@ -12,7 +12,7 @@ namespace srsran { -/// \brief Returns the full version with major.minor.patch as string. +/// Returns the full version with major.minor.patch as a string. const char* get_version(); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/support/CMakeLists.txt b/lib/support/CMakeLists.txt index 248131b03b..7f0874061e 100644 --- a/lib/support/CMakeLists.txt +++ b/lib/support/CMakeLists.txt @@ -6,9 +6,8 @@ # the distribution. # -add_subdirectory(build_info) +add_subdirectory(versioning) add_subdirectory(network) -add_subdirectory(version) set(SOURCES executors/priority_task_queue.cpp diff --git a/lib/support/version/CMakeLists.txt b/lib/support/version/CMakeLists.txt deleted file mode 100644 index 554fd992c9..0000000000 --- a/lib/support/version/CMakeLists.txt +++ /dev/null @@ -1,14 +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. -# - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/version_info.h.in - ${CMAKE_CURRENT_BINARY_DIR}/version_info.h -) -include_directories("${CMAKE_CURRENT_BINARY_DIR}") -add_library(srsran_version STATIC version.cpp) \ No newline at end of file diff --git a/lib/support/build_info/CMakeLists.txt b/lib/support/versioning/CMakeLists.txt similarity index 53% rename from lib/support/build_info/CMakeLists.txt rename to lib/support/versioning/CMakeLists.txt index ea41ead4f2..3f03792830 100644 --- a/lib/support/build_info/CMakeLists.txt +++ b/lib/support/versioning/CMakeLists.txt @@ -6,7 +6,8 @@ # the distribution. # -add_library(srsran_build_info STATIC build_info.cpp) -include_directories(${CMAKE_BINARY_DIR}) +configure_file(version_info.h.in ${CMAKE_CURRENT_BINARY_DIR}/version_info.h) +include_directories(${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) +add_library(srsran_versioning STATIC build_info.cpp version.cpp) add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/build_info.cmake) -add_dependencies(srsran_build_info gen_build_info) \ No newline at end of file +add_dependencies(srsran_versioning gen_build_info) diff --git a/lib/support/build_info/build_info.cpp b/lib/support/versioning/build_info.cpp similarity index 63% rename from lib/support/build_info/build_info.cpp rename to lib/support/versioning/build_info.cpp index 84c06d0a41..20f47d0a5a 100644 --- a/lib/support/build_info/build_info.cpp +++ b/lib/support/versioning/build_info.cpp @@ -8,24 +8,22 @@ * */ -#include "srsran/support/build_info/build_info.h" +#include "srsran/support/versioning/build_info.h" #include "hashes.h" -namespace srsran { +using namespace srsran; -const char* get_build_hash() +const char* srsran::get_build_hash() { return build_hash; } -const char* get_build_info() +const char* srsran::get_build_info() { return build_info; } -const char* get_build_mode() +const char* srsran::get_build_mode() { return build_mode; } - -} // namespace srsran \ No newline at end of file diff --git a/lib/support/build_info/hashes.h.in b/lib/support/versioning/hashes.h.in similarity index 54% rename from lib/support/build_info/hashes.h.in rename to lib/support/versioning/hashes.h.in index cb7979b623..5d2812ae93 100644 --- a/lib/support/build_info/hashes.h.in +++ b/lib/support/versioning/hashes.h.in @@ -15,21 +15,21 @@ namespace srsran { #ifdef BUILD_TYPE_RELEASE -static char build_mode[] = "Release"; +static const char build_mode[] = "Release"; #else #ifdef BUILD_TYPE_DEBUG -static char build_mode[] = "Debug"; +static const char build_mode[] = "Debug"; #else #ifdef BUILD_TYPE_RELWITHDEBINFO -static char build_mode[] = "RelWithDebInfo"; +static const char build_mode[] = "RelWithDebInfo"; #else -static char build_mode[] = "unknown"; +static const char build_mode[] = "unknown"; #endif #endif #endif -static char build_hash[] = "@GIT_COMMIT_HASH@"; +static const char build_hash[] = "@GIT_COMMIT_HASH@"; -static char build_info[] = "commit @GIT_COMMIT_HASH@ on branch @GIT_BRANCH@"; +static const char build_info[] = "commit @GIT_COMMIT_HASH@ on branch @GIT_BRANCH@"; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/support/version/version.cpp b/lib/support/versioning/version.cpp similarity index 88% rename from lib/support/version/version.cpp rename to lib/support/versioning/version.cpp index dcc84eface..3678d43448 100644 --- a/lib/support/version/version.cpp +++ b/lib/support/versioning/version.cpp @@ -10,7 +10,7 @@ * */ -#include "srsran/support/version/version.h" +#include "srsran/support/versioning/version.h" #include "version_info.h" using namespace srsran; @@ -18,4 +18,4 @@ using namespace srsran; const char* srsran::get_version() { return SRSRAN_VERSION_STRING; -} \ No newline at end of file +} diff --git a/lib/support/version/version_info.h.in b/lib/support/versioning/version_info.h.in similarity index 100% rename from lib/support/version/version_info.h.in rename to lib/support/versioning/version_info.h.in From 11db50db0aab74dd236d81ad883f45f5970f9af4 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 19:56:56 +0200 Subject: [PATCH 227/407] Support: Move code in support/math to the math_utils header. Change the lcm prototype to use a pairs of iterators to avoid introducing the span dependency --- include/srsran/support/math/lcm.h | 26 ------------------- include/srsran/support/math_utils.h | 8 ++++++ lib/scheduler/config/ue_configuration.cpp | 4 +-- .../scheduler_multi_ue_benchmark.cpp | 1 - .../du_ran_resource_manager_test.cpp | 1 - 5 files changed, 10 insertions(+), 30 deletions(-) delete mode 100644 include/srsran/support/math/lcm.h diff --git a/include/srsran/support/math/lcm.h b/include/srsran/support/math/lcm.h deleted file mode 100644 index c54370a170..0000000000 --- a/include/srsran/support/math/lcm.h +++ /dev/null @@ -1,26 +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 - -namespace srsran { - -/// Calculates the least common multiplier (LCM) for a range of integers. -template -Integer lcm(span values) -{ - return std::accumulate( - values.begin(), values.end(), Integer(1), [](Integer a, Integer b) { return std::lcm(a, b); }); -} - -} // namespace srsran \ No newline at end of file diff --git a/include/srsran/support/math_utils.h b/include/srsran/support/math_utils.h index 723f71730d..2a12bc648e 100644 --- a/include/srsran/support/math_utils.h +++ b/include/srsran/support/math_utils.h @@ -15,6 +15,7 @@ #include "srsran_assert.h" #include "srsran/adt/complex.h" +#include namespace srsran { @@ -178,4 +179,11 @@ inline Integer reverse_byte(Integer byte) return reverse_lut[byte]; } +/// Calculates the least common multiplier (LCM) for a range of integers. +template +Integer lcm(It begin, It end) +{ + return std::accumulate(begin, end, Integer(1), [](Integer a, Integer b) { return std::lcm(a, b); }); +} + } // namespace srsran diff --git a/lib/scheduler/config/ue_configuration.cpp b/lib/scheduler/config/ue_configuration.cpp index 832bbf0831..1dda0a5991 100644 --- a/lib/scheduler/config/ue_configuration.cpp +++ b/lib/scheduler/config/ue_configuration.cpp @@ -15,7 +15,7 @@ #include "../support/pdsch/pdsch_resource_allocation.h" #include "../support/pusch/pusch_default_time_allocation.h" #include "../support/pusch/pusch_resource_allocation.h" -#include "srsran/support/math/lcm.h" +#include "srsran/support/math_utils.h" #include using namespace srsran; @@ -513,7 +513,7 @@ static void generate_crnti_monitored_pdcch_candidates(bwp_info& bwp_cfg, rnti_t for (const search_space_info* ss : bwp_cfg.search_spaces) { ss_periods.push_back(ss->cfg->get_monitoring_slot_periodicity()); } - max_slot_periodicity = lcm(ss_periods); + max_slot_periodicity = lcm(ss_periods.begin(), ss_periods.end()); max_slot_periodicity = std::lcm(max_slot_periodicity, slots_per_frame); } diff --git a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp index e33375c742..07b92aa621 100644 --- a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp @@ -14,7 +14,6 @@ #include "srsran/adt/circular_array.h" #include "srsran/scheduler/scheduler_factory.h" #include "srsran/support/benchmark_utils.h" -#include "srsran/support/math/lcm.h" #include using namespace srsran; diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 9e10b7673a..2c58fe31bb 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -11,7 +11,6 @@ #include "lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h" #include "srsran/du/du_cell_config_helpers.h" #include "srsran/du/du_qos_config_helpers.h" -#include "srsran/support/math/lcm.h" #include "srsran/support/test_utils.h" #include From 634aba6084c2b9bb79bf97f321e30e923fe107b3 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 20:04:22 +0200 Subject: [PATCH 228/407] Support: Remove unused span_printer header --- include/srsran/support/span_printer.h | 54 --------------------------- 1 file changed, 54 deletions(-) delete mode 100644 include/srsran/support/span_printer.h diff --git a/include/srsran/support/span_printer.h b/include/srsran/support/span_printer.h deleted file mode 100644 index e9140782ee..0000000000 --- a/include/srsran/support/span_printer.h +++ /dev/null @@ -1,54 +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 - -namespace srsran { - -/// \brief Writes the given span into a file in binary format. -/// -/// The file is opened in truncated mode and writen in binary format by default. -/// -/// \tparam T Type of the data to write. -/// \param[in] filename Output file name (possibly, with path). -/// \param[in] data Data to write. -/// \param[in] mode Open mode for the file. -/// \return True on success, false otherwise. -/// \warning \c T must be standard layout. -template -inline bool print(const char* filename, - span data, - std::ios_base::openmode mode = std::ios_base::binary | std::ios_base::out) -{ - static_assert(std::is_standard_layout::value, "T is not standard layout"); - std::ofstream file(filename, mode); - - if (!file.is_open()) { - return false; - } - - // Write in binary format. - if (mode & std::ios_base::binary) { - file.write(reinterpret_cast(data.data()), data.size() * sizeof(T)); - return true; - } - - // Write in text format. - for (const auto& d : data) { - file << d << "\n"; - } - - return true; -} - -} // namespace srsran From c28bea5c838a47195a63c9cbbfedce1491e0659c Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 6 Aug 2024 20:06:56 +0200 Subject: [PATCH 229/407] Support: Fix broken function documentation. --- include/srsran/support/file_sink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/srsran/support/file_sink.h b/include/srsran/support/file_sink.h index ad212e6344..c6c23c99ce 100644 --- a/include/srsran/support/file_sink.h +++ b/include/srsran/support/file_sink.h @@ -35,7 +35,7 @@ class file_sink /// Checks if the file is open. bool is_open() const { return binary_file.is_open(); } - /// Writes + /// Writes the given span into a file. void write(span data) { report_fatal_error_if_not(binary_file.is_open(), "File not opened."); From 1861bd1c561bc30743b4583422e3b301b4e1f17f Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 7 Aug 2024 10:49:15 +0200 Subject: [PATCH 230/407] Support: Misc timer library cleanups --- include/srsran/support/timers.h | 29 ++++++++++----------- lib/support/timers.cpp | 46 +++++++++++++-------------------- 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/include/srsran/support/timers.h b/include/srsran/support/timers.h index 9ffb2cdd86..963a1235b9 100644 --- a/include/srsran/support/timers.h +++ b/include/srsran/support/timers.h @@ -46,13 +46,13 @@ class unique_timer; /// separate threads. An unique_timer object and the timer_manager communicate with one another via thread-safe queues. class timer_manager { - /// \brief Unambiguous identifier of the last command sent by a unique_timer to the timer_manager. + /// Unambiguous identifier of the last command sent by a unique_timer to the timer_manager. using cmd_id_t = uint32_t; - /// \brief Constant used to represent invalid timer durations. - constexpr static timer_duration INVALID_DURATION = std::numeric_limits::max(); + /// Constant used to represent invalid timer durations. + static constexpr timer_duration INVALID_DURATION = std::numeric_limits::max(); - /// \brief Possible states for a timer. + /// Possible states for a timer. enum class state_t { stopped, running, expired }; /// Command sent by the unique_timer (front-end) to the timer manager (back-end). @@ -61,13 +61,10 @@ class timer_manager /// Unique identity of the timer. timer_id_t id; - /// Identifier associated with this particular command. cmd_id_t cmd_id; - /// Action Request type sent by the unique_timer. action_t action; - /// Timer duration used, in case the action type is "start". unsigned duration; }; @@ -92,7 +89,7 @@ class timer_manager /// Callback triggered when timer expires. Callback updates are protected by backend lock. unique_function timeout_callback; - timer_frontend(timer_manager& parent_, timer_id_t id_); + timer_frontend(timer_manager& parent_, timer_id_t id_) : parent(parent_), id(id_) {} void destroy(); @@ -105,14 +102,14 @@ class timer_manager void stop(); }; - /// \brief Timer context used solely by the back-end side of the timer manager. + /// Timer context used solely by the back-end side of the timer manager. struct timer_backend_context { cmd_id_t cmd_id = 0; state_t state = state_t::stopped; unsigned timeout = 0; }; - /// \brief Object holding both the front-end and back-end contexts of the timers. + /// Object holding both the front-end and back-end contexts of the timers. struct timer_handle : public intrusive_double_linked_list_element<>, public intrusive_forward_list_element<> { std::unique_ptr frontend; timer_backend_context backend; @@ -135,7 +132,7 @@ class timer_manager size_t nof_timers() const; /// Returns the number of running timers handled by this instance. - unsigned nof_running_timers() const; + unsigned nof_running_timers() const { return nof_timers_running; } private: friend class unique_timer; @@ -146,15 +143,15 @@ class timer_manager /// Push a new timer command (start, stop, destroy) from the front-end execution context to the backend. void push_timer_command(cmd_t cmd); - /// \brief Create a new timer_handle object in the timer manager back-end side and associate it with the provided - /// front-end timer. + /// Create a new timer_handle object in the timer manager back-end side and associate it with the provided frontend + /// timer. void create_timer_handle(std::unique_ptr timer); /// Start the ticking of a timer with a given duration. void start_timer_backend(timer_handle& timer, unsigned duration); - /// \brief Stop a timer from ticking. If \c expiry_reason is set to true, the timer callback is dispatched to the - /// frontend execution context. + /// Stop a timer from ticking. If \c expiry_reason is set to true, the timer callback is dispatched to the frontend + /// execution context. bool try_stop_timer_backend(timer_handle& timer, bool expiry_reason); void stop_timer_backend(timer_handle& timer, bool expiry_reason); @@ -293,7 +290,7 @@ class unique_timer timer_manager::timer_frontend* handle = nullptr; }; -/// \brief Factory of timers that associates created timers to specific task executors. +/// Factory of timers that associates created timers to specific task executors. class timer_factory { public: diff --git a/lib/support/timers.cpp b/lib/support/timers.cpp index 9a30c6d8da..f349e6a5a0 100644 --- a/lib/support/timers.cpp +++ b/lib/support/timers.cpp @@ -21,18 +21,17 @@ static constexpr size_t WHEEL_MASK = WHEEL_SIZE - 1U; /// Maximum timeout duration supported for a given timer in ticks. static constexpr timer_duration MAX_TIMER_DURATION = timer_duration{std::numeric_limits::max() / 2}; -timer_manager::timer_frontend::timer_frontend(timer_manager& parent_, timer_id_t id_) : parent(parent_), id(id_) {} - void timer_manager::timer_frontend::destroy() { cmd_id.fetch_add(1, std::memory_order::memory_order_relaxed); state = state_t::stopped; parent.push_timer_command(cmd_t{id, cmd_id.load(std::memory_order_relaxed), cmd_t::destroy}); -}; +} void timer_manager::timer_frontend::set(timer_duration dur) { srsran_assert(dur <= MAX_TIMER_DURATION, "Invalid timer duration ({}>{})", dur.count(), MAX_TIMER_DURATION.count()); + cmd_id.fetch_add(1, std::memory_order::memory_order_relaxed); duration = dur; if (state == state_t::running) { @@ -63,21 +62,16 @@ void timer_manager::timer_frontend::stop() parent.push_timer_command(cmd_t{id, cmd_id.load(std::memory_order_relaxed), cmd_t::stop}); } -// ///////////////////// - -constexpr timer_duration timer_manager::INVALID_DURATION; - timer_manager::timer_manager(size_t capacity) : logger(srslog::fetch_basic_logger("ALL")), time_wheel(WHEEL_SIZE) { // Pre-reserve timers. while (timer_list.size() < capacity) { - timer_list.emplace_back(); - timer_list.back().frontend = std::make_unique(*this, (timer_id_t)next_timer_id++); + timer_list.emplace_back().frontend = std::make_unique(*this, (timer_id_t)next_timer_id++); } // Push to free list in reverse order to keep ascending ids. for (auto i = timer_list.rbegin(), e = timer_list.rend(); i != e; ++i) { - free_list.push_back(i->frontend.get()); + free_list.emplace_back(i->frontend.get()); } } @@ -91,10 +85,10 @@ void timer_manager::tick() } // Process new commands coming from the front-end. - for (std::variant>& event : cmds_to_process) { - if (std::holds_alternative>(event)) { + for (auto& event : cmds_to_process) { + if (auto* event_p = std::get_if>(&event)) { // New timer was created in the frontend. - create_timer_handle(std::move(std::get>(event))); + create_timer_handle(std::move(*event_p)); continue; } @@ -120,18 +114,19 @@ void timer_manager::tick() handle_postponed_timeouts(); // Advance time. - cur_time++; + ++cur_time; // Process the timer runs which expire in this tick. auto& wheel_list = time_wheel[cur_time & WHEEL_MASK]; - // > iterate intrusive linked list of running timers with same wheel index + // Iterate intrusive linked list of running timers with same wheel index. for (auto it = wheel_list.begin(); it != wheel_list.end();) { srsran_assert(it->frontend != nullptr, "invalid state of timer in timer wheel"); timer_handle& timer = timer_list[static_cast(it->frontend->id)]; - ++it; // we move iterator already, in case, the current timer gets removed from the linked list. + // We move iterator already, in case, the current timer gets removed from the linked list. + ++it; - // If the timer doesnt expire yet, continue the iteration in the same wheel bucket. + // If the timer doesn't expire yet, continue the iteration in the same wheel bucket. if (cur_time != timer.backend.timeout) { continue; } @@ -149,7 +144,7 @@ void timer_manager::push_timer_command(cmd_t cmd) void timer_manager::create_timer_handle(std::unique_ptr timer) { - unsigned timer_idx = static_cast(timer->id); + auto timer_idx = static_cast(timer->id); srsran_assert(timer_idx >= timer_list.size() or timer_list[timer_idx].frontend == nullptr, "Duplicate timer id detection"); if (timer_idx >= timer_list.size()) { @@ -166,7 +161,7 @@ void timer_manager::start_timer_backend(timer_handle& timer, unsigned duration) timer.backend.timeout = cur_time + std::max(duration, 1U); timer.backend.state = state_t::running; time_wheel[timer.backend.timeout & WHEEL_MASK].push_front(&timer); - nof_timers_running++; + ++nof_timers_running; } bool timer_manager::trigger_timeout_handling(timer_handle& timer) @@ -215,7 +210,7 @@ bool timer_manager::try_stop_timer_backend(timer_handle& timer, bool expiry_reas if (not success) { logger.warning("Failed to dispatch timeout handling for timer={}. Re-scheduling the handling to the next slot", timer.frontend->id); - failed_to_trigger_timers.push_back(std::make_pair(timer.frontend->id, timer.backend.cmd_id)); + failed_to_trigger_timers.emplace_back(timer.frontend->id, timer.backend.cmd_id); } } return true; @@ -248,12 +243,13 @@ void timer_manager::stop_timer_backend(timer_handle& timer, bool expiry_reason) void timer_manager::destroy_timer_backend(timer_handle& timer) { srsran_assert(timer.backend.state != state_t::running, "Destroying timer that is running not allowed"); - // clear frontend (it is already released by unique_timer). + + // Clear frontend (it is already released by unique_timer). timer.frontend->state = state_t::stopped; timer.frontend->duration = timer_manager::INVALID_DURATION; timer.frontend->timeout_callback = {}; timer.frontend->exec = nullptr; - // clear backend. + // Clear backend. timer.backend.state = state_t::stopped; timer.backend.timeout = 0; // Add timer handle in free list. @@ -307,9 +303,3 @@ size_t timer_manager::nof_timers() const std::lock_guard lock(free_list_mutex); return timer_list.size() - free_list.size(); } - -/// Returns the number of running timers handled by this instance. -unsigned timer_manager::nof_running_timers() const -{ - return nof_timers_running; -} From c14a034d82ad78f33a58398038996170e2162652 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 7 Aug 2024 11:27:59 +0200 Subject: [PATCH 231/407] Support: cleanups on test_utils header --- include/srsran/support/test_utils.h | 54 +++++++++++++++++------------ 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/include/srsran/support/test_utils.h b/include/srsran/support/test_utils.h index a85d06c14c..83e84bb34d 100644 --- a/include/srsran/support/test_utils.h +++ b/include/srsran/support/test_utils.h @@ -23,10 +23,8 @@ class log_sink_spy : public srslog::sink { public: explicit log_sink_spy(std::unique_ptr f) : - srslog::sink(std::move(f)), s(srslog::get_default_sink()) + srslog::sink(std::move(f)), s(srslog::get_default_sink()), error_counter(0), warning_counter(0) { - error_counter.store(0); - warning_counter.store(0); } /// Identifier of this custom sink. @@ -123,12 +121,10 @@ class log_sink_message_spy : public srslog::sink std::vector entries; }; -/** - * Delimits beginning/ending of a test with the following console output: - * ============= [Test ] =============== - * - * ======================================================= - */ +/// Delimits beginning/ending of a test with the following console output: +/// ============= [Test ] =============== +/// +/// ======================================================= class test_delimit_logger { const size_t delimiter_length = 128; @@ -140,12 +136,14 @@ class test_delimit_logger test_name = fmt::format(test_name_fmt, std::forward(args)...); std::string name_str = fmt::format("[ Test \"{}\" ]", test_name); double nof_repeats = (delimiter_length - name_str.size()) / 2.0; - fmt::print("{0:=>{1}}{2}{0:=>{3}}\n", "", (int)floor(nof_repeats), name_str, (int)ceil(nof_repeats)); + fmt::print("{0:=>{1}}{2}{0:=>{3}}\n", "", (int)std::floor(nof_repeats), name_str, (int)std::ceil(nof_repeats)); } + test_delimit_logger(const test_delimit_logger&) = delete; test_delimit_logger(test_delimit_logger&&) = delete; test_delimit_logger& operator=(const test_delimit_logger&) = delete; test_delimit_logger& operator=(test_delimit_logger&&) = delete; + ~test_delimit_logger() { srslog::flush(); @@ -176,15 +174,18 @@ struct moveonly_test_object { moveonly_test_object& operator=(const moveonly_test_object& other) = delete; bool has_value() const { return val_ptr != nullptr; } - int value() const + + int value() const { srsran_assert(has_value(), "Invalid access"); return *val_ptr; } + bool operator==(const moveonly_test_object& other) const { - return has_value() == other.has_value() and (!has_value() || value() == other.value()); + return has_value() == other.has_value() && (!has_value() || value() == other.value()); } + bool operator!=(const moveonly_test_object& other) const { return !(*this == other); } static size_t object_count() { return object_count_impl().load(std::memory_order_relaxed); } @@ -209,8 +210,10 @@ struct copyonly_test_object { copyonly_test_object& operator=(const copyonly_test_object&) noexcept = default; copyonly_test_object& operator=(copyonly_test_object&&) = delete; - int value() const { return val; } + int value() const { return val; } + bool operator==(const copyonly_test_object& other) const { return val == other.val; } + bool operator!=(const copyonly_test_object& other) const { return val != other.val; } static size_t object_count() { return object_count_impl(); } @@ -221,25 +224,30 @@ struct copyonly_test_object { static size_t count = 0; return count; } + int val; }; struct nondefault_ctor_test_object { nondefault_ctor_test_object(int val_) : val(val_) {} - int value() const { return val; } + + int value() const { return val; } + bool operator==(const nondefault_ctor_test_object& other) const { return val == other.val; } + bool operator!=(const nondefault_ctor_test_object& other) const { return val != other.val; } private: int val; }; -/// \brief This class creates a random generation interface that is suitable for unit tests. The user has the -/// ability to set a random seed to reproduce tests. +/// \brief This class creates a random generation interface that is suitable for unit tests. +/// +/// The user has the ability to set a random seed to reproduce tests. class test_rgen { public: - /// \brief Get test pseudo-random generator. + /// Get test pseudo-random generator. static std::mt19937& get() { thread_local std::mt19937& random_generator = init(std::random_device{}()); @@ -247,6 +255,7 @@ class test_rgen } /// \brief Set random seed for the test pseudo-random generator. + /// /// If this function is never called, the pseudo-random generator will be initialized with a random seed using /// std::random_device. If it is called once, the seed will be the one passed as an argument. If it is called more /// than once, the test will abort. Thus, there should not be race conditions in seed initialization. @@ -258,7 +267,7 @@ class test_rgen } } - /// \brief Return a random integer with uniform distribution within the specified bounds. + /// Returns a random integer with uniform distribution within the specified bounds. template static Integer uniform_int(Integer min, Integer max) { @@ -273,7 +282,7 @@ class test_rgen static bool bernoulli(double p) { return std::bernoulli_distribution(p)(get()); } - /// \brief Return a vector of integers with specified size filled with random values. + /// Return a vector of integers with specified size filled with random values. template static std::vector random_vector(size_t sz) { @@ -312,7 +321,7 @@ class test_rgen namespace fmt { -/// \brief Formatter for moveonly_test_object. +/// Formatter for moveonly_test_object. template <> struct formatter { template @@ -320,9 +329,10 @@ struct formatter { { return ctx.begin(); } + template - auto format(const srsran::moveonly_test_object& obj, FormatContext& ctx) - -> decltype(std::declval().out()) + auto format(const srsran::moveonly_test_object& obj, + FormatContext& ctx) -> decltype(std::declval().out()) { return format_to(ctx.out(), "{}", obj.value()); } From 46b12de97624b25da12a6e8163e60fe0eb36422c Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 7 Aug 2024 13:25:26 +0200 Subject: [PATCH 232/407] Support: Cleanup on sysinfo --- include/srsran/support/sysinfo.h | 2 +- lib/support/sysinfo.cpp | 184 ++++++++++++++++++------------- 2 files changed, 110 insertions(+), 76 deletions(-) diff --git a/include/srsran/support/sysinfo.h b/include/srsran/support/sysinfo.h index afa8dcccc1..5c49981b57 100644 --- a/include/srsran/support/sysinfo.h +++ b/include/srsran/support/sysinfo.h @@ -33,7 +33,7 @@ bool check_drm_kms_polling(srslog::basic_logger& logger); /// /// \param[in] isol_cpus Set of CPUs to be isolated for the gNB app. /// \return True if we were able to configure cgroups through the sysfs. -bool configure_cgroups(const srsran::os_sched_affinity_bitmask& isol_cpus); +bool configure_cgroups(const os_sched_affinity_bitmask& isol_cpus); /// \brief Removes cgroups created by the gNB app. void cleanup_cgroups(); diff --git a/lib/support/sysinfo.cpp b/lib/support/sysinfo.cpp index 9c9e30d546..423125ea39 100644 --- a/lib/support/sysinfo.cpp +++ b/lib/support/sysinfo.cpp @@ -9,37 +9,42 @@ */ #include "srsran/support/sysinfo.h" +#include "srsran/adt/scope_exit.h" #include "srsran/support/executors/unique_thread.h" +#include #include -#include #include #include #include #include -static const std::string isolated_cgroup_path = "/sys/fs/cgroup/srs_isolated"; -static const std::string housekeeping_cgroup_path = "/sys/fs/cgroup/srs_housekeeping"; +using namespace srsran; -/// Executes system command, deletes the given path if the command fails. +static const char* isolated_cgroup_path = "/sys/fs/cgroup/srs_isolated"; +static const char* housekeeping_cgroup_path = "/sys/fs/cgroup/srs_housekeeping"; + +/// Executes a system command and deletes the given path if the command fails. static bool exec_system_command(const std::string& command, const std::string& cleanup_path = "") { if (::system(command.c_str()) < 0) { - fmt::print("{} command failed. error=\"{}\"\n", command, strerror(errno)); + fmt::print("{} command failed. error=\"{}\"\n", command, ::strerror(errno)); if (!cleanup_path.empty()) { ::rmdir(cleanup_path.c_str()); } - return false; } + return true; } /// Writing the value 0 to a cgroup.procs file causes the writing process to be moved to the corresponding cgroup. -static void move_to_cgroup(const std::string& cgroup_path) +static void move_to_cgroup(std::string_view cgroup_path) { - std::ofstream output(cgroup_path + "/cgroup.procs"); + std::string path = fmt::format("{}{}", cgroup_path, "/cgroup.procs"); + + std::ofstream output(path); if (output.fail()) { - fmt::print("Could not open {} for writing. error=\"{}\"\n", cgroup_path + "/cgroup.procs", strerror(errno)); + fmt::print("Could not open {} for writing. error=\"{}\"\n", path, ::strerror(errno)); } output.write("0\n", 2); } @@ -51,94 +56,114 @@ static bool move_procs_between_cgroups(const std::string& dst_path, const std::s std::ifstream source_file(src_path); if (source_file.fail()) { - fmt::print("Could not open {} directory. error=\"{}\"\n", src_path, strerror(errno)); + fmt::print("Could not open {} directory. error=\"{}\"\n", src_path, ::strerror(errno)); return false; } - std::string pid; - while (std::getline(source_file, pid)) { + + std::string pid_str; + while (std::getline(source_file, pid_str)) { std::ofstream destination_file(dst_path); if (destination_file.fail()) { - fmt::print("Could not open {} directory. error=\"{}\"\n", dst_path, strerror(errno)); + fmt::print("Could not open {} directory. error=\"{}\"\n", dst_path, ::strerror(errno)); + return false; + } + + ::pid_t pid = {}; + if (std::from_chars(pid_str.data(), pid_str.data() + pid_str.size(), pid).ec != std::errc()) { + fmt::print("Unable to parse PID\n"); return false; } - destination_file << std::stoi(pid) << "\n"; + destination_file << pid << "\n"; } std::this_thread::sleep_for(50ms); return true; } -bool srsran::configure_cgroups(const srsran::os_sched_affinity_bitmask& isol_cpus) +bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) { std::string isolated_cpus; std::string os_cpus; // Create the string with the CPU indexes. - for (unsigned pos = 0; pos != isol_cpus.size(); ++pos) { + for (unsigned pos = 0, e = isol_cpus.size(); pos != e; ++pos) { if (isol_cpus.test(pos)) { - isolated_cpus += (isolated_cpus.empty()) ? std::to_string(pos) : "," + std::to_string(pos); + if (isolated_cpus.empty()) { + fmt::format_to(std::back_inserter(isolated_cpus), "{}", pos); + } else { + fmt::format_to(std::back_inserter(isolated_cpus), ",{}", pos); + } } else { - os_cpus += (os_cpus.empty()) ? std::to_string(pos) : "," + std::to_string(pos); + if (os_cpus.empty()) { + fmt::format_to(std::back_inserter(os_cpus), "{}", pos); + } else { + fmt::format_to(std::back_inserter(os_cpus), ",{}", pos); + } } } - std::string cgroup_path = "/sys/fs/cgroup"; - struct stat info; - if (::stat(cgroup_path.c_str(), &info) < 0) { - fmt::print("Could not find {}, make sure cgroups-v2 is mounted. error=\"{}\"\n", cgroup_path, strerror(errno)); + static const char* cgroup_path = "/sys/fs/cgroup"; + struct ::stat info; + if (::stat(cgroup_path, &info) < 0) { + fmt::print("Could not find {}, make sure cgroups-v2 is mounted. error=\"{}\"\n", cgroup_path, ::strerror(errno)); return false; } - /// First move itself to root cgroup. + // First move itself to root cgroup. move_to_cgroup(cgroup_path); - /// Create cgroup for OS tasks, call it 'housekeeping' cgroup. + // Create cgroup for OS tasks, call it 'housekeeping' cgroup. if (!os_cpus.empty()) { - std::string housekeeping = cgroup_path + "/srs_housekeeping"; + std::string housekeeping = fmt::format("{}{}", cgroup_path, "/srs_housekeeping"); if ((::mkdir(housekeeping.c_str(), 0755)) < 0 && errno != EEXIST) { - fmt::print("Could not create {} directory. error=\"{}\"\n", housekeeping, strerror(errno)); + fmt::print("Could not create {} directory. error=\"{}\"\n", housekeeping, ::strerror(errno)); return false; } - std::string set_cpus_cmd = "echo " + os_cpus + " > " + housekeeping + "/cpuset.cpus"; - if (!exec_system_command(set_cpus_cmd, housekeeping)) { + + if (!exec_system_command(fmt::format("echo {} > {}{}", os_cpus, housekeeping, "/cpuset.cpus"), housekeeping)) { return false; } - /// Migrate all processes to the default cgroup, that will be using housekeeping cpuset. - std::string procs_filename = housekeeping + "/cgroup.procs"; - FILE* file = popen("ps -eLo lwp=", "r"); + + // Migrate all processes to the default cgroup, that will be using housekeeping cpuset. + std::string procs_filename = fmt::format("{}{}", housekeeping, "/cgroup.procs"); + std::FILE* file = ::popen("ps -eLo lwp=", "r"); if (!file) { fmt::print("Couldn't move system processes to a dedicated cgroup\n"); return false; } - const size_t len = 32; + + auto close_file = make_scope_exit([file]() { ::pclose(file); }); + const size_t len = 32; char pid_buffer[len]; while (::fgets(pid_buffer, len, file)) { - unsigned pid; - std::stringstream ss(pid_buffer); - std::ofstream output(procs_filename); + std::ofstream output(procs_filename); if (output.fail()) { - fmt::print("Could not open {} directory. error=\"{}\"\n", procs_filename, strerror(errno)); + fmt::print("Could not open {} directory. error=\"{}\"\n", procs_filename, ::strerror(errno)); + return false; + } + + ::pid_t pid = {}; + if (std::from_chars(pid_buffer, pid_buffer + ::strlen(pid_buffer), pid).ec != std::errc()) { + fmt::print("Unable to parse PID\n"); return false; } - ss >> pid; output << pid << "\n"; } - ::pclose(file); } - /// Create cgroup with isolated CPUs dedicated for the gNB app. - std::string isol_cgroup_path = cgroup_path + "/srs_isolated"; + // Create cgroup with isolated CPUs dedicated for the gNB app. + std::string isol_cgroup_path = fmt::format("{}{}", cgroup_path, "/srs_isolated"); if ((::mkdir(isol_cgroup_path.c_str(), 0755)) < 0 && errno != EEXIST) { - fmt::print("Could not create {} directory. error=\"{}\"\n", isol_cgroup_path, strerror(errno)); + fmt::print("Could not create {} directory. error=\"{}\"\n", isol_cgroup_path, ::strerror(errno)); return false; } - std::string set_cpus_cmd = "echo " + isolated_cpus + " > " + isol_cgroup_path + "/cpuset.cpus"; + std::string set_cpus_cmd = fmt::format("echo {} > {}{}", isolated_cpus, isol_cgroup_path, "/cpuset.cpus"); if (!exec_system_command(set_cpus_cmd, isol_cgroup_path)) { return false; } - /// Finally move itself to isolcated cgroup. + // Finally move itself to isolcated cgroup. move_to_cgroup(isol_cgroup_path); return true; @@ -147,32 +172,34 @@ bool srsran::configure_cgroups(const srsran::os_sched_affinity_bitmask& isol_cpu void srsran::cleanup_cgroups() { using namespace std::chrono_literals; + static const char* root_cgroup_path = "/sys/fs/cgroup/cgroup.procs"; - bool cgroup_changed = false; - std::string root_cgroup_path = "/sys/fs/cgroup/cgroup.procs"; + bool cgroup_changed = false; - struct stat sysfs_info; + struct ::stat sysfs_info; if (::stat("/sys/fs/cgroup", &sysfs_info) < 0) { return; } - struct stat info; - if (::stat(housekeeping_cgroup_path.c_str(), &info) == 0) { - move_procs_between_cgroups(root_cgroup_path, housekeeping_cgroup_path + "/cgroup.procs"); + struct ::stat info; + if (::stat(housekeeping_cgroup_path, &info) == 0) { + move_procs_between_cgroups(root_cgroup_path, fmt::format("{}{}", housekeeping_cgroup_path, "/cgroup.procs")); // Remove previously created cgroups. - if (::rmdir(housekeeping_cgroup_path.c_str()) < 0) { - fmt::print("Could not delete {}. error=\"{}\"\n", housekeeping_cgroup_path, strerror(errno)); + if (::rmdir(housekeeping_cgroup_path) < 0) { + fmt::print("Could not delete {}. error=\"{}\"\n", housekeeping_cgroup_path, ::strerror(errno)); } cgroup_changed = true; } - if (::stat(isolated_cgroup_path.c_str(), &info) == 0) { + + if (::stat(isolated_cgroup_path, &info) == 0) { // Move all processes to the parent cgroup. - move_procs_between_cgroups(root_cgroup_path, isolated_cgroup_path + "/cgroup.procs"); - if (::rmdir(isolated_cgroup_path.c_str())) { - fmt::print("Could not delete {}. error=\"{}\"\n", isolated_cgroup_path, strerror(errno)); + move_procs_between_cgroups(root_cgroup_path, fmt::format("{}{}", isolated_cgroup_path, "/cgroup.procs")); + if (::rmdir(isolated_cgroup_path)) { + fmt::print("Could not delete {}. error=\"{}\"\n", isolated_cgroup_path, ::strerror(errno)); } cgroup_changed = true; } + // Wait for changes in cpuset to take place. if (cgroup_changed) { std::this_thread::sleep_for(100ms); @@ -182,17 +209,17 @@ void srsran::cleanup_cgroups() std::optional srsran::check_cgroups() { // Return false if the system doesn't have cgroups-v2 mounted. - struct stat sysfs_info; + struct ::stat sysfs_info; if (::stat("/sys/fs/cgroup", &sysfs_info) < 0) { - return {}; + return std::nullopt; } fmt::memory_buffer buffer; - struct stat info; - if (::stat(housekeeping_cgroup_path.c_str(), &info) == 0) { + struct ::stat info; + if (::stat(housekeeping_cgroup_path, &info) == 0) { fmt::format_to(buffer, "{}", housekeeping_cgroup_path); } - if (::stat(isolated_cgroup_path.c_str(), &info) == 0) { + if (::stat(isolated_cgroup_path, &info) == 0) { if (buffer.size() != 0) { fmt::format_to(buffer, ", "); } @@ -204,53 +231,60 @@ std::optional srsran::check_cgroups() bool srsran::check_cpu_governor(srslog::basic_logger& logger) { - unsigned int n_cpus = std::thread::hardware_concurrency(); - std::string filename_base = "/sys/devices/system/cpu/cpu"; - for (unsigned int i = 0; i < n_cpus; ++i) { - std::string filename = filename_base + std::to_string(i) + "/cpufreq/scaling_governor"; + static const char* filename_base = "/sys/devices/system/cpu/cpu"; + + for (unsigned int i = 0, e = std::thread::hardware_concurrency(); i != e; ++i) { + std::string filename = fmt::format("{}{}{}", filename_base, i, "/cpufreq/scaling_governor"); + std::ifstream input(filename); if (input.fail()) { - logger.warning("Could not check scaling governor. filename={} error=\"{}\"", filename, strerror(errno)); + logger.warning("Could not check scaling governor. filename={} error=\"{}\"", filename, ::strerror(errno)); return false; } + std::string gov; std::getline(input, gov); if (input.fail()) { - logger.warning("Could not check scaling governor. filename={} error=\"{}\"", filename, strerror(errno)); + logger.warning("Could not check scaling governor. filename={} error=\"{}\"", filename, ::strerror(errno)); return false; } + if (gov == "performance") { logger.debug("CPU{} scaling governor is set to performance", i); - } else { - logger.warning( - "CPU{} scaling governor is not set to performance, which may hinder performance. You can set it to " - "performance using the " - "\"srsran_performance\" script", - i); + continue; } + logger.warning("CPU{} scaling governor is not set to performance, which may hinder performance. You can set it to " + "performance using the " + "\"srsran_performance\" script", + i); } + return true; } bool srsran::check_drm_kms_polling(srslog::basic_logger& logger) { - std::string filename = "/sys/module/drm_kms_helper/parameters/poll"; + static const char* filename = "/sys/module/drm_kms_helper/parameters/poll"; + std::ifstream input(filename); if (input.fail()) { - logger.warning("Could not check DRM KMS polling. filename={} error=\"{}\"", filename, strerror(errno)); + logger.warning("Could not check DRM KMS polling. filename={} error=\"{}\"", filename, ::strerror(errno)); return false; } + std::string polling; std::getline(input, polling); if (input.fail()) { - logger.warning("Could not check DRM KMS polling. filename={} error=\"{}\"", filename, strerror(errno)); + logger.warning("Could not check DRM KMS polling. filename={} error=\"{}\"", filename, ::strerror(errno)); return false; } + if (polling == "N") { logger.debug("DRM KMS polling is disabled"); } else { logger.warning("DRM KMS polling is enabled, which may hinder performance. You can disable it using the " "\"srsran_performance\" script"); } + return true; } From 356ef466c1228b48164666cc67c99f3bc65978f0 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 7 Aug 2024 14:05:15 +0200 Subject: [PATCH 233/407] Support: cleanup misc support files. --- include/srsran/support/prefixed_logger.h | 28 ++++++------------------ include/srsran/support/sdu_window.h | 2 +- include/srsran/support/srsran_test.h | 2 +- include/srsran/support/stats.h | 2 +- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/include/srsran/support/prefixed_logger.h b/include/srsran/support/prefixed_logger.h index 98ea3037f2..429ceb3b72 100644 --- a/include/srsran/support/prefixed_logger.h +++ b/include/srsran/support/prefixed_logger.h @@ -15,15 +15,13 @@ namespace srsran { -/// Class used to store common logging parameters for all types RLC entities. -/// It provides logging helpers, so that the UE index and LCID are always logged. -/// -/// \param log_name name of the logger we want to use (e.g. RLC, PDCP, etc.) -/// \param du_index UE identifier within the DU -/// \param lcid LCID for the bearer +/// This utility class allows adding a prefix string to all log entries generated using the provided methods. template class prefixed_logger { + srslog::basic_logger& logger; + std::shared_ptr log_label; + public: prefixed_logger(const std::string& log_name, Prefix prefix, const char* prefix_separator = "") : logger(srslog::fetch_basic_logger(log_name, false)) @@ -76,7 +74,7 @@ class prefixed_logger log_error(fmt, std::forward(args)...); break; case srslog::basic_levels::none: - // skip + // Skip. break; default: log_warning("Unsupported log level: {}", basic_level_to_string(level)); @@ -122,7 +120,7 @@ class prefixed_logger log_error(it_begin, it_end, fmt, std::forward(args)...); break; case srslog::basic_levels::none: - // skip + // Skip. break; default: log_warning("Unsupported log level: {}", basic_level_to_string(level)); @@ -188,7 +186,7 @@ class prefixed_logger log_error(msg, len, fmt, std::forward(args)...); break; case srslog::basic_levels::none: - // skip + // Skip. break; default: log_warning("Unsupported log level: {}", basic_level_to_string(level)); @@ -199,33 +197,21 @@ class prefixed_logger srslog::basic_logger& get_basic_logger() { return logger; } private: - srslog::basic_logger& logger; - std::shared_ptr log_label; - template void log_helper(srslog::log_channel& channel, const char* fmt, Args&&... args) const { - if (!channel.enabled()) { - return; - } channel(log_label, fmt, std::forward(args)...); } template void log_helper(It it_begin, It it_end, srslog::log_channel& channel, const char* fmt, Args&&... args) const { - if (!channel.enabled()) { - return; - } channel(log_label, it_begin, it_end, fmt, std::forward(args)...); } template void log_helper(const uint8_t* msg, size_t len, srslog::log_channel& channel, const char* fmt, Args&&... args) const { - if (!channel.enabled()) { - return; - } channel(log_label, msg, len, fmt, std::forward(args)...); } }; diff --git a/include/srsran/support/sdu_window.h b/include/srsran/support/sdu_window.h index f6d70d2a09..3333039d15 100644 --- a/include/srsran/support/sdu_window.h +++ b/include/srsran/support/sdu_window.h @@ -10,8 +10,8 @@ #pragma once +#include #include -#include namespace srsran { diff --git a/include/srsran/support/srsran_test.h b/include/srsran/support/srsran_test.h index 6ea3f00e1c..2c50ce1af2 100644 --- a/include/srsran/support/srsran_test.h +++ b/include/srsran/support/srsran_test.h @@ -16,7 +16,7 @@ namespace srsran { namespace detail { -/// Helper function to format TESTASSERT_EQ +/// Helper function to format TESTASSERT_EQ. template [[gnu::noinline]] inline std::string assert_eq_format_helper(T expected_val, U actual_val, bool eq_cmp, const std::string& msg) noexcept diff --git a/include/srsran/support/stats.h b/include/srsran/support/stats.h index abc2e229e3..ad5bd9c58e 100644 --- a/include/srsran/support/stats.h +++ b/include/srsran/support/stats.h @@ -230,7 +230,7 @@ class sample_statistics private: /// Ensure the sample type is arithmetic. - static_assert(std::is_arithmetic::value, "Invalid type."); + static_assert(std::is_arithmetic_v, "Invalid type."); /// Records the maximum observed value. T max = std::numeric_limits::min(); /// Records the minimum observed value. From e91c6ae2457b0c8b81c42d3b8a45b88b15d5bdb4 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 7 Aug 2024 14:37:46 +0200 Subject: [PATCH 234/407] Support: Cleanup math_utils --- include/srsran/support/math_utils.h | 6 +++--- lib/support/math_utils.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/srsran/support/math_utils.h b/include/srsran/support/math_utils.h index 2a12bc648e..6222bfacaf 100644 --- a/include/srsran/support/math_utils.h +++ b/include/srsran/support/math_utils.h @@ -20,10 +20,10 @@ namespace srsran { /// Defines two times Pi. -static constexpr float TWOPI = 2.0F * static_cast(M_PI); +constexpr float TWOPI = 2.0F * static_cast(M_PI); /// Floating point near zero value. -static constexpr float near_zero = 1e-9; +constexpr float near_zero = 1e-9; /// \brief Performs an integer division rounding up. /// @@ -145,7 +145,7 @@ inline Integer reverse_byte(Integer byte) { static_assert(std::is_convertible_v, "The input type must be convertible to an unsigned integer of eight bits"); - static const std::array reverse_lut = { + static constexpr std::array reverse_lut = { 0b00000000, 0b10000000, 0b01000000, 0b11000000, 0b00100000, 0b10100000, 0b01100000, 0b11100000, 0b00010000, 0b10010000, 0b01010000, 0b11010000, 0b00110000, 0b10110000, 0b01110000, 0b11110000, 0b00001000, 0b10001000, 0b01001000, 0b11001000, 0b00101000, 0b10101000, 0b01101000, 0b11101000, 0b00011000, 0b10011000, 0b01011000, diff --git a/lib/support/math_utils.cpp b/lib/support/math_utils.cpp index 1cd2feb35d..2f0f2277ca 100644 --- a/lib/support/math_utils.cpp +++ b/lib/support/math_utils.cpp @@ -12,11 +12,11 @@ #include "srsran/support/error_handling.h" #include "srsran/support/srsran_assert.h" -/// Number of prime numbers between 2 and 3299 (both included). -constexpr unsigned NOF_PRIME_NUMBERS = 463; - using namespace srsran; +/// Number of prime numbers between 2 and 3299 (both included). +static constexpr unsigned NOF_PRIME_NUMBERS = 463; + static constexpr std::array prime_numbers = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, From 14fb5c48bd3b16d7f18a05ff432223182bd6c2a8 Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 9 Aug 2024 10:19:05 +0200 Subject: [PATCH 235/407] Support: Remove file_sink class in favour of file_vector --- apps/examples/radio/radio_util_sample.cpp | 10 ++-- apps/examples/radio/rx_power_analyzer.cpp | 4 +- .../srsran/support/async/detail/event_impl.h | 2 +- .../srsran/support/async/detail/type_list.h | 3 +- include/srsran/support/file_sink.h | 47 ------------------- include/srsran/support/file_tensor.h | 3 +- include/srsran/support/file_vector.h | 3 +- include/srsran/support/format_utils.h | 28 +++++------ include/srsran/support/test_utils.h | 4 +- lib/support/sysinfo.cpp | 32 ++++++------- lib/support/timers.cpp | 2 +- 11 files changed, 45 insertions(+), 93 deletions(-) delete mode 100644 include/srsran/support/file_sink.h diff --git a/apps/examples/radio/radio_util_sample.cpp b/apps/examples/radio/radio_util_sample.cpp index 28d8cead56..6f9efa0ca7 100644 --- a/apps/examples/radio/radio_util_sample.cpp +++ b/apps/examples/radio/radio_util_sample.cpp @@ -16,7 +16,7 @@ #include "srsran/gateways/baseband/buffer/baseband_gateway_buffer_dynamic.h" #include "srsran/radio/radio_factory.h" #include "srsran/support/executors/task_worker.h" -#include "srsran/support/file_sink.h" +#include "srsran/support/file_vector.h" #include "srsran/support/math_utils.h" #include "srsran/support/signal_handling.h" #include @@ -351,9 +351,9 @@ int main(int argc, char** argv) uint64_t sample_count = 0; // Open file sink if mot empty. - file_sink rx_file; + std::unique_ptr> rx_file; if (!rx_filename.empty()) { - rx_file = file_sink(rx_filename); + rx_file = std::make_unique>(rx_filename.c_str(), openmode::write_only); } // Counter for the number of empty transmission buffers. @@ -382,8 +382,8 @@ int main(int argc, char** argv) rx_metadata[stream_id] = receiver.receive(rx_baseband_buffers[stream_id].get_writer()); // Save file. - if (stream_id == 0 && rx_file.is_open()) { - rx_file.write(rx_baseband_buffers[stream_id][0]); + if (stream_id == 0 && rx_file) { + rx_file->write(rx_baseband_buffers[stream_id][0]); } // Prepare transmit metadata. diff --git a/apps/examples/radio/rx_power_analyzer.cpp b/apps/examples/radio/rx_power_analyzer.cpp index 0d9b82288c..3b9c359f5f 100644 --- a/apps/examples/radio/rx_power_analyzer.cpp +++ b/apps/examples/radio/rx_power_analyzer.cpp @@ -30,7 +30,7 @@ #include "srsran/srsvec/dot_prod.h" #include "srsran/support/complex_normal_random.h" #include "srsran/support/executors/task_worker.h" -#include "srsran/support/file_sink.h" +#include "srsran/support/file_vector.h" #include "srsran/support/signal_handling.h" #include #include @@ -183,7 +183,7 @@ static void write_results_csv(const std::vector& results) fmt::print("Result filename is not set. \n"); } - file_sink results_file(results_filename); + file_vector results_file(results_filename.c_str(), openmode::write_only); fmt::print("Writing to CSV file {}...\n", results_filename); fmt::print("CSV columns: ,,\n"); diff --git a/include/srsran/support/async/detail/event_impl.h b/include/srsran/support/async/detail/event_impl.h index 998204a436..8d81ca5138 100644 --- a/include/srsran/support/async/detail/event_impl.h +++ b/include/srsran/support/async/detail/event_impl.h @@ -52,9 +52,9 @@ class manual_event_common }; manual_event_common() = default; + ~manual_event_common() = default; manual_event_common(const manual_event_common& event_) = delete; manual_event_common& operator=(const manual_event_common& event_) = delete; - ~manual_event_common() = default; /// Resets event state. void reset() diff --git a/include/srsran/support/async/detail/type_list.h b/include/srsran/support/async/detail/type_list.h index e9f7642b00..26620f73cc 100644 --- a/include/srsran/support/async/detail/type_list.h +++ b/include/srsran/support/async/detail/type_list.h @@ -30,7 +30,8 @@ struct get_type_from_index_helper { /// List of types. template -struct type_list {}; +struct type_list { +}; /// Get size of type_list. template diff --git a/include/srsran/support/file_sink.h b/include/srsran/support/file_sink.h deleted file mode 100644 index c6c23c99ce..0000000000 --- a/include/srsran/support/file_sink.h +++ /dev/null @@ -1,47 +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 { - -template -class file_sink -{ -private: - std::ofstream binary_file; - -public: - /// Default constructor. It does not open file. - file_sink() = default; - - /// Constructs a file sink using a file name. - file_sink(std::string file_name) : binary_file(file_name, std::ios::out | std::ios::binary) - { - report_fatal_error_if_not(binary_file.is_open(), "Failed to open file."); - } - - /// Checks if the file is open. - bool is_open() const { return binary_file.is_open(); } - - /// Writes the given span into a file. - void write(span data) - { - report_fatal_error_if_not(binary_file.is_open(), "File not opened."); - - binary_file.write(reinterpret_cast(data.data()), sizeof(T) * data.size()); - } -}; - -} // namespace srsran diff --git a/include/srsran/support/file_tensor.h b/include/srsran/support/file_tensor.h index 94b169e73e..ea6c0b9d77 100644 --- a/include/srsran/support/file_tensor.h +++ b/include/srsran/support/file_tensor.h @@ -24,7 +24,6 @@ namespace srsran { template class file_tensor { -private: const char* file_name; std::array dimension_sizes; openmode op; @@ -38,7 +37,7 @@ class file_tensor /// \param[in] filename Input file name. /// \param[in] dim_sizes Array describing the data dimensions. /// \param[in] op_ File opening mode. - file_tensor(const char* filename, const std::array dim_sizes, openmode op_ = openmode::read_only) : + file_tensor(const char* filename, const std::array& dim_sizes, openmode op_ = openmode::read_only) : file_name(filename), dimension_sizes(dim_sizes), op(op_) { } diff --git a/include/srsran/support/file_vector.h b/include/srsran/support/file_vector.h index 95348aab1b..1c59936e28 100644 --- a/include/srsran/support/file_vector.h +++ b/include/srsran/support/file_vector.h @@ -29,13 +29,12 @@ enum class openmode { read_write }; -template /// \brief Simple binary file input-output interface. /// /// An object of this file allows reading and writing values of type \c T from and to a binary file. +template class file_vector { -private: const char* file_name; openmode op; diff --git a/include/srsran/support/format_utils.h b/include/srsran/support/format_utils.h index c64fbe1ae4..0c3f60e14e 100644 --- a/include/srsran/support/format_utils.h +++ b/include/srsran/support/format_utils.h @@ -16,7 +16,7 @@ namespace srsran { -/// \brief Converts fmt memoryy buffer to c_str() without the need for conversion to intermediate std::string. +/// Converts fmt memory buffer to c_str() without the need for conversion to intermediate std::string. template const char* to_c_str(fmt::basic_memory_buffer& mem_buffer) { @@ -39,17 +39,17 @@ class delimited_formatter /// Default constructor. delimited_formatter() { - static const fmt::string_view DEFAULT_FORMAT = "{}"; - static const fmt::string_view DEFAULT_DELIMITER = " "; + static constexpr std::string_view DEFAULT_FORMAT = "{}"; + static constexpr std::string_view DEFAULT_DELIMITER = " "; format_buffer.append(DEFAULT_FORMAT.begin(), DEFAULT_FORMAT.end()); delimiter_buffer.append(DEFAULT_DELIMITER.begin(), DEFAULT_DELIMITER.end()); } /// Constructor that sets the default delimiter according to the string \c default_delimiter. - explicit delimited_formatter(const std::string& default_delimiter) + explicit delimited_formatter(std::string_view default_delimiter) { - static const fmt::string_view DEFAULT_FORMAT = "{}"; - static const fmt::string_view DEFAULT_DELIMITER = default_delimiter; + static constexpr std::string_view DEFAULT_FORMAT = "{}"; + std::string_view DEFAULT_DELIMITER = default_delimiter; format_buffer.append(DEFAULT_FORMAT.begin(), DEFAULT_FORMAT.end()); delimiter_buffer.append(DEFAULT_DELIMITER.begin(), DEFAULT_DELIMITER.end()); } @@ -69,8 +69,8 @@ class delimited_formatter // Set the first field indicator. first = true; - static const fmt::string_view PREAMBLE_FORMAT = "{:"; - static const fmt::string_view NEWLINE_DELIMITER = "\n "; + static constexpr std::string_view PREAMBLE_FORMAT = "{:"; + static constexpr std::string_view NEWLINE_DELIMITER = "\n "; // Skip if context is empty and use default format. if (context.begin() == context.end()) { @@ -195,11 +195,11 @@ class delimited_formatter if (temp_buffer.size() > 0) { // Prepend delimiter to the formatted output. - fmt::format_to(context.out(), "{}", fmt::string_view(delimiter_buffer.data(), delimiter_buffer.size())); + fmt::format_to(context.out(), "{}", std::string_view(delimiter_buffer.data(), delimiter_buffer.size())); } // Append the formatted string to the context iterator. - fmt::format_to(context.out(), "{}", fmt::string_view(temp_buffer.data(), temp_buffer.size())); + fmt::format_to(context.out(), "{}", std::string_view(temp_buffer.data(), temp_buffer.size())); return; } @@ -216,21 +216,21 @@ class delimited_formatter // Buffer to hold the formatted string. fmt::memory_buffer temp_buffer; fmt::format_to( - temp_buffer, fmt::string_view(format_buffer.data(), format_buffer.size()), std::forward(args)...); + temp_buffer, std::string_view(format_buffer.data(), format_buffer.size()), std::forward(args)...); if (temp_buffer.size() > 0) { // Prepend delimiter to the formatted output. - fmt::format_to(context.out(), "{}", fmt::string_view(delimiter_buffer.data(), delimiter_buffer.size())); + fmt::format_to(context.out(), "{}", std::string_view(delimiter_buffer.data(), delimiter_buffer.size())); } // Append the formatted string to the context iterator. - fmt::format_to(context.out(), "{}", fmt::string_view(temp_buffer.data(), temp_buffer.size())); + fmt::format_to(context.out(), "{}", std::string_view(temp_buffer.data(), temp_buffer.size())); return; } // Format without prepending delimiter. fmt::format_to( - context.out(), fmt::string_view(format_buffer.data(), format_buffer.size()), std::forward(args)...); + context.out(), std::string_view(format_buffer.data(), format_buffer.size()), std::forward(args)...); first = false; } diff --git a/include/srsran/support/test_utils.h b/include/srsran/support/test_utils.h index 83e84bb34d..e2ea8236f7 100644 --- a/include/srsran/support/test_utils.h +++ b/include/srsran/support/test_utils.h @@ -331,8 +331,8 @@ struct formatter { } template - auto format(const srsran::moveonly_test_object& obj, - FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const srsran::moveonly_test_object& obj, FormatContext& ctx) + -> decltype(std::declval().out()) { return format_to(ctx.out(), "{}", obj.value()); } diff --git a/lib/support/sysinfo.cpp b/lib/support/sysinfo.cpp index 423125ea39..9f94006fba 100644 --- a/lib/support/sysinfo.cpp +++ b/lib/support/sysinfo.cpp @@ -27,7 +27,7 @@ static const char* housekeeping_cgroup_path = "/sys/fs/cgroup/srs_housekeeping"; static bool exec_system_command(const std::string& command, const std::string& cleanup_path = "") { if (::system(command.c_str()) < 0) { - fmt::print("{} command failed. error=\"{}\"\n", command, ::strerror(errno)); + fmt::print("{} command failed. error='{}'\n", command, ::strerror(errno)); if (!cleanup_path.empty()) { ::rmdir(cleanup_path.c_str()); } @@ -44,7 +44,7 @@ static void move_to_cgroup(std::string_view cgroup_path) std::ofstream output(path); if (output.fail()) { - fmt::print("Could not open {} for writing. error=\"{}\"\n", path, ::strerror(errno)); + fmt::print("Could not open '{}' for writing. error='{}'\n", path, ::strerror(errno)); } output.write("0\n", 2); } @@ -56,7 +56,7 @@ static bool move_procs_between_cgroups(const std::string& dst_path, const std::s std::ifstream source_file(src_path); if (source_file.fail()) { - fmt::print("Could not open {} directory. error=\"{}\"\n", src_path, ::strerror(errno)); + fmt::print("Could not open '{}' directory. error='{}'\n", src_path, ::strerror(errno)); return false; } @@ -64,7 +64,7 @@ static bool move_procs_between_cgroups(const std::string& dst_path, const std::s while (std::getline(source_file, pid_str)) { std::ofstream destination_file(dst_path); if (destination_file.fail()) { - fmt::print("Could not open {} directory. error=\"{}\"\n", dst_path, ::strerror(errno)); + fmt::print("Could not open '{}' directory. error='{}'\n", dst_path, ::strerror(errno)); return false; } @@ -105,7 +105,7 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) static const char* cgroup_path = "/sys/fs/cgroup"; struct ::stat info; if (::stat(cgroup_path, &info) < 0) { - fmt::print("Could not find {}, make sure cgroups-v2 is mounted. error=\"{}\"\n", cgroup_path, ::strerror(errno)); + fmt::print("Could not find '{}', make sure cgroups-v2 is mounted. error='{}'\n", cgroup_path, ::strerror(errno)); return false; } @@ -116,7 +116,7 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) if (!os_cpus.empty()) { std::string housekeeping = fmt::format("{}{}", cgroup_path, "/srs_housekeeping"); if ((::mkdir(housekeeping.c_str(), 0755)) < 0 && errno != EEXIST) { - fmt::print("Could not create {} directory. error=\"{}\"\n", housekeeping, ::strerror(errno)); + fmt::print("Could not create '{}' directory. error='{}'\n", housekeeping, ::strerror(errno)); return false; } @@ -128,7 +128,7 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) std::string procs_filename = fmt::format("{}{}", housekeeping, "/cgroup.procs"); std::FILE* file = ::popen("ps -eLo lwp=", "r"); if (!file) { - fmt::print("Couldn't move system processes to a dedicated cgroup\n"); + fmt::print("Could not move system processes to a dedicated cgroup\n"); return false; } @@ -138,7 +138,7 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) while (::fgets(pid_buffer, len, file)) { std::ofstream output(procs_filename); if (output.fail()) { - fmt::print("Could not open {} directory. error=\"{}\"\n", procs_filename, ::strerror(errno)); + fmt::print("Could not open '{}' directory. error='{}'\n", procs_filename, ::strerror(errno)); return false; } @@ -154,7 +154,7 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) // Create cgroup with isolated CPUs dedicated for the gNB app. std::string isol_cgroup_path = fmt::format("{}{}", cgroup_path, "/srs_isolated"); if ((::mkdir(isol_cgroup_path.c_str(), 0755)) < 0 && errno != EEXIST) { - fmt::print("Could not create {} directory. error=\"{}\"\n", isol_cgroup_path, ::strerror(errno)); + fmt::print("Could not create '{}' directory. error='{}'\n", isol_cgroup_path, ::strerror(errno)); return false; } @@ -163,7 +163,7 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) return false; } - // Finally move itself to isolcated cgroup. + // Finally move itself to isolated cgroup. move_to_cgroup(isol_cgroup_path); return true; @@ -186,7 +186,7 @@ void srsran::cleanup_cgroups() move_procs_between_cgroups(root_cgroup_path, fmt::format("{}{}", housekeeping_cgroup_path, "/cgroup.procs")); // Remove previously created cgroups. if (::rmdir(housekeeping_cgroup_path) < 0) { - fmt::print("Could not delete {}. error=\"{}\"\n", housekeeping_cgroup_path, ::strerror(errno)); + fmt::print("Could not delete '{}'. error='{}'\n", housekeeping_cgroup_path, ::strerror(errno)); } cgroup_changed = true; } @@ -195,7 +195,7 @@ void srsran::cleanup_cgroups() // Move all processes to the parent cgroup. move_procs_between_cgroups(root_cgroup_path, fmt::format("{}{}", isolated_cgroup_path, "/cgroup.procs")); if (::rmdir(isolated_cgroup_path)) { - fmt::print("Could not delete {}. error=\"{}\"\n", isolated_cgroup_path, ::strerror(errno)); + fmt::print("Could not delete '{}'. error='{}'\n", isolated_cgroup_path, ::strerror(errno)); } cgroup_changed = true; } @@ -238,14 +238,14 @@ bool srsran::check_cpu_governor(srslog::basic_logger& logger) std::ifstream input(filename); if (input.fail()) { - logger.warning("Could not check scaling governor. filename={} error=\"{}\"", filename, ::strerror(errno)); + logger.warning("Could not check scaling governor. filename={} error={}", filename, ::strerror(errno)); return false; } std::string gov; std::getline(input, gov); if (input.fail()) { - logger.warning("Could not check scaling governor. filename={} error=\"{}\"", filename, ::strerror(errno)); + logger.warning("Could not check scaling governor. filename={} error={}", filename, ::strerror(errno)); return false; } @@ -268,14 +268,14 @@ bool srsran::check_drm_kms_polling(srslog::basic_logger& logger) std::ifstream input(filename); if (input.fail()) { - logger.warning("Could not check DRM KMS polling. filename={} error=\"{}\"", filename, ::strerror(errno)); + logger.warning("Could not check DRM KMS polling. filename={} error={}", filename, ::strerror(errno)); return false; } std::string polling; std::getline(input, polling); if (input.fail()) { - logger.warning("Could not check DRM KMS polling. filename={} error=\"{}\"", filename, ::strerror(errno)); + logger.warning("Could not check DRM KMS polling. filename={} error={}", filename, ::strerror(errno)); return false; } diff --git a/lib/support/timers.cpp b/lib/support/timers.cpp index f349e6a5a0..df617f5a71 100644 --- a/lib/support/timers.cpp +++ b/lib/support/timers.cpp @@ -126,7 +126,7 @@ void timer_manager::tick() // We move iterator already, in case, the current timer gets removed from the linked list. ++it; - // If the timer doesn't expire yet, continue the iteration in the same wheel bucket. + // If the timer does not expire yet, continue the iteration in the same wheel bucket. if (cur_time != timer.backend.timeout) { continue; } From 343bf5c06396f52caa687b1cc544020c05900c28 Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 9 Aug 2024 11:29:19 +0200 Subject: [PATCH 236/407] Support: More header cleanups --- include/srsran/support/benchmark_utils.h | 33 +++-- include/srsran/support/bit_encoding.h | 22 ++-- .../srsran/support/cpu_architecture_info.h | 4 +- include/srsran/support/cpu_features.h | 12 +- include/srsran/support/event_tracing.h | 14 +-- lib/support/bit_encoding.cpp | 114 +++++++++--------- lib/support/cpu_architecture_info.cpp | 12 +- lib/support/event_tracing.cpp | 14 +-- lib/support/executors/unique_thread.cpp | 10 +- .../benchmarks/du_high/du_high_benchmark.cpp | 2 +- 10 files changed, 117 insertions(+), 120 deletions(-) diff --git a/include/srsran/support/benchmark_utils.h b/include/srsran/support/benchmark_utils.h index 29934b81c2..4a944e5b63 100644 --- a/include/srsran/support/benchmark_utils.h +++ b/include/srsran/support/benchmark_utils.h @@ -19,32 +19,29 @@ namespace srsran { /// This function forbids the compiler from optimizing away expressions without side-effects. template -inline std::enable_if_t::value && (sizeof(T) <= sizeof(T*))> -do_not_optimize(T const& value) +inline std::enable_if_t && (sizeof(T) <= sizeof(T*))> do_not_optimize(T const& value) { asm volatile("" : : "r,m"(value) : "memory"); } template -inline std::enable_if_t::value || (sizeof(T) > sizeof(T*))> -do_not_optimize(T const& value) +inline std::enable_if_t || (sizeof(T) > sizeof(T*))> do_not_optimize(T const& value) { asm volatile("" : : "m"(value) : "memory"); } template -inline std::enable_if_t::value && (sizeof(T) <= sizeof(T*))> do_not_optimize(T& value) +inline std::enable_if_t && (sizeof(T) <= sizeof(T*))> do_not_optimize(T& value) { asm volatile("" : "+m,r"(value) : : "memory"); } template -inline std::enable_if_t::value || (sizeof(T) > sizeof(T*))> do_not_optimize(T& value) +inline std::enable_if_t || (sizeof(T) > sizeof(T*))> do_not_optimize(T& value) { asm volatile("" : "+m"(value) : : "memory"); } -/// \brief Describes a class for performing benchmarks. +/// Describes a class for performing benchmarks. class benchmarker { -private: /// Benchmark main title. std::string title; /// Number of repetitions. @@ -62,7 +59,7 @@ class benchmarker /// Collects different measurements. std::vector benchmark_results; - /// \brief Get the maximum measured execution time. + /// Get the maximum measured execution time. /// \return A pair of values containing the maximum execution time and the number of elements in order. std::pair get_max_meas_time_ns() const { @@ -76,10 +73,9 @@ class benchmarker /// Get percentile column width for execution time, including one decimal point. unsigned get_percentile_width_time(double scaling = 1.0) const { - uint64_t max_meas_ns = get_max_meas_time_ns().first; - unsigned percentile_width = - static_cast(std::ceil(std::log10(static_cast(max_meas_ns) * scaling))); - percentile_width = std::max(percentile_width, 6U); + uint64_t max_meas_ns = get_max_meas_time_ns().first; + auto percentile_width = static_cast(std::ceil(std::log10(static_cast(max_meas_ns) * scaling))); + percentile_width = std::max(percentile_width, 6U); return percentile_width + 2; } @@ -141,7 +137,7 @@ class benchmarker /// \param[in] time_ns Execution time in nanoseconds. /// \param[in] size Number of elements processed during the measurement. /// \return The calculated throughput. - static inline double convert_to_throughput(uint64_t time_ns, size_t size) + static double convert_to_throughput(uint64_t time_ns, size_t size) { time_ns = std::max(time_ns, 1UL); @@ -171,7 +167,7 @@ class benchmarker } /// Prints the time execution measurements in nanoseconds. - void print_percentiles_time(std::string units = "nanoseconds", double scaling = 1.0) const + void print_percentiles_time(const std::string& units = "nanoseconds", double scaling = 1.0) const { if (benchmark_results.empty()) { return; @@ -203,7 +199,7 @@ class benchmarker } } - /// \brief Prints the throughput measurements in millions of elements per seconds. + /// Prints the throughput measurements in millions of elements per seconds. /// \param[in] units Units counted in the throughput (ie. bits, symbols, etc.). void print_percentiles_throughput(const std::string& units, double scaling = 1.0) const { @@ -243,12 +239,13 @@ class benchmarker } /// \brief Performs a new performance measurement. + /// /// \tparam Func Lambda type to perform the benchmark. - /// \tparam PostFunc Lambda type to call after each Func call. + /// \tparam PostFunc Lambda type to call after each Func call. /// \param[in] description Measurement description for later reporting. /// \param[in] size Number of elements processed in the measurement. /// \param[in] function Lambda function to call repeatedly. - /// \param[in] post_func Lambda function to call repeatedly, after \c function, but without being accounted for + /// \param[in] post_func Lambda function to call repeatedly, after \c function, but without being accounted for /// in the benchmark results. template void new_measure(const std::string& description, diff --git a/include/srsran/support/bit_encoding.h b/include/srsran/support/bit_encoding.h index ec63fa395a..0af1dcfb1d 100644 --- a/include/srsran/support/bit_encoding.h +++ b/include/srsran/support/bit_encoding.h @@ -22,7 +22,7 @@ class bit_encoder explicit bit_encoder(byte_buffer& bytes) : writer(bytes) {} /// Get a view to held byte buffer. - srsran::byte_buffer_view data() const { return writer.view(); } + byte_buffer_view data() const { return writer.view(); } /// Gets number of written bytes. unsigned nof_bytes() const { return writer.length(); } @@ -47,17 +47,17 @@ class bit_encoder /// Append range of bytes into byte_buffer held by bit_encoder. /// \param bytes span of bytes. - bool pack_bytes(srsran::span bytes); + bool pack_bytes(span bytes); /// Append bytes of a byte_buffer into byte_buffer held by bit_encoder. - bool pack_bytes(srsran::byte_buffer_view bytes); + bool pack_bytes(byte_buffer_view bytes); /// Pads held buffer with zeros until the next byte. - void align_bytes_zero(); + void align_bytes_zero() { offset = 0; } private: /// Interface to byte buffer where bits are going to be appended. - srsran::byte_buffer_writer writer; + byte_buffer_writer writer; /// Offset of the next bit to be set. Values: (0..7). uint8_t offset = 0; }; @@ -66,7 +66,7 @@ class bit_encoder class bit_decoder { public: - explicit bit_decoder(srsran::byte_buffer_view buffer_) : buffer(buffer_), it(buffer.begin()) {} + explicit bit_decoder(byte_buffer_view buffer_) : buffer(buffer_), it(buffer.begin()) {} /// Get a view to held byte buffer. byte_buffer_view data() const { return buffer; } @@ -89,13 +89,13 @@ class bit_decoder /// \param val bitmap of bits read. /// \param n_bits number of bits to read. /// \return true if read is successful. False, if the number of bits read exceeded the byte_buffer size. - template + template bool unpack(T& val, uint32_t n_bits); /// Read unaligned bytes from underlying byte_buffer. /// \param bytes span of bytes where the result is stored. The span size defines the number of bytes to be read. /// \return true if successful. False if the number of bytes to be read exceeds the end of the byte_buffer. - bool unpack_bytes(srsran::span bytes); + bool unpack_bytes(span bytes); /// Create a view across \c n_bytes bytes of the underlying byte_buffer, starting at the first full byte from the /// current location. For this purpose, the decoder is first automatically aligned via \c align_bytes. @@ -108,9 +108,9 @@ class bit_decoder void align_bytes(); private: - srsran::byte_buffer_view buffer; - srsran::byte_buffer::const_iterator it; - uint8_t offset = 0; + byte_buffer_view buffer; + byte_buffer::const_iterator it; + uint8_t offset = 0; }; } // namespace srsran diff --git a/include/srsran/support/cpu_architecture_info.h b/include/srsran/support/cpu_architecture_info.h index 175e04388c..eb40c3de1f 100644 --- a/include/srsran/support/cpu_architecture_info.h +++ b/include/srsran/support/cpu_architecture_info.h @@ -21,7 +21,7 @@ class cpu_architecture_info /// Aggregates CPU information. struct cpu_description { /// Set of CPUs as returned by the OS. - cpu_set_t cpuset; + ::cpu_set_t cpuset; /// Total number of CPUs. size_t nof_cpus; /// Number of available CPUs. @@ -68,7 +68,7 @@ class cpu_architecture_info size_t get_host_nof_available_cpus() const { return cpu_desc.nof_available_cpus; } /// Get available CPUs as a cpu_set_t structure. - cpu_set_t get_available_cpuset() const { return cpu_desc.cpuset; } + ::cpu_set_t get_available_cpuset() const { return cpu_desc.cpuset; } /// Prints discovered CPU information. void print_cpu_info(srslog::basic_logger& logger) const; diff --git a/include/srsran/support/cpu_features.h b/include/srsran/support/cpu_features.h index c4e198fbd3..a953ac705c 100644 --- a/include/srsran/support/cpu_features.h +++ b/include/srsran/support/cpu_features.h @@ -10,9 +10,9 @@ #pragma once +#include "srsran/adt/to_array.h" #include "srsran/support/format_utils.h" #include "fmt/format.h" -#include namespace srsran { @@ -127,7 +127,8 @@ inline bool cpu_supports_feature(cpu_feature feature) } } -static const std::vector cpu_features_included = { +namespace detail { +constexpr auto cpu_features_included = to_array({ #ifdef __x86_64__ #ifdef __SSE4_1__ cpu_feature::sse4_1, @@ -168,12 +169,13 @@ static const std::vector cpu_features_included = { cpu_feature::neon, #endif // __ARM_NEON #endif // __aarch64__ -}; +}); +} // namespace detail inline std::string get_cpu_feature_info() { fmt::memory_buffer buffer; - for (cpu_feature feature : cpu_features_included) { + for (cpu_feature feature : detail::cpu_features_included) { #ifdef __x86_64__ format_to( buffer, "{}{}{}", buffer.size() == 0 ? "" : " ", feature, cpu_supports_feature(feature) ? "(ok)" : "(na)"); @@ -187,7 +189,7 @@ inline std::string get_cpu_feature_info() inline bool cpu_supports_included_features() { - for (cpu_feature feature : cpu_features_included) { + for (cpu_feature feature : detail::cpu_features_included) { if (!cpu_supports_feature(feature)) { return false; } diff --git a/include/srsran/support/event_tracing.h b/include/srsran/support/event_tracing.h index 3816412bda..fcf90f2d1d 100644 --- a/include/srsran/support/event_tracing.h +++ b/include/srsran/support/event_tracing.h @@ -28,13 +28,13 @@ using trace_clock = std::chrono::steady_clock; using trace_point = trace_clock::time_point; using trace_duration = std::chrono::microseconds; -/// \brief Open a file to write trace events to. +/// Open a file to write trace events to. void open_trace_file(std::string_view trace_file_name = "/tmp/srsran_trace.json"); -/// \brief Close the trace file. This function is called automatically when the program exits. +/// Close the trace file. This function is called automatically when the program exits. void close_trace_file(); -/// \brief Check if the trace file is open. +/// Check if the trace file is open. bool is_trace_file_open(); /// \brief Trace event used for events with defined name, starting point and duration. @@ -100,13 +100,13 @@ class file_event_tracer void operator<<(const instant_trace_event& event) const; }; -/// \brief Specialization of file_event_tracer that does not write any events. +/// Specialization of file_event_tracer that does not write any events. template <> class file_event_tracer : public detail::null_event_tracer { }; -/// \brief Class that repurposes a log channel to write trace events. +/// Class that repurposes a log channel to write trace events. template class logger_event_tracer { @@ -130,7 +130,7 @@ class logger_event_tracer : public detail::null_event_tracer { }; -/// \brief Class that writes trace events to a vector of strings for testing purposes. +/// Class that writes trace events to a vector of strings for testing purposes. class test_event_tracer { public: @@ -148,4 +148,4 @@ class test_event_tracer std::vector last_events; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/support/bit_encoding.cpp b/lib/support/bit_encoding.cpp index 6882ecb5df..9cb957e612 100644 --- a/lib/support/bit_encoding.cpp +++ b/lib/support/bit_encoding.cpp @@ -16,81 +16,68 @@ using namespace srsran; bool bit_encoder::pack(uint64_t val, uint32_t n_bits) { srsran_assert(n_bits <= 64U, "Invalid number of bits={} passed to pack()", n_bits); + while (n_bits > 0U) { if (offset == 0U) { if (not writer.append(0U)) { return false; } } - // apply mask if required + + // Apply mask if required. if (n_bits < 64U) { - uint64_t mask = (1UL << n_bits) - 1UL; // bitmap of n_bits ones. (UB if n_bits == 64) + // Bitmap of n_bits ones. (UB if n_bits == 64). + uint64_t mask = (1UL << n_bits) - 1UL; val = val & mask; } + + // In case n_bits < number of bits left in current byte (ie, last iteration). if (static_cast(8U - offset) > n_bits) { - // in case n_bits < number of bits left in current byte (ie, last iteration). auto shifted_val = static_cast(val << (8U - offset - n_bits)); writer.back() += shifted_val; offset += n_bits; n_bits = 0U; - } else { - // in case, space in current byte is lower or equal to n_bits (ie, not the last iteration). - auto shifted_val = static_cast(val >> (n_bits - 8U + offset)); - writer.back() += shifted_val; - n_bits -= 8U - offset; - offset = 0U; + continue; } + + // In case, space in current byte is lower or equal to n_bits (ie, not the last iteration). + auto shifted_val = static_cast(val >> (n_bits - 8U + offset)); + writer.back() += shifted_val; + n_bits -= 8U - offset; + offset = 0U; } + return true; } -bool bit_encoder::pack_bytes(srsran::span bytes) +bool bit_encoder::pack_bytes(span bytes) { if (bytes.empty()) { return true; } + + // Aligned case. if (offset == 0) { - // Aligned case - if (not writer.append(bytes)) { - return false; - } - } else { - for (uint8_t byte : bytes) { - if (not pack(byte, 8U)) { - return false; - } - } + return writer.append(bytes); } - return true; + + return std::all_of(bytes.begin(), bytes.end(), [this](auto byte) { return pack(byte, 8U); }); } -bool bit_encoder::pack_bytes(srsran::byte_buffer_view bytes) +bool bit_encoder::pack_bytes(byte_buffer_view bytes) { if (bytes.empty()) { return true; } + + // Aligned case. if (offset == 0) { - // Aligned case. - if (not writer.append(bytes)) { - return false; - } - } else { - for (uint8_t byte : bytes) { - if (not pack(byte, 8U)) { - return false; - } - } + return writer.append(bytes); } - return true; -} -void bit_encoder::align_bytes_zero() -{ - offset = 0; + return std::all_of(bytes.begin(), bytes.end(), [this](auto byte) { return pack(byte, 8U); }); } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool bit_decoder::advance_bits(uint32_t n_bits) { uint32_t extra_bits = (offset + n_bits) % 8U; @@ -100,8 +87,10 @@ bool bit_decoder::advance_bits(uint32_t n_bits) if (bytes_required > buffer.end() - it) { return false; } + it += bytes_offset; offset = extra_bits; + return true; } @@ -109,26 +98,31 @@ template bool bit_decoder::unpack(T& val, uint32_t n_bits) { srsran_assert(n_bits <= sizeof(T) * 8U, "unpack_bits() only supports up to {} bits", sizeof(T) * 8U); + val = 0; while (n_bits > 0U) { if (it == buffer.end()) { return false; } - if ((uint32_t)(8U - offset) > n_bits) { - uint8_t mask = (uint8_t)(1u << (8u - offset)) - (uint8_t)(1u << (8u - offset - n_bits)); - val += ((uint8_t)((*it) & mask)) >> (8u - offset - n_bits); + + if (static_cast(8U - offset) > n_bits) { + uint8_t mask = static_cast(1u << (8u - offset)) - static_cast(1u << (8u - offset - n_bits)); + val += (static_cast((*it) & mask)) >> (8u - offset - n_bits); offset += n_bits; n_bits = 0; - } else { - auto mask = static_cast((1u << (8u - offset)) - 1u); - val += ((T)((*it) & mask)) << (n_bits - 8 + offset); - n_bits -= 8 - offset; - offset = 0; - ++it; + continue; } + + auto mask = static_cast((1u << (8u - offset)) - 1u); + val += (static_cast((*it) & mask)) << (n_bits - 8 + offset); + n_bits -= 8 - offset; + offset = 0; + ++it; } + return true; } + template bool bit_decoder::unpack(bool&, uint32_t n_bits); template bool bit_decoder::unpack(int8_t&, uint32_t n_bits); template bool bit_decoder::unpack(uint8_t&, uint32_t n_bits); @@ -139,41 +133,47 @@ template bool bit_decoder::unpack(uint32_t&, uint32_t n_bits); template bool bit_decoder::unpack(int64_t&, uint32_t n_bits); template bool bit_decoder::unpack(uint64_t&, uint32_t n_bits); -bool bit_decoder::unpack_bytes(srsran::span bytes) +bool bit_decoder::unpack_bytes(span bytes) { if (bytes.empty()) { return true; } + if (static_cast(bytes.size()) > buffer.end() - it) { return false; } + + // Aligned case if (offset == 0) { - // Aligned case std::copy(it, it + bytes.size(), bytes.begin()); it += bytes.size(); - } else { - // Unaligned case - for (uint32_t i = 0; i < bytes.size(); ++i) { - if (not unpack(bytes[i], 8)) { - return false; - } + return true; + } + + // Unaligned case. + for (auto& byte : bytes) { + if (not unpack(byte, 8)) { + return false; } } + return true; } byte_buffer_view bit_decoder::unpack_aligned_bytes(size_t n_bytes) { - byte_buffer_view result{}; + byte_buffer_view result; align_bytes(); if (n_bytes == 0) { return result; } + if (static_cast(n_bytes) > buffer.end() - it) { return result; } result = byte_buffer_view{it, it + n_bytes}; it += n_bytes; + return result; } diff --git a/lib/support/cpu_architecture_info.cpp b/lib/support/cpu_architecture_info.cpp index d5b73ddaf0..ae473af32d 100644 --- a/lib/support/cpu_architecture_info.cpp +++ b/lib/support/cpu_architecture_info.cpp @@ -43,12 +43,12 @@ static interval parse_cpu_range(const std::string& value) auto parse_result = parse_one_cpu(str); range.push_back(parse_result); } - return interval(range[0], range[1]); + return {range[0], range[1]}; } -// Obtain CPU description at the start of the application. This value is affected by commands or tools like taskset, -// which limit the number of cores available to the application. However, frameworks (e.g. DPDK) that affect the -// affinities of the main thread in the main() function will not affect this value. +/// Obtain CPU description at the start of the application. This value is affected by commands or tools like taskset, +/// which limit the number of cores available to the application. However, frameworks (e.g. DPDK) that affect the +/// affinities of the main thread in the main() function will not affect this value. const cpu_architecture_info::cpu_description cpu_architecture_info::cpu_desc = cpu_architecture_info::discover_cpu_architecture(); @@ -61,7 +61,7 @@ cpu_architecture_info::cpu_description cpu_architecture_info::discover_cpu_archi } cpu_description cpuinfo; - cpu_set_t& cpuset = cpuinfo.cpuset; + ::cpu_set_t& cpuset = cpuinfo.cpuset; // Discover host CPU architecture. CPU_ZERO(&cpuset); @@ -108,7 +108,7 @@ cpu_architecture_info::cpu_description cpu_architecture_info::discover_cpu_archi // Parse /sys/devices/system/cpu/cpu*/topology/thread_siblings_list to get the lists of logical cores belonging to // the same physical core. - auto sort_function = [](std::string a, std::string b) { + auto sort_function = [](const std::string& a, const std::string& b) { auto get_first_cpu = [](const std::string& line) { std::string str; std::istringstream iss(line); diff --git a/lib/support/event_tracing.cpp b/lib/support/event_tracing.cpp index ffcf55b1ba..26e4828708 100644 --- a/lib/support/event_tracing.cpp +++ b/lib/support/event_tracing.cpp @@ -66,12 +66,10 @@ class event_trace_writer private: FILE* fptr; - - // Task worker to process events. + /// Task worker to process events. general_task_worker trace_worker; - - bool first_entry = true; - std::atomic warn_logged{false}; + bool first_entry = true; + std::atomic warn_logged{false}; }; struct trace_event_extended : public trace_event { @@ -170,8 +168,8 @@ struct formatter : public basic_fmt_parser { template <> struct formatter : public basic_fmt_parser { template - auto format(const instant_trace_event_extended& event, FormatContext& ctx) - -> decltype(std::declval().out()) + auto format(const instant_trace_event_extended& event, + FormatContext& ctx) -> decltype(std::declval().out()) { static const char* scope_str[] = {"g", "p", "t"}; @@ -267,4 +265,4 @@ void test_event_tracer::operator<<(const trace_thres_event& event) void test_event_tracer::operator<<(const instant_trace_event& event) { last_events.push_back(fmt::format("{}", instant_trace_event_extended{event})); -} \ No newline at end of file +} diff --git a/lib/support/executors/unique_thread.cpp b/lib/support/executors/unique_thread.cpp index 56f32a7e76..51e403f917 100644 --- a/lib/support/executors/unique_thread.cpp +++ b/lib/support/executors/unique_thread.cpp @@ -39,8 +39,8 @@ static bool thread_set_affinity(pthread_t t, const os_sched_affinity_bitmask& bi "Warning: The CPU affinity of thread \"{}\" contains the following invalid CPU ids: {}\n", name, invalid_ids); } - cpu_set_t* cpusetp = CPU_ALLOC(bitmap.size()); - size_t cpuset_size = CPU_ALLOC_SIZE(bitmap.size()); + ::cpu_set_t* cpusetp = CPU_ALLOC(bitmap.size()); + size_t cpuset_size = CPU_ALLOC_SIZE(bitmap.size()); CPU_ZERO_S(cpuset_size, cpusetp); for (size_t i = 0; i < bitmap.size(); ++i) { @@ -77,13 +77,13 @@ static void print_thread_priority(pthread_t t, const char* tname, std::thread::i return; } - cpu_set_t cpuset; + ::cpu_set_t cpuset; struct sched_param param; int policy; const char* p; int s, j; - s = pthread_getaffinity_np(t, sizeof(cpu_set_t), &cpuset); + s = pthread_getaffinity_np(t, sizeof(::cpu_set_t), &cpuset); if (s != 0) { printf("error pthread_getaffinity_np: %s\n", strerror(s)); } @@ -119,7 +119,7 @@ const os_sched_affinity_bitmask& os_sched_affinity_bitmask::available_cpus() { static os_sched_affinity_bitmask available_cpus_mask = []() { os_sched_affinity_bitmask bitmask; - cpu_set_t cpuset = cpu_architecture_info::get().get_available_cpuset(); + ::cpu_set_t cpuset = cpu_architecture_info::get().get_available_cpuset(); for (size_t i = 0; i < bitmask.size(); ++i) { if (CPU_ISSET(i, &cpuset)) { bitmask.cpu_bitset.set(i); diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index bf23144db0..6b2adc4b06 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -1237,7 +1237,7 @@ static void configure_main_thread(span du_cell_cores) // Set main test thread to use same cores as du_cell. if (not du_cell_cores.empty()) { - cpu_set_t cpuset; + ::cpu_set_t cpuset; CPU_ZERO(&cpuset); for (unsigned i : du_cell_cores) { CPU_SET(i, &cpuset); From fe290383f192a9d05319512b6a191e472ec6e9cd Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 9 Aug 2024 11:57:33 +0200 Subject: [PATCH 237/407] Support: minor cosmetic changes --- include/srsran/support/async/protocol_transaction_manager.h | 2 +- .../support/memory_pool/fixed_size_memory_block_pool.h | 6 +++--- include/srsran/support/memory_pool/memory_block_list.h | 6 +++--- lib/support/bit_encoding.cpp | 2 +- lib/support/byte_buffer.cpp | 2 +- lib/support/executors/task_execution_manager.cpp | 4 ++-- lib/support/sdu_window_impl.h | 4 ++-- lib/support/sysinfo.cpp | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/srsran/support/async/protocol_transaction_manager.h b/include/srsran/support/async/protocol_transaction_manager.h index acae9f5cb1..af7ea46b95 100644 --- a/include/srsran/support/async/protocol_transaction_manager.h +++ b/include/srsran/support/async/protocol_transaction_manager.h @@ -165,7 +165,7 @@ class protocol_transaction_manager public: /// Time limit for a transaction to complete. - const static std::chrono::milliseconds max_timeout; + static const std::chrono::milliseconds max_timeout; explicit protocol_transaction_manager(protocol_transaction_id_t nof_transaction_ids_, timer_factory timer_service_) : nof_transaction_ids(nof_transaction_ids_), timer_service(timer_service_) diff --git a/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h b/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h index 983fc8268c..6ed92391af 100644 --- a/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h +++ b/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h @@ -56,10 +56,10 @@ template class fixed_size_memory_block_pool { /// The number of blocks in batch that the worker can steal from the central cache. - constexpr static size_t block_batch_size = 32U; + static constexpr size_t block_batch_size = 32U; /// The number of batches of blocks that a worker can store in its own thread for non-contended access. - constexpr static size_t MAX_LOCAL_BATCH_CAPACITY = 64U; + static constexpr size_t MAX_LOCAL_BATCH_CAPACITY = 64U; /// A batch of memory blocks that is exchanged in bulk between the central and local caches. using memory_block_batch = free_memory_block_list; @@ -71,7 +71,7 @@ class fixed_size_memory_block_pool // to account the potential number of producers. The way to exactly over-dimension this queue is inconvenient, so // we just try to conservatively ensure it can accommodate up to 32 producers for a block size of 32. If this is // not enough, the queue will resize itself and malloc in the process. - const static size_t OVER_DIM_CENTRAL_CACHE = 2 * 32 * 32; + static const size_t OVER_DIM_CENTRAL_CACHE = 2 * 32 * 32; /// Ctor of the memory pool. It is set as private because the class works as a singleton. explicit fixed_size_memory_block_pool(size_t nof_blocks_, size_t memory_block_size_) : diff --git a/include/srsran/support/memory_pool/memory_block_list.h b/include/srsran/support/memory_pool/memory_block_list.h index ee3983c41f..e4a92f2016 100644 --- a/include/srsran/support/memory_pool/memory_block_list.h +++ b/include/srsran/support/memory_pool/memory_block_list.h @@ -32,8 +32,8 @@ class intrusive_memory_block_list node* tail = nullptr; std::size_t count = 0; - constexpr static std::size_t min_memory_block_size() { return sizeof(node); } - constexpr static std::size_t min_memory_block_align() { return alignof(node); } + static constexpr std::size_t min_memory_block_size() { return sizeof(node); } + static constexpr std::size_t min_memory_block_align() { return alignof(node); } /// Pushes a new memory block to the linked list. void push(void* block) noexcept @@ -227,4 +227,4 @@ class concurrent_free_memory_block_list mutable std::mutex mutex; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/support/bit_encoding.cpp b/lib/support/bit_encoding.cpp index 9cb957e612..f4d865074f 100644 --- a/lib/support/bit_encoding.cpp +++ b/lib/support/bit_encoding.cpp @@ -94,7 +94,7 @@ bool bit_decoder::advance_bits(uint32_t n_bits) return true; } -template +template bool bit_decoder::unpack(T& val, uint32_t n_bits) { srsran_assert(n_bits <= sizeof(T) * 8U, "unpack_bits() only supports up to {} bits", sizeof(T) * 8U); diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index 93a2c7af16..97d337e6b1 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -25,7 +25,7 @@ detail::byte_buffer_segment_pool& srsran::detail::get_default_byte_buffer_segmen { // Initialize byte buffer segment pool, if not yet initialized. // Note: In case of unit tests, this function will be called rather than init_byte_buffer_segment_pool(...). - constexpr static size_t default_byte_buffer_segment_pool_size = 16384; + static constexpr size_t default_byte_buffer_segment_pool_size = 16384; static auto& pool = detail::byte_buffer_segment_pool::get_instance(default_byte_buffer_segment_pool_size, byte_buffer_segment_pool_default_segment_size()); return pool; diff --git a/lib/support/executors/task_execution_manager.cpp b/lib/support/executors/task_execution_manager.cpp index 19d8256479..6e2d1d8a01 100644 --- a/lib/support/executors/task_execution_manager.cpp +++ b/lib/support/executors/task_execution_manager.cpp @@ -391,8 +391,8 @@ struct priority_worker_pool_context final : public common_task_execution_context [¶ms]() { std::vector qparams{params.queues.size()}; for (unsigned i = 0; i != params.queues.size(); ++i) { - report_error_if_not(params.queues[i].policy != srsran::concurrent_queue_policy::lockfree_mpmc or - params.queues[i].policy != srsran::concurrent_queue_policy::locking_mpmc, + report_error_if_not(params.queues[i].policy != concurrent_queue_policy::lockfree_mpmc or + params.queues[i].policy != concurrent_queue_policy::locking_mpmc, "Only MPMC queues are supported for worker pools"); qparams[i].policy = params.queues[i].policy; qparams[i].size = params.queues[i].size; diff --git a/lib/support/sdu_window_impl.h b/lib/support/sdu_window_impl.h index 7d6659ba77..fc9bd73036 100644 --- a/lib/support/sdu_window_impl.h +++ b/lib/support/sdu_window_impl.h @@ -58,8 +58,8 @@ class sdu_window_impl final : public sdu_window bool has_sn(uint32_t sn) const override { return window.contains(sn); } private: - PREFIXED_LOGGER& logger; - srsran::circular_map window; + PREFIXED_LOGGER& logger; + circular_map window; }; } // namespace srsran diff --git a/lib/support/sysinfo.cpp b/lib/support/sysinfo.cpp index 9f94006fba..ca2cf8559c 100644 --- a/lib/support/sysinfo.cpp +++ b/lib/support/sysinfo.cpp @@ -233,7 +233,7 @@ bool srsran::check_cpu_governor(srslog::basic_logger& logger) { static const char* filename_base = "/sys/devices/system/cpu/cpu"; - for (unsigned int i = 0, e = std::thread::hardware_concurrency(); i != e; ++i) { + for (unsigned i = 0, e = std::thread::hardware_concurrency(); i != e; ++i) { std::string filename = fmt::format("{}{}{}", filename_base, i, "/cpufreq/scaling_governor"); std::ifstream input(filename); From f45073fc962e6993fa0be5cd2c6b27039d6607ee Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 9 Aug 2024 12:45:54 +0200 Subject: [PATCH 238/407] Support: Fix PID conversion to number in sysinfo --- lib/support/event_tracing.cpp | 4 ++-- lib/support/sysinfo.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/support/event_tracing.cpp b/lib/support/event_tracing.cpp index 26e4828708..18de4b2c5c 100644 --- a/lib/support/event_tracing.cpp +++ b/lib/support/event_tracing.cpp @@ -168,8 +168,8 @@ struct formatter : public basic_fmt_parser { template <> struct formatter : public basic_fmt_parser { template - auto format(const instant_trace_event_extended& event, - FormatContext& ctx) -> decltype(std::declval().out()) + auto format(const instant_trace_event_extended& event, FormatContext& ctx) + -> decltype(std::declval().out()) { static const char* scope_str[] = {"g", "p", "t"}; diff --git a/lib/support/sysinfo.cpp b/lib/support/sysinfo.cpp index ca2cf8559c..e39c8f60d7 100644 --- a/lib/support/sysinfo.cpp +++ b/lib/support/sysinfo.cpp @@ -142,8 +142,9 @@ bool srsran::configure_cgroups(const os_sched_affinity_bitmask& isol_cpus) return false; } - ::pid_t pid = {}; - if (std::from_chars(pid_buffer, pid_buffer + ::strlen(pid_buffer), pid).ec != std::errc()) { + char* end = nullptr; + ::pid_t pid = std::strtol(pid_buffer, &end, 10); + if (&pid_buffer[0] == end) { fmt::print("Unable to parse PID\n"); return false; } From 8b411e586278b2c9529b9fe59d1595aee1b290ad Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 12 Aug 2024 15:00:55 +0200 Subject: [PATCH 239/407] sched: validate PUCCH configuration only if present in Serving Cell configuration --- lib/scheduler/config/scheduler_ue_config_validator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/config/scheduler_ue_config_validator.cpp b/lib/scheduler/config/scheduler_ue_config_validator.cpp index d823a6748b..64ac11465b 100644 --- a/lib/scheduler/config/scheduler_ue_config_validator.cpp +++ b/lib/scheduler/config/scheduler_ue_config_validator.cpp @@ -28,7 +28,9 @@ srsran::config_validators::validate_sched_ue_creation_request_message(const sche HANDLE_ERROR(validate_pdsch_cfg(cell.serv_cell_cfg)); - HANDLE_ERROR(validate_pucch_cfg(cell.serv_cell_cfg, cell_cfg.dl_carrier.nof_ant)); + if (cell.serv_cell_cfg.ul_config.has_value() and cell.serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.has_value()) { + HANDLE_ERROR(validate_pucch_cfg(cell.serv_cell_cfg, cell_cfg.dl_carrier.nof_ant)); + } HANDLE_ERROR(validate_csi_meas_cfg(cell.serv_cell_cfg, cell_cfg.tdd_cfg_common)); From e13a6f916aca31512ae5677df7ebd9fcfd85c7cc Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 12 Aug 2024 15:01:40 +0200 Subject: [PATCH 240/407] sched: dont add UE to slice if it does not have dedicated configuration --- lib/scheduler/slicing/slice_scheduler.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 09320d42f8..96b77f3c11 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -61,6 +61,12 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { + // [Implementation-defined] UE does not have complete dedicated configuration. Hence, UE won't be added to the slice. + if ((ue_cfg.logical_channels().size() == 1 and ue_cfg.logical_channels().back().lcid == LCID_SRB0) or + not ue_cfg.pcell_cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg.has_value() or + ue_cfg.pcell_cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.empty()) { + return; + } for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); if (ues.contains(ue_cfg.ue_index)) { @@ -78,12 +84,7 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co } // Add new bearers. - for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg); - if (ues.contains(next_ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[next_ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); - } - } + add_ue(next_ue_cfg); } void slice_scheduler::rem_ue(du_ue_index_t ue_idx) From baa397042c0f91cc3b70b9d52d93fe3dac9c995c Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 12 Aug 2024 15:59:21 +0200 Subject: [PATCH 241/407] sched: use 8 DL HARQ process if nof. HARQ process is not set in PDSCH-ServingCellConfig --- lib/scheduler/ue_scheduling/ue_cell.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index ced808bb50..847d624de0 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -22,6 +22,10 @@ using namespace srsran; /// Number of UL HARQs reserved per UE (Implementation-defined) constexpr unsigned NOF_UL_HARQS = 16; +/// The default number of HARQ processes to be used on the PDSCH of a serving cell. See TS 38.331, \c +/// nrofHARQ-ProcessesForPDSCH. +constexpr unsigned DEFAULT_NOF_DL_HARQS = 8; + ue_cell::ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, @@ -29,7 +33,9 @@ ue_cell::ue_cell(du_ue_index_t ue_index_, ue_index(ue_index_), cell_index(ue_cell_cfg_.cell_cfg_common.cell_index), harqs(crnti_val, - (unsigned)ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg->nof_harq_proc, + ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg.has_value() + ? (unsigned)ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg->nof_harq_proc + : DEFAULT_NOF_DL_HARQS, NOF_UL_HARQS, harq_timeout_notifier, ue_cell_cfg_.cell_cfg_common.ntn_cs_koffset), From f9e9e7be5df514ab0c0422dafc1c0225dfc6040c Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 12 Aug 2024 16:00:18 +0200 Subject: [PATCH 242/407] unittest: add test for scheduling UE with empty SpCell configuration --- .../scheduler/multiple_ue_sched_test.cpp | 32 +++++++++++++++++++ .../scheduler/test_utils/config_generators.h | 26 +++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index 8f0b06202c..0e135a1e2f 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -1268,6 +1268,38 @@ TEST_F(single_ue_sched_tester, srb0_retransmission_not_scheduled_if_csi_rs_is_pr } } +TEST_F(single_ue_sched_tester, test_ue_scheduling_with_empty_spcell_cfg) +{ + setup_sched(create_expert_config(10), create_custom_cell_config_request(srsran::duplex_mode::TDD)); + // Add UE. + const auto& cell_cfg_params = create_custom_cell_cfg_builder_params(srsran::duplex_mode::TDD); + auto ue_creation_req = test_helpers::create_empty_spcell_cfg_sched_ue_creation_request(cell_cfg_params); + ue_creation_req.starts_in_fallback = true; + + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(allocate_rnti()); + bench->sch.handle_ue_creation_request(ue_creation_req); + bench->ues[ue_creation_req.ue_index] = sched_test_ue{ue_creation_req.crnti, {}, {}, ue_creation_req}; + + run_slot(); + + // Push DL buffer status indication. + push_buffer_state_to_dl_ue(to_du_ue_index(0), 100, LCID_SRB0); + + bool successfully_scheduled_srb0_bytes = false; + for (unsigned i = 0; i != 20; ++i) { + run_slot(); + auto& test_ue = get_ue(to_du_ue_index(0)); + const auto* grant = find_ue_pdsch(test_ue); + if (grant != nullptr) { + successfully_scheduled_srb0_bytes = true; + break; + } + } + ASSERT_TRUE(successfully_scheduled_srb0_bytes) + << fmt::format("SRB0 not scheduled for UE with empty SpCell configuration"); +} + // Dummy function overload of template void testing::internal::PrintTo(const T& value, ::std::ostream* os). // This prevents valgrind from complaining about uninitialized variables. // See https://github.com/google/googletest/issues/3805. diff --git a/tests/unittests/scheduler/test_utils/config_generators.h b/tests/unittests/scheduler/test_utils/config_generators.h index 0cbb399c2a..e63b81496b 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.h +++ b/tests/unittests/scheduler/test_utils/config_generators.h @@ -108,6 +108,32 @@ create_default_sched_ue_creation_request(const cell_config_builder_params& pa return msg; } +inline sched_ue_creation_request_message +create_empty_spcell_cfg_sched_ue_creation_request(const cell_config_builder_params& params = {}) +{ + sched_ue_creation_request_message msg{}; + + msg.ue_index = to_du_ue_index(0); + msg.crnti = to_rnti(0x4601); + + cell_config_dedicated cfg; + cfg.serv_cell_idx = to_serv_cell_index(0); + serving_cell_config& serv_cell = cfg.serv_cell_cfg; + + serv_cell.cell_index = to_du_cell_index(0); + // > TAG-ID. + serv_cell.tag_id = static_cast(0); + + msg.cfg.cells.emplace(); + msg.cfg.cells->push_back(cfg); + + msg.cfg.lc_config_list.emplace(); + msg.cfg.lc_config_list->resize(1); + (*msg.cfg.lc_config_list)[0] = config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB0); + + return msg; +} + inline rach_indication_message generate_rach_ind_msg(slot_point prach_slot_rx, rnti_t temp_crnti, unsigned rapid = 0) { rach_indication_message msg{}; From f9628fb06e58e70bd895953cf5c269163eddf58a Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 13 Aug 2024 09:11:19 +0200 Subject: [PATCH 243/407] sched: move the check for completeness of UE configuration from slice scheduler to UE configuration --- lib/scheduler/config/ue_configuration.cpp | 18 ++++++++++++++++++ lib/scheduler/config/ue_configuration.h | 9 +++++++++ lib/scheduler/slicing/slice_scheduler.cpp | 6 ++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/config/ue_configuration.cpp b/lib/scheduler/config/ue_configuration.cpp index 1dda0a5991..4cac64f9c3 100644 --- a/lib/scheduler/config/ue_configuration.cpp +++ b/lib/scheduler/config/ue_configuration.cpp @@ -741,6 +741,13 @@ void ue_cell_configuration::configure_bwp_ded_cfg(bwp_id_t bwpid, const bwp_upli } } +bool ue_cell_configuration::is_cfg_dedicated_complete() const +{ + return (cell_cfg_ded.init_dl_bwp.pdcch_cfg.has_value() and + not cell_cfg_ded.init_dl_bwp.pdcch_cfg->search_spaces.empty()) and + (cell_cfg_ded.ul_config.has_value() and cell_cfg_ded.ul_config->init_ul_bwp.pucch_cfg.has_value()); +} + ue_configuration::ue_configuration(du_ue_index_t ue_index_, rnti_t crnti_) : ue_index(ue_index_), crnti(crnti_) {} ue_configuration::ue_configuration(du_ue_index_t ue_index_, @@ -820,3 +827,14 @@ void ue_configuration::update(const cell_common_configuration_list& common_cells } } } + +bool ue_configuration::is_ue_cfg_complete() const +{ + // [Implementation-defined] UE with only SRB0 configured is considered to not have complete UE configuration yet. + if ((lc_list.size() == 1 and lc_list.back().lcid == LCID_SRB0)) { + return false; + } + return std::any_of(du_cells.begin(), du_cells.end(), [](const auto& ue_cell_cfg) { + return ue_cell_cfg->is_cfg_dedicated_complete(); + }); +} diff --git a/lib/scheduler/config/ue_configuration.h b/lib/scheduler/config/ue_configuration.h index 32773fbf33..1045d30f39 100644 --- a/lib/scheduler/config/ue_configuration.h +++ b/lib/scheduler/config/ue_configuration.h @@ -112,6 +112,11 @@ class ue_cell_configuration const serving_cell_config& cfg_dedicated() const { return cell_cfg_ded; } + /// Returns whether UE dedicated configuration is considered complete or not for scheduling the UE as a non-fallback + /// UE. + /// \remark UE can be scheduled in fallback scheduler even if UE does not have a complete UE dedicated configuration. + bool is_cfg_dedicated_complete() const; + bool has_bwp_id(bwp_id_t bwp_id) const { return bwp_table[bwp_id].dl_common != nullptr; } /// Get BWP information given a BWP-Id. @@ -229,6 +234,10 @@ class ue_configuration /// Update the UE dedicated configuration given a configuration request coming from outside the scheduler. void update(const cell_common_configuration_list& common_cells, const sched_ue_config_request& cfg_req); + /// Returns whether UE configuration is considered complete or not for scheduling the UE as a non-fallback UE. + /// \remark UE can be scheduled in fallback scheduler even if UE does not have a complete configuration. + bool is_ue_cfg_complete() const; + private: // List of configured logical channels std::vector lc_list; diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 96b77f3c11..9ddfbe7697 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -61,10 +61,8 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { - // [Implementation-defined] UE does not have complete dedicated configuration. Hence, UE won't be added to the slice. - if ((ue_cfg.logical_channels().size() == 1 and ue_cfg.logical_channels().back().lcid == LCID_SRB0) or - not ue_cfg.pcell_cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg.has_value() or - ue_cfg.pcell_cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.empty()) { + // [Implementation-defined] UE does not have complete configuration. Hence, UE won't be added to the slice. + if (not ue_cfg.is_ue_cfg_complete()) { return; } for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { From 1a0d06af1c04d696c02af9fe776afaf04faf040a Mon Sep 17 00:00:00 2001 From: sauka Date: Tue, 13 Aug 2024 10:26:37 +0300 Subject: [PATCH 244/407] ofh: fix neon compilation --- lib/ofh/compression/iq_compression_bfp_neon.cpp | 3 ++- lib/ofh/compression/packing_utils_neon.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ofh/compression/iq_compression_bfp_neon.cpp b/lib/ofh/compression/iq_compression_bfp_neon.cpp index 27b0069871..e34b071373 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.cpp +++ b/lib/ofh/compression/iq_compression_bfp_neon.cpp @@ -13,6 +13,7 @@ #include "packing_utils_neon.h" #include "quantizer.h" #include "srsran/ofh/compression/compression_properties.h" +#include "srsran/support/math_utils.h" using namespace srsran; using namespace ofh; @@ -81,7 +82,7 @@ void iq_compression_bfp_neon::compress(span buffer, // Auxiliary arrays used for float to fixed point conversion of the input data. std::array input_quantized; - span float_samples_span(reinterpret_cast(input.data()), input.size() * 2U); + span float_samples_span(reinterpret_cast(iq_data.data()), iq_data.size() * 2U); span input_quantized_span(input_quantized.data(), float_samples_span.size()); // Performs conversion of input brain float values to signed 16-bit integers. diff --git a/lib/ofh/compression/packing_utils_neon.h b/lib/ofh/compression/packing_utils_neon.h index 84c1ca53dd..b457a59e4b 100644 --- a/lib/ofh/compression/packing_utils_neon.h +++ b/lib/ofh/compression/packing_utils_neon.h @@ -11,6 +11,7 @@ #pragma once #include "neon_helpers.h" +#include "srsran/adt/span.h" #include "srsran/support/error_handling.h" namespace srsran { From f513e4efb16603fe6b0caacfdcfb4016de8afdf5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 12 Aug 2024 18:34:18 +0200 Subject: [PATCH 245/407] du_manager: when UE resources fail to be allocated, the DU manager still sends initial UL RRC Message with empty DU-to-DU container --- .../procedures/ue_creation_procedure.cpp | 87 +++++----- .../du_pucch_resource_manager.cpp | 15 ++ .../du_pucch_resource_manager.h | 3 + .../du_ran_resource_manager.h | 15 +- .../du_ran_resource_manager_impl.cpp | 15 +- .../du_ran_resource_manager_impl.h | 4 +- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 6 +- .../du_manager/du_manager_test_helpers.cpp | 4 +- .../du_manager/du_manager_test_helpers.h | 4 +- .../du_ran_resource_manager_test.cpp | 156 +++++++++++------- 10 files changed, 182 insertions(+), 127 deletions(-) diff --git a/lib/du_manager/procedures/ue_creation_procedure.cpp b/lib/du_manager/procedures/ue_creation_procedure.cpp index 34379f1a9b..13a39b5c40 100644 --- a/lib/du_manager/procedures/ue_creation_procedure.cpp +++ b/lib/du_manager/procedures/ue_creation_procedure.cpp @@ -93,15 +93,17 @@ void ue_creation_procedure::operator()(coro_context>& ctx) expected ue_creation_procedure::create_du_ue_context() { // Create a DU UE resource manager, which will be responsible for managing bearer and PUCCH resources. - ue_ran_resource_configurator ue_res = du_res_alloc.create_ue_resource_configurator(req.ue_index, req.pcell_index); - if (ue_res.empty()) { - return make_unexpected(ue_res.get_error()); + auto alloc_result = du_res_alloc.create_ue_resource_configurator(req.ue_index, req.pcell_index); + if (not alloc_result.has_value()) { + // The UE resource manager could not create a new UE entry. + return make_unexpected(alloc_result.error()); } // Fetch the DU cell configuration of the primary cell UE is connected to. const auto& cell_cfg = du_params.ran.cells[req.pcell_index]; // Create the DU UE context. - return ue_mng.add_ue(du_ue_context(req.ue_index, req.pcell_index, req.tc_rnti, cell_cfg.nr_cgi), std::move(ue_res)); + return ue_mng.add_ue(du_ue_context(req.ue_index, req.pcell_index, req.tc_rnti, cell_cfg.nr_cgi), + std::move(alloc_result.value())); } async_task ue_creation_procedure::clear_ue() @@ -128,10 +130,13 @@ async_task ue_creation_procedure::clear_ue() bool ue_creation_procedure::setup_du_ue_resources() { - // > Verify that the UE resource configurator is correctly setup. - if (ue_ctx->resources.empty()) { - proc_logger.log_proc_failure("Unable to allocate RAN resources for UE"); - return false; + // SRB0 is always created. + ue_ctx->bearers.add_srb(srb_id_t::srb0); + + if (ue_ctx->resources.resource_alloc_failed()) { + // In special case, where the RAN resources were not allocated successfully for the UE (e.g. lack of PUCCH space), + // only SRB0 is added, which will be used for RRC Reject. + return true; } // Allocate PCell PHY/MAC resources for DU UE. @@ -146,8 +151,7 @@ bool ue_creation_procedure::setup_du_ue_resources() return false; } - // Create DU UE SRB0 and SRB1. - ue_ctx->bearers.add_srb(srb_id_t::srb0); + // Create DU UE SRB1. ue_ctx->bearers.add_srb(srb_id_t::srb1); return true; @@ -167,15 +171,18 @@ void ue_creation_procedure::create_rlc_srbs() du_params.rlc.pcap_writer)); // Create SRB1 RLC entity. - du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; - srb1.rlc_bearer = create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, - ue_ctx->ue_index, - ue_ctx->pcell_index, - srb1, - ue_ctx->resources->srbs[srb_id_t::srb1].rlc_cfg, - du_params.services, - ue_ctx->get_rlc_rlf_notifier(), - du_params.rlc.pcap_writer)); + if (ue_ctx->bearers.srbs().contains(srb_id_t::srb1)) { + du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; + srb1.rlc_bearer = + create_rlc_entity(make_rlc_entity_creation_message(du_params.ran.gnb_du_id, + ue_ctx->ue_index, + ue_ctx->pcell_index, + srb1, + ue_ctx->resources->srbs[srb_id_t::srb1].rlc_cfg, + du_params.services, + ue_ctx->get_rlc_rlf_notifier(), + du_params.rlc.pcap_writer)); + } } async_task ue_creation_procedure::create_mac_ue() @@ -219,22 +226,22 @@ f1ap_ue_creation_response ue_creation_procedure::create_f1ap_ue() f1ap_msg.ue_index = ue_ctx->ue_index; f1ap_msg.c_rnti = ue_ctx->rnti; f1ap_msg.pcell_index = ue_ctx->pcell_index; - f1ap_msg.f1c_bearers_to_add.resize(2); - - // Create SRB0 and SRB1. - du_ue_srb& srb0 = ue_ctx->bearers.srbs()[srb_id_t::srb0]; - f1ap_msg.f1c_bearers_to_add[0].srb_id = srb_id_t::srb0; - f1ap_msg.f1c_bearers_to_add[0].rx_sdu_notifier = &srb0.connector.f1c_rx_sdu_notif; - du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; - f1ap_msg.f1c_bearers_to_add[1].srb_id = srb_id_t::srb1; - f1ap_msg.f1c_bearers_to_add[1].rx_sdu_notifier = &srb1.connector.f1c_rx_sdu_notif; - - // Pack SRB1 configuration that is going to be passed in the F1AP DU-to-CU-RRC-Container IE to the CU as per TS38.473, - // Section 8.4.1.2. + + // Create SRBs. + f1ap_msg.f1c_bearers_to_add.reserve(ue_ctx->bearers.srbs().size()); + for (du_ue_srb& srb : ue_ctx->bearers.srbs()) { + f1c_bearer_to_addmod& f1c_bearer = f1ap_msg.f1c_bearers_to_add.emplace_back(); + f1c_bearer.srb_id = srb.srb_id; + f1c_bearer.rx_sdu_notifier = &srb.connector.f1c_rx_sdu_notif; + } + cell_group_cfg_s cell_group; - calculate_cell_group_config_diff(cell_group, {}, ue_ctx->resources.value()); + if (ue_ctx->bearers.srbs().contains(srb_id_t::srb1)) { + // If allocation of UE RAN resources was successful, the cellGroupConfig is not empty. + // Pack SRB1 configuration that is going to be passed in the F1AP DU-to-CU-RRC-Container IE to the CU as per + // TS38.473, Section 8.4.1.2. + calculate_cell_group_config_diff(cell_group, {}, ue_ctx->resources.value()); - { asn1::bit_ref bref{f1ap_msg.du_cu_rrc_container}; asn1::SRSASN_CODE result = cell_group.pack(bref); srsran_assert(result == asn1::SRSASN_SUCCESS, "Failed to generate CellConfigGroup"); @@ -254,10 +261,12 @@ void ue_creation_procedure::connect_layer_bearers() du_params.rlc.mac_ue_info_handler); // Connect SRB1 bearer layers. - du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; - srb1.connector.connect(ue_ctx->ue_index, - srb_id_t::srb1, - *f1ap_resp.f1c_bearers_added[1], - *srb1.rlc_bearer, - du_params.rlc.mac_ue_info_handler); + if (ue_ctx->bearers.srbs().contains(srb_id_t::srb1)) { + du_ue_srb& srb1 = ue_ctx->bearers.srbs()[srb_id_t::srb1]; + srb1.connector.connect(ue_ctx->ue_index, + srb_id_t::srb1, + *f1ap_resp.f1c_bearers_added[1], + *srb1.rlc_bearer, + du_params.rlc.mac_ue_info_handler); + } } diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index df2bbc87bd..e5a630eca7 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -221,6 +221,7 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) // Verify where there are SR and CSI resources to allocate a new UE. if (free_sr_list.empty() or (default_csi_report_cfg.has_value() and free_csi_list.empty())) { + disable_pucch_cfg(cell_grp_cfg); return false; } @@ -269,6 +270,7 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) } if (!sr_res_offset.has_value()) { + disable_pucch_cfg(cell_grp_cfg); return false; } @@ -320,6 +322,9 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) void du_pucch_resource_manager::dealloc_resources(cell_group_config& cell_grp_cfg) { + if (not cell_grp_cfg.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.has_value()) { + return; + } auto& sr_to_deallocate = cell_grp_cfg.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list.front(); cells[cell_grp_cfg.cells[0].serv_cell_cfg.cell_index].sr_res_offset_free_list.emplace_back( pucch_res_idx_to_sr_du_res_idx(sr_to_deallocate.pucch_res_id.cell_res_id), sr_to_deallocate.offset); @@ -449,3 +454,13 @@ unsigned du_pucch_resource_manager::pucch_res_idx_to_csi_du_res_idx(unsigned puc user_defined_pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets); } + +void du_pucch_resource_manager::disable_pucch_cfg(srsran::srs_du::cell_group_config& cell_grp_cfg) +{ + auto& serv_cell = cell_grp_cfg.cells[0].serv_cell_cfg; + + serv_cell.ul_config->init_ul_bwp.pucch_cfg.reset(); + if (serv_cell.csi_meas_cfg.has_value()) { + serv_cell.csi_meas_cfg.value().csi_report_cfg_list.clear(); + } +} diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h index bb23f72656..42f2b5de62 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.h @@ -78,6 +78,9 @@ class du_pucch_resource_manager [[nodiscard]] bool csi_offset_collides_with_sr(unsigned sr_offset, unsigned csi_offset) const; + /// Called when PUCCH allocation fails for a given UE. + void disable_pucch_cfg(cell_group_config& cell_grp_cfg); + // Parameters for PUCCH configuration passed by the user. const pucch_builder_params user_defined_pucch_cfg; const std::vector default_pucch_res_list; diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h index 4ef2b43bfe..a4e19c4ab7 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h @@ -45,9 +45,7 @@ class ue_ran_resource_configurator }; explicit ue_ran_resource_configurator(std::unique_ptr ue_res_, std::string error = {}) : - ue_res_impl(std::move(ue_res_)), - cached_res(ue_res_impl != nullptr ? &ue_res_impl->get() : nullptr), - configurator_error(ue_res_impl != nullptr ? std::string{} : error) + ue_res_impl(std::move(ue_res_)), cached_res(&ue_res_impl->get()), configurator_error(std::move(error)) { } @@ -65,11 +63,11 @@ class ue_ran_resource_configurator return ue_res_impl->update(pcell_index, upd_req, reestablished_context); } - /// \brief Checks whether the UE resources have been correctly allocated. - bool empty() const { return ue_res_impl == nullptr; } + /// \brief Checks whether the allocation of resources to the UE failed, due to lack of resources. + bool resource_alloc_failed() const { return not configurator_error.empty(); } /// \brief Returns the configurator error, which non-empty string only if the procedure failed. - std::string get_error() const { return empty() ? configurator_error : std::string{}; } + std::string get_error() const { return configurator_error; } const du_ue_resource_config& value() const { return *cached_res; } const du_ue_resource_config& operator*() const { return *cached_res; } @@ -88,8 +86,9 @@ class du_ran_resource_manager virtual ~du_ran_resource_manager() = default; /// \brief Create a new UE resource allocation config object. - virtual ue_ran_resource_configurator create_ue_resource_configurator(du_ue_index_t ue_index, - du_cell_index_t pcell_index) = 0; + /// \return UE Resource configuration if correctly created. Unexpected if no space in the manager was found. + virtual expected + create_ue_resource_configurator(du_ue_index_t ue_index, du_cell_index_t pcell_index) = 0; }; } // namespace srs_du diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index 542e69aaab..6297e45bef 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -49,24 +49,21 @@ du_ran_resource_manager_impl::du_ran_resource_manager_impl(span +du_ran_resource_manager_impl::create_ue_resource_configurator(du_ue_index_t ue_index, du_cell_index_t pcell_index) { if (ue_res_pool.contains(ue_index)) { - return ue_ran_resource_configurator{std::unique_ptr{nullptr}, - std::string("Double allocation of same UE not supported")}; + return make_unexpected(std::string("Double allocation of same UE not supported")); } ue_res_pool.emplace(ue_index); auto& mcg = ue_res_pool[ue_index].cg_cfg; // UE initialized PCell. + // Note: In case of lack of RAN resource availability, the return will be error type. error_type err = allocate_cell_resources(ue_index, pcell_index, SERVING_CELL_PCELL_IDX); - if (not err.has_value()) { - ue_res_pool.erase(ue_index); - return ue_ran_resource_configurator{std::unique_ptr{nullptr}, err.error()}; - } - return ue_ran_resource_configurator{std::make_unique(&mcg, *this, ue_index)}; + return ue_ran_resource_configurator{std::make_unique(&mcg, *this, ue_index), + err.has_value() ? std::string{} : err.error()}; } du_ue_resource_update_response diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h index 49c1423bb9..ce35de3b2b 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h @@ -56,8 +56,8 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager du_ran_resource_manager_impl& operator=(du_ran_resource_manager_impl&&) = delete; du_ran_resource_manager_impl& operator=(const du_ran_resource_manager_impl&) = delete; - ue_ran_resource_configurator create_ue_resource_configurator(du_ue_index_t ue_index, - du_cell_index_t pcell_index) override; + expected + create_ue_resource_configurator(du_ue_index_t ue_index, du_cell_index_t pcell_index) override; /// \brief Updates a UE's cell configuration context based on the F1 UE Context Update request. /// diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp index 881515f63a..fd17493ac5 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -59,8 +59,10 @@ void f1c_srb0_du_bearer::handle_sdu(byte_buffer_chain sdu) logger.error("UL {} SRB0 Tx PDU: Discarding Tx PDU. Cause: Failed to append SDU to RRC container.", ue_ctxt); return; } - init_msg->du_to_cu_rrc_container_present = true; - init_msg->du_to_cu_rrc_container = std::move(du_cu_rrc_container); + init_msg->du_to_cu_rrc_container_present = not du_cu_rrc_container.empty(); + if (init_msg->du_to_cu_rrc_container_present) { + init_msg->du_to_cu_rrc_container = std::move(du_cu_rrc_container); + } init_msg->sul_access_ind_present = false; init_msg->transaction_id = transaction.id(); init_msg->ran_ue_id_present = false; diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index ad1e5a7a83..ab50e8f5d5 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -57,12 +57,12 @@ const du_ue_resource_config& dummy_ue_resource_configurator_factory::dummy_resou return parent.ue_resource_pool[ue_index]; } -ue_ran_resource_configurator +expected dummy_ue_resource_configurator_factory::create_ue_resource_configurator(du_ue_index_t ue_index, du_cell_index_t pcell_index) { if (ue_resource_pool.count(ue_index) > 0) { - return ue_ran_resource_configurator{nullptr}; + return make_unexpected(std::string("Duplicate UE index")); } last_ue_index = ue_index; last_ue_pcell = pcell_index; diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index 02cd338d0c..ff1b7b679d 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -301,8 +301,8 @@ class dummy_ue_resource_configurator_factory : public du_ran_resource_manager dummy_ue_resource_configurator_factory(); - ue_ran_resource_configurator create_ue_resource_configurator(du_ue_index_t ue_index, - du_cell_index_t pcell_index) override; + expected + create_ue_resource_configurator(du_ue_index_t ue_index, du_cell_index_t pcell_index) override; }; f1ap_ue_context_update_request create_f1ap_ue_context_update_request(du_ue_index_t ue_idx, diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 2c58fe31bb..8652c989a6 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -40,10 +40,14 @@ class du_ran_resource_manager_tester_base } } - ue_ran_resource_configurator& create_ue(du_ue_index_t ue_index) + ue_ran_resource_configurator* create_ue(du_ue_index_t ue_index) { - ues.emplace(ue_index, res_mng->create_ue_resource_configurator(ue_index, to_du_cell_index(0))); - return ues[ue_index]; + auto result = res_mng->create_ue_resource_configurator(ue_index, to_du_cell_index(0)); + if (not result.has_value()) { + return nullptr; + } + ues.emplace(ue_index, std::move(result.value())); + return &ues[ue_index]; } static f1ap_ue_context_update_request srb1_creation_req(du_ue_index_t ue_index) @@ -169,29 +173,31 @@ class du_ran_resource_manager_tester : public du_ran_resource_manager_tester_bas TEST_P(du_ran_resource_manager_tester, when_ue_resource_config_is_created_then_pcell_is_configured) { const du_ue_index_t ue_idx1 = to_du_ue_index(0); - const ue_ran_resource_configurator& ue_res = create_ue(ue_idx1); - - ASSERT_FALSE(ue_res.empty()); - ASSERT_EQ(ue_res->cell_group.cells.size(), 1); - ASSERT_TRUE(ue_res->cell_group.cells.contains(0)); - ASSERT_TRUE(ue_res->srbs.empty()); - ASSERT_TRUE(ue_res->drbs.empty()); - ASSERT_EQ(ue_res->cell_group.cells[0].serv_cell_cfg.cell_index, to_du_cell_index(0)); - ASSERT_EQ(ue_res->cell_group.cells[0].serv_cell_idx, SERVING_CELL_PCELL_IDX); - ASSERT_FALSE(ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list.empty()); - ASSERT_FALSE(ue_res->cell_group.mcg_cfg.scheduling_request_config.empty()); + const ue_ran_resource_configurator* ue_res = create_ue(ue_idx1); + + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); + ASSERT_EQ(ue_res->value().cell_group.cells.size(), 1); + ASSERT_TRUE(ue_res->value().cell_group.cells.contains(0)); + ASSERT_TRUE(ue_res->value().srbs.empty()); + ASSERT_TRUE(ue_res->value().drbs.empty()); + ASSERT_EQ(ue_res->value().cell_group.cells[0].serv_cell_cfg.cell_index, to_du_cell_index(0)); + ASSERT_EQ(ue_res->value().cell_group.cells[0].serv_cell_idx, SERVING_CELL_PCELL_IDX); + ASSERT_FALSE(ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list.empty()); + ASSERT_FALSE(ue_res->value().cell_group.mcg_cfg.scheduling_request_config.empty()); } TEST_P(du_ran_resource_manager_tester, when_srb1_is_added_then_ue_resource_config_is_updated) { const du_ue_index_t ue_idx1 = to_du_ue_index(0); - ue_ran_resource_configurator& ue_res = create_ue(ue_idx1); - auto resp = ue_res.update(to_du_cell_index(0), srb1_creation_req(ue_idx1)); + ue_ran_resource_configurator* ue_res = create_ue(ue_idx1); + ASSERT_NE(ue_res, nullptr); + auto resp = ue_res->update(to_du_cell_index(0), srb1_creation_req(ue_idx1)); ASSERT_FALSE(resp.failed()); - ASSERT_EQ(ue_res->srbs.size(), 1); - ASSERT_TRUE(ue_res->srbs.contains(srb_id_t::srb1)); - ASSERT_EQ(ue_res->srbs[srb_id_t::srb1].rlc_cfg.mode, rlc_mode::am); + ASSERT_EQ(ue_res->value().srbs.size(), 1); + ASSERT_TRUE(ue_res->value().srbs.contains(srb_id_t::srb1)); + ASSERT_EQ(ue_res->value().srbs[srb_id_t::srb1].rlc_cfg.mode, rlc_mode::am); } TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_use_different_sr_offsets) @@ -204,9 +210,11 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u // > Created UEs have unique (PUCCH resource, SR offset) pairs. std::set> sr_offsets; for (unsigned i = 0; i != nof_avail_sr_offsets; ++i) { - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); - const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); + const auto& sr_res_list = + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_periodicity_to_slot(sr_res_list[0].period), sr_period); if (cell_cfg_list[0].tdd_ul_dl_cfg_common.has_value()) { @@ -219,7 +227,7 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); // Check if PUCCH config is correctly updated. - const serving_cell_config serving_cell_cfg = ue_res->cell_group.cells[0].serv_cell_cfg; + const serving_cell_config serving_cell_cfg = ue_res->value().cell_group.cells[0].serv_cell_cfg; std::optional csi_pucch_res{}; const bool has_csi_cfg = serving_cell_cfg.csi_meas_cfg.has_value() and not serving_cell_cfg.csi_meas_cfg.value().csi_report_cfg_list.empty() and @@ -231,16 +239,21 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u .pucch_csi_res_list.front() .pucch_res_id.cell_res_id); } - ASSERT_TRUE(verify_pucch_cfg(ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value(), - csi_pucch_res)); + ASSERT_TRUE(verify_pucch_cfg( + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value(), csi_pucch_res)); next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); } { // > No more SR offsets available. UE Resource Allocation fails. - const ue_ran_resource_configurator& empty_ue_res = create_ue(next_ue_index); - ASSERT_TRUE(empty_ue_res.empty()); + const ue_ran_resource_configurator* ue_res_no_resources = create_ue(next_ue_index); + ASSERT_NE(ue_res_no_resources, nullptr); + ASSERT_TRUE(ue_res_no_resources->resource_alloc_failed()); + ASSERT_FALSE( + ue_res_no_resources->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.has_value()); + ASSERT_TRUE( + ue_res_no_resources->value().cell_group.cells[0].serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list.empty()); ues.erase(next_ue_index); } @@ -254,14 +267,16 @@ TEST_P(du_ran_resource_manager_tester, when_multiple_ues_are_created_then_they_u ues[ue_idx_to_rem]->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset; ues.erase(ue_idx_to_rem); next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); ASSERT_EQ(rem_pucch_resource, - ue_res->cell_group.cells[0] + ue_res->value() + .cell_group.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] .pucch_res_id.cell_res_id); ASSERT_EQ(rem_sr_offset, - ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); } INSTANTIATE_TEST_SUITE_P(du_ran_resource_manager_tester, @@ -446,11 +461,13 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi std::set> sr_offsets; std::set> csi_offsets; for (unsigned i = 0; i != std::get<0>(avail_res); ++i) { - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_periodicity_to_slot(sr_res_list[0].period), sr_period); // Make sure the SR is in a fully-UL slot. @@ -464,8 +481,8 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); // Check if the CSI has been assigned to the UE. - ASSERT_TRUE(has_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg)); - const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg); + ASSERT_TRUE(has_ue_csi_cfg(ue_res->value().cell_group.cells[0].serv_cell_cfg)); + const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->value().cell_group.cells[0].serv_cell_cfg); ASSERT_FALSE(ue_csi_cfg.pucch_csi_res_list.empty()); const unsigned ue_csi_pucch_res_id = ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.cell_res_id; const unsigned ue_csi_pucch_offset = ue_csi_cfg.report_slot_offset; @@ -484,12 +501,12 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi const interval expected_f1 = get_expected_pucch_res_id_interval(static_cast(next_ue_index), srsran::pucch_format::FORMAT_1); const interval actual_f1 = get_pucch_res_id_interval( - ue_res->cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), srsran::pucch_format::FORMAT_1); const interval expected_f2 = get_expected_pucch_res_id_interval(static_cast(next_ue_index), srsran::pucch_format::FORMAT_2); const interval actual_f2 = get_pucch_res_id_interval( - ue_res->cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg.value(), srsran::pucch_format::FORMAT_2); ASSERT_TRUE(expected_f1.start() == actual_f1.start() and expected_f1.stop() == actual_f1.stop()); @@ -500,8 +517,9 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi { // > No more SR offsets available. UE Resource Allocation fails. - const ue_ran_resource_configurator& empty_ue_res = create_ue(next_ue_index); - ASSERT_TRUE(empty_ue_res.empty()); + const ue_ran_resource_configurator* empty_ue_res = create_ue(next_ue_index); + ASSERT_NE(empty_ue_res, nullptr); + ASSERT_TRUE(empty_ue_res->resource_alloc_failed()); ues.erase(next_ue_index); } @@ -521,27 +539,31 @@ TEST_P(du_ran_res_mng_multiple_cfg_tester, test_correct_resource_creation_indexi ues.erase(ue_idx_to_rem); next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); // If the resources and offset were limited by the SR, then check if a new SR can be allocated. const bool nof_ue_limited_by_sr_resources = std::get<1>(avail_res); if (nof_ue_limited_by_sr_resources) { ASSERT_EQ(rem_sr_pucch_resource, - ue_res->cell_group.cells[0] + ue_res->value() + .cell_group.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0] .pucch_res_id.cell_res_id); - ASSERT_EQ(rem_sr_offset, - ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); + ASSERT_EQ( + rem_sr_offset, + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list[0].offset); } // If the resources and offset were limited by the CSI, then check if a new CSI can be allocated. const bool nof_ue_limited_by_csi_resources = std::get<2>(avail_res); if (nof_ue_limited_by_csi_resources) { - ASSERT_EQ( - rem_csi_pucch_resource_id, - get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg).pucch_csi_res_list.front().pucch_res_id.cell_res_id); - ASSERT_EQ(rem_csi_offset, get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg).report_slot_offset); + ASSERT_EQ(rem_csi_pucch_resource_id, + get_ue_csi_cfg(ue_res->value().cell_group.cells[0].serv_cell_cfg) + .pucch_csi_res_list.front() + .pucch_res_id.cell_res_id); + ASSERT_EQ(rem_csi_offset, get_ue_csi_cfg(ue_res->value().cell_group.cells[0].serv_cell_cfg).report_slot_offset); } } @@ -612,23 +634,26 @@ TEST_P(du_ran_res_mng_pucch_cnt_tester, test_du_pucch_cnt) std::set> sr_offsets; std::set> csi_offsets; for (unsigned i = 0; i != 1000; ++i) { - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - if (ue_res.empty()) { + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + if (ue_res == nullptr) { + break; + } + if (ue_res->resource_alloc_failed()) { ues.erase(next_ue_index); break; } - ASSERT_FALSE(ue_res.empty()); // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_offsets.count(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)), 0); sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); unsigned sr_offset = sr_res_list[0].offset; // Check if the CSI has been assigned to the UE. - ASSERT_TRUE(has_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg)); - const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->cell_group.cells[0].serv_cell_cfg); + ASSERT_TRUE(has_ue_csi_cfg(ue_res->value().cell_group.cells[0].serv_cell_cfg)); + const auto& ue_csi_cfg = get_ue_csi_cfg(ue_res->value().cell_group.cells[0].serv_cell_cfg); ASSERT_FALSE(ue_csi_cfg.pucch_csi_res_list.empty()); const unsigned csi_pucch_res_id = ue_csi_cfg.pucch_csi_res_list.front().pucch_res_id.cell_res_id; const unsigned csi_offset = ue_csi_cfg.report_slot_offset; @@ -664,8 +689,9 @@ TEST_P(du_ran_res_mng_pucch_cnt_tester, test_du_pucch_cnt) // Attempt a new allocation and verify it is successful. next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); } INSTANTIATE_TEST_SUITE_P( @@ -706,15 +732,18 @@ TEST_P(du_ran_res_mng_pucch_cnt_sr_only_tester, test_du_pucch_cnt_sr_only) // > Created UEs have unique (PUCCH resource, SR offset) pairs. std::set> sr_offsets; for (unsigned i = 0; i != 1000; ++i) { - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - if (ue_res.empty()) { + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + if (ue_res == nullptr) { + break; + } + if (ue_res->resource_alloc_failed()) { ues.erase(next_ue_index); break; } - ASSERT_FALSE(ue_res.empty()); // Check if the SR has been assigned to the UE. - const auto& sr_res_list = ue_res->cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; + const auto& sr_res_list = + ue_res->value().cell_group.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->sr_res_list; ASSERT_FALSE(sr_res_list.empty()); ASSERT_EQ(sr_offsets.count(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)), 0); sr_offsets.insert(std::make_pair(sr_res_list[0].pucch_res_id.cell_res_id, sr_res_list[0].offset)); @@ -737,8 +766,9 @@ TEST_P(du_ran_res_mng_pucch_cnt_sr_only_tester, test_du_pucch_cnt_sr_only) // Attempt a new allocation and verify it is successful. next_ue_index = to_du_ue_index((unsigned)next_ue_index + 1); - const ue_ran_resource_configurator& ue_res = create_ue(next_ue_index); - ASSERT_FALSE(ue_res.empty()); + const ue_ran_resource_configurator* ue_res = create_ue(next_ue_index); + ASSERT_NE(ue_res, nullptr); + ASSERT_FALSE(ue_res->resource_alloc_failed()); } INSTANTIATE_TEST_SUITE_P( From ac77e40a3614126800636a2af0d50876be77e6ec Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 13 Aug 2024 09:23:16 +0200 Subject: [PATCH 246/407] du_manager: handle UEs for which the DU RAN resource allocation failed --- .../du_ran_resource_manager_impl.cpp | 2 ++ .../du_high/du_high_many_ues_test.cpp | 35 +++++++++++++------ .../test_utils/du_high_env_simulator.cpp | 20 +++++++++++ .../test_utils/du_high_env_simulator.h | 6 +++- .../f1ap/f1ap_test_message_validators.cpp | 10 ++++++ .../f1ap/f1ap_test_message_validators.h | 2 ++ 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index 6297e45bef..f0372ac0f0 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -156,6 +156,8 @@ error_type du_ran_resource_manager_impl::allocate_cell_resources(du ue_res.cell_group.pcg_cfg.pdsch_harq_codebook = pdsch_harq_ack_codebook::dynamic; if (not pucch_res_mng.alloc_resources(ue_res.cell_group)) { + // Deallocate dedicated Search Spaces. + ue_res.cell_group.cells[0].serv_cell_cfg.init_dl_bwp.pdcch_cfg->search_spaces.clear(); return make_unexpected(fmt::format("Unable to allocate dedicated PUCCH resources for cell={}", cell_index)); } } else { diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index 341c54e19f..5c0cc8a42f 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -11,16 +11,26 @@ #include "tests/integrationtests/du_high/test_utils/du_high_env_simulator.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/unittests/f1ap/du/f1ap_du_test_helpers.h" -#include "srsran/support/test_utils.h" #include using namespace srsran; using namespace srs_du; +static du_high_env_sim_params create_custom_params() +{ + du_high_env_sim_params params; + // Reduce number of PUCCH resources, so we do not have to create so many UEs to reach the saturation point. + params.pucch_cfg.emplace(); + params.pucch_cfg->nof_ue_pucch_f0_or_f1_res_harq = 8; + params.pucch_cfg->nof_ue_pucch_f2_res_harq = 8; + params.pucch_cfg->nof_sr_resources = 1; + return params; +} + class du_high_many_ues_tester : public du_high_env_simulator, public testing::Test { protected: - du_high_many_ues_tester() + du_high_many_ues_tester() : du_high_env_simulator(create_custom_params()) { // Reset the last sent F1AP PDU (e.g. F1 setup). cu_notifier.last_f1ap_msgs.clear(); @@ -29,20 +39,25 @@ class du_high_many_ues_tester : public du_high_env_simulator, public testing::Te uint16_t next_rnti = 0x4601; }; -TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_stop_being_created) +TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_being_rejected) { - unsigned added_ues = 0; + unsigned ue_count = 0; + for (; ue_count != MAX_NOF_DU_UES; ++ue_count) { + ASSERT_TRUE(this->add_ue(to_rnti(next_rnti))); - for (unsigned i = 0; i != MAX_NOF_DU_UES; ++i) { - bool added = this->add_ue(to_rnti(next_rnti)); - if (not added) { + byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); + if (container.empty()) { break; } - added_ues++; + next_rnti++; } - ASSERT_GT(added_ues, 75) << "The number of UEs created by DU was too low"; + ASSERT_GT(ue_count, 30) << "The number of UEs accepted by DU was too low"; + ASSERT_LT(ue_count, MAX_NOF_DU_UES) << "The DU is accepting UEs past its number of PUCCH resources"; - ASSERT_FALSE(this->add_ue(to_rnti(next_rnti))) << "No more UEs can be added after the DU runs out of resources"; + next_rnti++; + ASSERT_TRUE(this->add_ue(to_rnti(next_rnti))); + byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); + ASSERT_TRUE(container.empty()) << "No more UEs are accepted after the DU runs out of resources"; } diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 53f7a52fdb..dca23ca25d 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -172,6 +172,9 @@ du_high_env_simulator::du_high_env_simulator(du_high_env_sim_params params) : builder_params.pci = (pci_t)i; cfg.cells.push_back(config_helpers::make_default_du_cell_config(builder_params)); cfg.cells.back().nr_cgi.nci = nr_cell_identity::create(i).value(); + if (params.pucch_cfg.has_value()) { + cfg.cells.back().pucch_cfg = params.pucch_cfg.value(); + } } cfg.qos = config_helpers::make_default_du_qos_config_list(/* warn_on_drop */ true, 0); @@ -287,6 +290,23 @@ bool du_high_env_simulator::run_rrc_setup(rnti_t rnti) return send_dl_rrc_msg_and_await_ul_rrc_msg(u, msg, 0); } +bool du_high_env_simulator::run_rrc_reject(rnti_t rnti) +{ + auto it = ues.find(rnti); + if (it == ues.end()) { + test_logger.error("rnti={}: Failed to run RRC Setup procedure. Cause: UE not found", rnti); + return false; + } + const ue_sim_context& u = it->second; + + // Send DL RRC Message which contains dummy RRC Reject. + f1ap_message msg = generate_dl_rrc_message_transfer( + *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb0, byte_buffer::create({0x1, 0x2, 0x3}).value()); + + // No need to wait for reply. + return true; +} + bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti, reestablishment_stage stop_at) { auto it = ues.find(rnti); diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index fdce31fa06..c0a622ecfe 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -42,7 +42,8 @@ bool is_ue_context_release_complete_valid(const f1ap_message& msg, /// Parameters to set the DU-high environment simulator. struct du_high_env_sim_params { - unsigned nof_cells = 1; + unsigned nof_cells = 1; + std::optional pucch_cfg; }; class du_high_env_simulator @@ -57,6 +58,9 @@ class du_high_env_simulator /// Transfer) until the CU receives the RRC Setup Complete (via UL RRC Message Transfer). bool run_rrc_setup(rnti_t rnti); + /// Run the RRC reject procedure for a given RNTI. + bool run_rrc_reject(rnti_t rnti); + /// Run the RRC Reestablishment procedure for the given RNTI from the moment the CU-CP sends an RRC Reestablishment /// (via DL RRC Message Transfer) until the CU receives the RRC Reestablishment Complete (via UL RRC Message /// Transfer). diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp index f68d11d9f2..e5d8bf56ae 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.cpp @@ -64,6 +64,16 @@ const byte_buffer& srsran::test_helpers::get_rrc_container(const f1ap_message& m return msg.pdu.init_msg().value.dl_rrc_msg_transfer()->rrc_container; } +byte_buffer srsran::test_helpers::get_du_to_cu_container(const f1ap_message& msg) +{ + if (msg.pdu.init_msg().proc_code == ASN1_F1AP_ID_INIT_UL_RRC_MSG_TRANSFER) { + return msg.pdu.init_msg().value.init_ul_rrc_msg_transfer()->du_to_cu_rrc_container_present + ? msg.pdu.init_msg().value.init_ul_rrc_msg_transfer()->du_to_cu_rrc_container.copy() + : byte_buffer{}; + } + return byte_buffer{}; +} + bool srsran::test_helpers::is_valid_dl_rrc_message_transfer_with_msg4(const f1ap_message& msg) { TRUE_OR_RETURN(is_valid_dl_rrc_message_transfer(msg)); diff --git a/tests/test_doubles/f1ap/f1ap_test_message_validators.h b/tests/test_doubles/f1ap/f1ap_test_message_validators.h index 0233fdfb58..996e00cb57 100644 --- a/tests/test_doubles/f1ap/f1ap_test_message_validators.h +++ b/tests/test_doubles/f1ap/f1ap_test_message_validators.h @@ -32,6 +32,8 @@ bool is_valid_dl_rrc_message_transfer(const f1ap_message& msg); const byte_buffer& get_rrc_container(const f1ap_message& msg); +byte_buffer get_du_to_cu_container(const f1ap_message& msg); + bool is_valid_dl_rrc_message_transfer_with_msg4(const f1ap_message& msg); bool is_ul_rrc_msg_transfer_valid(const f1ap_message& msg, srb_id_t srb_id); From f734948d829b5c08909b951ca00769d51563e0c6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 13 Aug 2024 09:59:00 +0200 Subject: [PATCH 247/407] du_high: extend many ue unit test for the case when UEs are rejected due to lack of DU resources --- .../du_high/du_high_many_ues_test.cpp | 10 +++-- .../test_utils/du_high_env_simulator.cpp | 44 +++++++++++-------- .../test_utils/du_high_env_simulator.h | 2 + .../test_doubles/f1ap/f1ap_test_messages.cpp | 24 ++++++++++ tests/test_doubles/f1ap/f1ap_test_messages.h | 9 +++- 5 files changed, 67 insertions(+), 22 deletions(-) diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index 5c0cc8a42f..6b8ea25da6 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -43,20 +43,24 @@ TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_bei { unsigned ue_count = 0; for (; ue_count != MAX_NOF_DU_UES; ++ue_count) { - ASSERT_TRUE(this->add_ue(to_rnti(next_rnti))); + rnti_t rnti = to_rnti(next_rnti++); + ASSERT_TRUE(this->add_ue(rnti)); byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); if (container.empty()) { + // When DU-to-CU container is empty, it means that the DU could not allocate resources for the UE. + + ASSERT_TRUE(this->run_rrc_reject(rnti)) << "RRC Reject not scheduled"; + break; } - next_rnti++; + ASSERT_TRUE(this->run_rrc_setup(rnti)); } ASSERT_GT(ue_count, 30) << "The number of UEs accepted by DU was too low"; ASSERT_LT(ue_count, MAX_NOF_DU_UES) << "The DU is accepting UEs past its number of PUCCH resources"; - next_rnti++; ASSERT_TRUE(this->add_ue(to_rnti(next_rnti))); byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); ASSERT_TRUE(container.empty()) << "No more UEs are accepted after the DU runs out of resources"; diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index dca23ca25d..99e371e13e 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -299,12 +299,12 @@ bool du_high_env_simulator::run_rrc_reject(rnti_t rnti) } const ue_sim_context& u = it->second; - // Send DL RRC Message which contains dummy RRC Reject. - f1ap_message msg = generate_dl_rrc_message_transfer( - *u.du_ue_id, *u.cu_ue_id, srb_id_t::srb0, byte_buffer::create({0x1, 0x2, 0x3}).value()); + // Send UE Context Release Command which contains dummy RRC Reject. + f1ap_message msg = test_helpers::generate_ue_context_release_command(*u.cu_ue_id, *u.du_ue_id, srb_id_t::srb0); + du_hi->get_f1ap_message_handler().handle_message(msg); - // No need to wait for reply. - return true; + // Await Msg4 scheduling. + return await_dl_msg_sched(u, lcid_t::LCID_SRB0); } bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti, reestablishment_stage stop_at) @@ -365,22 +365,14 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti return true; } -bool du_high_env_simulator::send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_context& u, - const f1ap_message& dl_msg, - uint32_t rlc_ul_sn) +bool du_high_env_simulator::await_dl_msg_sched(const ue_sim_context& u, lcid_t lcid) { const auto& phy_cell = phy.cells[u.pcell_index]; - lcid_t dl_lcid = uint_to_lcid(dl_msg.pdu.init_msg().value.dl_rrc_msg_transfer()->srb_id); - lcid_t ul_lcid = dl_lcid == LCID_SRB0 ? LCID_SRB1 : dl_lcid; - - du_hi->get_f1ap_message_handler().handle_message(dl_msg); - - // Wait for Msg4 to be sent to the PHY. bool ret = run_until([&]() { if (phy_cell.last_dl_res.has_value() and phy_cell.last_dl_res.value().dl_res != nullptr) { auto& dl_res = *phy_cell.last_dl_res.value().dl_res; - return find_ue_pdsch_with_lcid(u.rnti, dl_lcid, dl_res.ue_grants) != nullptr; + return find_ue_pdsch_with_lcid(u.rnti, lcid, dl_res.ue_grants) != nullptr; } return false; }); @@ -388,18 +380,34 @@ bool du_high_env_simulator::send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_co test_logger.error("rnti={}: Msg4 not sent to the PHY", u.rnti); return false; } + return true; +} + +bool du_high_env_simulator::send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_context& u, + const f1ap_message& dl_msg, + uint32_t rlc_ul_sn) +{ + lcid_t dl_lcid = uint_to_lcid(dl_msg.pdu.init_msg().value.dl_rrc_msg_transfer()->srb_id); + lcid_t ul_lcid = dl_lcid == LCID_SRB0 ? LCID_SRB1 : dl_lcid; + + du_hi->get_f1ap_message_handler().handle_message(dl_msg); + + // Wait for DL message to be sent to the PHY. + if (not await_dl_msg_sched(u, dl_lcid)) { + return false; + } - // Wait for Msg4 to be ACKed. + // Wait for DL message to be ACKed. unsigned dl_msg_k1 = 4; for (unsigned i = 0; i != dl_msg_k1; ++i) { run_slot(); } - // UE sends Msg5. Wait until F1AP forwards UL RRC Message to CU-CP. + // UE sends UL message. Wait until F1AP forwards UL RRC Message to CU-CP. cu_notifier.last_f1ap_msgs.clear(); du_hi->get_pdu_handler().handle_rx_data_indication( test_helpers::create_pdu_with_sdu(next_slot, u.rnti, ul_lcid, rlc_ul_sn)); - ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); + bool ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); srb_id_t ul_srb_id = int_to_srb_id(ul_lcid); if (not ret or not test_helpers::is_ul_rrc_msg_transfer_valid(cu_notifier.last_f1ap_msgs.back(), ul_srb_id)) { test_logger.error("rnti={}: F1AP UL RRC Message not sent or is invalid", u.rnti); diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index c0a622ecfe..789814deaf 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -105,6 +105,8 @@ class du_high_env_simulator std::array srbs; }; + [[nodiscard]] bool await_dl_msg_sched(const ue_sim_context& u, lcid_t lcid); + [[nodiscard]] bool send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_context& u, const f1ap_message& dl_msg, uint32_t rlc_ul_sn); diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.cpp b/tests/test_doubles/f1ap/f1ap_test_messages.cpp index f575490467..099fea4d7f 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_messages.cpp @@ -320,6 +320,30 @@ f1ap_message srsran::test_helpers::generate_ue_context_release_request(gnb_cu_ue return msg; } +f1ap_message srsran::test_helpers::generate_ue_context_release_command(gnb_cu_ue_f1ap_id_t cu_ue_id, + gnb_du_ue_f1ap_id_t du_ue_id, + srb_id_t srb_id, + byte_buffer rrc_container) +{ + f1ap_message msg; + msg.pdu.set_init_msg(); + msg.pdu.init_msg().load_info_obj(ASN1_F1AP_ID_UE_CONTEXT_RELEASE); + + auto& release_cmd = msg.pdu.init_msg().value.ue_context_release_cmd(); + release_cmd->gnb_cu_ue_f1ap_id = (unsigned)cu_ue_id; + release_cmd->gnb_du_ue_f1ap_id = (unsigned)du_ue_id; + release_cmd->cause.set_radio_network(); + release_cmd->cause.radio_network().value = cause_radio_network_e::unspecified; + if (not rrc_container.empty()) { + release_cmd->srb_id_present = true; + release_cmd->srb_id = srb_id_to_uint(srb_id); + release_cmd->rrc_container_present = true; + release_cmd->rrc_container = std::move(rrc_container); + } + + return msg; +} + f1ap_message srsran::test_helpers::generate_ue_context_release_complete(const f1ap_message& ue_ctxt_release_cmd) { srsran_assert(ue_ctxt_release_cmd.pdu.type().value == f1ap_pdu_c::types_opts::init_msg, "Invalid argument message"); diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.h b/tests/test_doubles/f1ap/f1ap_test_messages.h index 96f8b6efd0..f5ca25a438 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.h +++ b/tests/test_doubles/f1ap/f1ap_test_messages.h @@ -81,7 +81,14 @@ f1ap_message create_ul_rrc_message_transfer(gnb_du_ue_f1ap_id_t du_ue_id, /// \brief Generates dummy F1AP UE CONTEXT RELEASE REQUEST message. f1ap_message generate_ue_context_release_request(gnb_cu_ue_f1ap_id_t cu_ue_id, gnb_du_ue_f1ap_id_t du_ue_id); -/// \brief Generates dummy F1AP UE CONTEXT RELEASE COMPLETE message. +/// \brief Generates dummy F1AP UE CONTEXT RELEASE COMMAND message, sent by the CU to the DU. +f1ap_message +generate_ue_context_release_command(gnb_cu_ue_f1ap_id_t cu_ue_id, + gnb_du_ue_f1ap_id_t du_ue_id, + srb_id_t srb_id = srb_id_t::srb1, + byte_buffer rrc_container = byte_buffer::create({0x1, 0x2, 0x3}).value()); + +/// \brief Generates dummy F1AP UE CONTEXT RELEASE COMPLETE message, sent by the DU to the CU. f1ap_message generate_ue_context_release_complete(const f1ap_message& ue_ctxt_release_cmd); f1ap_message generate_ue_context_release_complete(gnb_cu_ue_f1ap_id_t cu_ue_id, gnb_du_ue_f1ap_id_t du_ue_id); From efd314167c23c029cb88ccb71d8376fb30bbfbe3 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 13 Aug 2024 10:12:51 +0200 Subject: [PATCH 248/407] f1ap-du: wait for timeout instead of delivery notification in case of ue context release with SRB0 message --- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 11 +++++++++-- lib/f1ap/du/ue_context/f1c_du_bearer_impl.h | 2 ++ lib/f1ap/du/ue_context/ue_bearer_manager.cpp | 14 ++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp index fd17493ac5..7017a8482d 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -15,6 +15,7 @@ #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/pdcp/pdcp_sn_util.h" #include "srsran/support/async/async_no_op_task.h" +#include "srsran/support/async/async_timer.h" #include "srsran/support/async/execute_on.h" using namespace srsran; @@ -26,6 +27,7 @@ f1c_srb0_du_bearer::f1c_srb0_du_bearer(f1ap_ue_context& ue_ctxt_, f1ap_message_notifier& f1ap_notifier_, f1c_rx_sdu_notifier& f1c_rx_sdu_notifier_, f1ap_event_manager& ev_manager_, + f1ap_du_configurator& du_configurator_, task_executor& ctrl_exec_, task_executor& ue_exec_) : ue_ctxt(ue_ctxt_), @@ -34,6 +36,7 @@ f1c_srb0_du_bearer::f1c_srb0_du_bearer(f1ap_ue_context& ue_ctxt_, f1ap_notifier(f1ap_notifier_), sdu_notifier(f1c_rx_sdu_notifier_), ev_manager(ev_manager_), + du_configurator(du_configurator_), ctrl_exec(ctrl_exec_), ue_exec(ue_exec_), logger(srslog::fetch_basic_logger("DU-F1")) @@ -99,8 +102,12 @@ async_task f1c_srb0_du_bearer::handle_pdu_and_await_delivery(byte_buffer // Forward task to lower layers. handle_pdu(std::move(sdu)); - // For SRB0, there is no delivery notification. - return launch_no_op_task(true); + // For SRB0, there is no delivery notification mechanism, so we just let the timeout trigger. + return launch_async([this, time_to_wait](coro_context>& ctx) { + CORO_BEGIN(ctx); + CORO_AWAIT(async_wait_for(du_configurator.get_timer_factory().create_timer(), time_to_wait)); + CORO_RETURN(false); + }); } async_task f1c_srb0_du_bearer::handle_pdu_and_await_transmission(byte_buffer pdu, diff --git a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h index 771bc88d4f..cab05642e3 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.h @@ -32,6 +32,7 @@ class f1c_srb0_du_bearer final : public f1c_bearer f1ap_message_notifier& f1ap_notifier_, f1c_rx_sdu_notifier& f1c_rx_sdu_notifier_, f1ap_event_manager& ev_manager_, + f1ap_du_configurator& du_configurator_, task_executor& ctrl_exec_, task_executor& ue_exec_); @@ -54,6 +55,7 @@ class f1c_srb0_du_bearer final : public f1c_bearer f1ap_message_notifier& f1ap_notifier; f1c_rx_sdu_notifier& sdu_notifier; f1ap_event_manager& ev_manager; + f1ap_du_configurator& du_configurator; task_executor& ctrl_exec; task_executor& ue_exec; srslog::basic_logger& logger; diff --git a/lib/f1ap/du/ue_context/ue_bearer_manager.cpp b/lib/f1ap/du/ue_context/ue_bearer_manager.cpp index 61bab3e583..191aa28291 100644 --- a/lib/f1ap/du/ue_context/ue_bearer_manager.cpp +++ b/lib/f1ap/du/ue_context/ue_bearer_manager.cpp @@ -21,10 +21,16 @@ void ue_bearer_manager::add_srb0_f1c_bearer(f1c_rx_sdu_notifier& f1c_rx_sd const byte_buffer& du_cu_rrc_container, f1ap_event_manager& ev_mng) { - f1c_bearers.emplace( - 0, - std::make_unique( - ue_ctx, pcell_cgi, du_cu_rrc_container, f1ap_notifier, f1c_rx_sdu_notif, ev_mng, ctrl_exec, ue_exec)); + f1c_bearers.emplace(0, + std::make_unique(ue_ctx, + pcell_cgi, + du_cu_rrc_container, + f1ap_notifier, + f1c_rx_sdu_notif, + ev_mng, + du_configurator, + ctrl_exec, + ue_exec)); } void ue_bearer_manager::add_f1c_bearer(srb_id_t srb_id, f1c_rx_sdu_notifier& rx_sdu_notif) From 6f3289ef40fc2603dc52c1408fdf73305c16d4f2 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 13 Aug 2024 11:34:14 +0200 Subject: [PATCH 249/407] du_high: extend many ue unit test to verify correct cleanup of UE resources on removal --- .../du_high/du_high_many_ues_test.cpp | 9 ++- .../test_utils/du_high_env_simulator.cpp | 74 +++++++++++++------ .../test_utils/du_high_env_simulator.h | 7 +- 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index 6b8ea25da6..3c920d5a70 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -61,7 +61,14 @@ TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_bei ASSERT_GT(ue_count, 30) << "The number of UEs accepted by DU was too low"; ASSERT_LT(ue_count, MAX_NOF_DU_UES) << "The DU is accepting UEs past its number of PUCCH resources"; - ASSERT_TRUE(this->add_ue(to_rnti(next_rnti))); + // If we try to add more UEs, they also fail. + ASSERT_TRUE(this->add_ue(to_rnti(next_rnti++))); byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); ASSERT_TRUE(container.empty()) << "No more UEs are accepted after the DU runs out of resources"; + + // Once we remove a UE, we have space again for another UE. + ASSERT_TRUE(this->run_ue_context_release(to_rnti(0x4601))); + ASSERT_TRUE(this->add_ue(to_rnti(next_rnti++))); + container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); + ASSERT_FALSE(container.empty()) << "The resources of the released UE were not correctly cleaned up"; } diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 99e371e13e..c5ab17d670 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -203,9 +203,10 @@ du_high_env_simulator::~du_high_env_simulator() workers.stop(); } -bool du_high_env_simulator::run_until(unique_function condition, unsigned max_slot_count) +bool du_high_env_simulator::run_until(unique_function condition, std::optional max_slot_count) { - for (unsigned count = 0; count != max_slot_count; ++count) { + unsigned max_count = max_slot_count.has_value() ? max_slot_count.value() : 1000; + for (unsigned count = 0; count != max_count; ++count) { if (condition()) { return true; } @@ -292,19 +293,7 @@ bool du_high_env_simulator::run_rrc_setup(rnti_t rnti) bool du_high_env_simulator::run_rrc_reject(rnti_t rnti) { - auto it = ues.find(rnti); - if (it == ues.end()) { - test_logger.error("rnti={}: Failed to run RRC Setup procedure. Cause: UE not found", rnti); - return false; - } - const ue_sim_context& u = it->second; - - // Send UE Context Release Command which contains dummy RRC Reject. - f1ap_message msg = test_helpers::generate_ue_context_release_command(*u.cu_ue_id, *u.du_ue_id, srb_id_t::srb0); - du_hi->get_f1ap_message_handler().handle_message(msg); - - // Await Msg4 scheduling. - return await_dl_msg_sched(u, lcid_t::LCID_SRB0); + return run_ue_context_release(rnti, srb_id_t::srb0); } bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti, reestablishment_stage stop_at) @@ -365,17 +354,21 @@ bool du_high_env_simulator::run_rrc_reestablishment(rnti_t rnti, rnti_t old_rnti return true; } -bool du_high_env_simulator::await_dl_msg_sched(const ue_sim_context& u, lcid_t lcid) +bool du_high_env_simulator::await_dl_msg_sched(const ue_sim_context& u, + lcid_t lcid, + std::optional max_slot_count) { const auto& phy_cell = phy.cells[u.pcell_index]; - bool ret = run_until([&]() { - if (phy_cell.last_dl_res.has_value() and phy_cell.last_dl_res.value().dl_res != nullptr) { - auto& dl_res = *phy_cell.last_dl_res.value().dl_res; - return find_ue_pdsch_with_lcid(u.rnti, lcid, dl_res.ue_grants) != nullptr; - } - return false; - }); + bool ret = run_until( + [&]() { + if (phy_cell.last_dl_res.has_value() and phy_cell.last_dl_res.value().dl_res != nullptr) { + auto& dl_res = *phy_cell.last_dl_res.value().dl_res; + return find_ue_pdsch_with_lcid(u.rnti, lcid, dl_res.ue_grants) != nullptr; + } + return false; + }, + max_slot_count); if (not ret) { test_logger.error("rnti={}: Msg4 not sent to the PHY", u.rnti); return false; @@ -484,6 +477,41 @@ bool du_high_env_simulator::run_ue_context_setup(rnti_t rnti) return true; } +bool du_high_env_simulator::run_ue_context_release(rnti_t rnti, srb_id_t srb_id) +{ + auto it = ues.find(rnti); + if (it == ues.end()) { + return false; + } + auto& u = it->second; + + // Send UE Context Release Command which contains dummy RRC Release. + cu_notifier.last_f1ap_msgs.clear(); + f1ap_message msg = test_helpers::generate_ue_context_release_command(*u.cu_ue_id, *u.du_ue_id, srb_id); + du_hi->get_f1ap_message_handler().handle_message(msg); + + // Await for RRC container to be scheduled in the MAC. + lcid_t lcid = srb_id_to_lcid(srb_id); + if (not await_dl_msg_sched(u, lcid, 120)) { + return false; + } + + // Wait for UE Context Release Complete. + bool ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); + if (not ret) { + test_logger.error("Did not receive UE context release complete"); + return false; + } + if (not is_ue_context_release_complete_valid(cu_notifier.last_f1ap_msgs.back(), *u.du_ue_id, *u.cu_ue_id)) { + test_logger.error("UE context release complete message is not valid"); + return false; + } + + ues.erase(rnti); + + return true; +} + void du_high_env_simulator::run_slot() { // Dispatch a slot indication to all cells in the L2 (fork work across cells). diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index 789814deaf..bce5591807 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -71,9 +71,11 @@ class du_high_env_simulator bool run_ue_context_setup(rnti_t rnti); + bool run_ue_context_release(rnti_t rnti, srb_id_t srb_id = srb_id_t::srb1); + void run_slot(); - bool run_until(unique_function condition, unsigned max_slot_count = 1000); + bool run_until(unique_function condition, std::optional max_slot_count = std::nullopt); virtual void handle_slot_results(du_cell_index_t cell_index); @@ -105,7 +107,8 @@ class du_high_env_simulator std::array srbs; }; - [[nodiscard]] bool await_dl_msg_sched(const ue_sim_context& u, lcid_t lcid); + [[nodiscard]] bool + await_dl_msg_sched(const ue_sim_context& u, lcid_t lcid, std::optional max_slot_count = std::nullopt); [[nodiscard]] bool send_dl_rrc_msg_and_await_ul_rrc_msg(const ue_sim_context& u, const f1ap_message& dl_msg, uint32_t rlc_ul_sn); From 63e3615bc770aa29ba96ef749072e5b4132775b1 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 13 Aug 2024 11:47:36 +0200 Subject: [PATCH 250/407] support: fix intrusive_ptr copy ctor --- include/srsran/adt/detail/intrusive_ptr.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/include/srsran/adt/detail/intrusive_ptr.h b/include/srsran/adt/detail/intrusive_ptr.h index 136d2de632..35bbe5274d 100644 --- a/include/srsran/adt/detail/intrusive_ptr.h +++ b/include/srsran/adt/detail/intrusive_ptr.h @@ -36,9 +36,9 @@ template class intrusive_ptr { public: - intrusive_ptr() = default; + intrusive_ptr() noexcept = default; - intrusive_ptr(T* ptr_, bool add_ref = true) : ptr(ptr_) + intrusive_ptr(T* ptr_, bool add_ref = true) noexcept : ptr(ptr_) { if (ptr != nullptr && add_ref) { intrusive_ptr_inc_ref(ptr); @@ -61,18 +61,13 @@ class intrusive_ptr } } - intrusive_ptr& operator=(intrusive_ptr& other) noexcept + intrusive_ptr& operator=(const intrusive_ptr& other) noexcept { - if (ptr != other.ptr) { - T* temp = ptr; - if (other.ptr != nullptr) { - intrusive_ptr_inc_ref(other.ptr); - } - ptr = other.ptr; - if (temp != nullptr) { - instrusive_ptr_dec_ref(temp); - } + if (this == &other) { + return *this; } + intrusive_ptr{other}.swap(*this); + return *this; } intrusive_ptr& operator=(intrusive_ptr&& other) noexcept From c831108735d4de71b1bad21ecc23f625a09d5e48 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 13 Aug 2024 11:58:11 +0200 Subject: [PATCH 251/407] rlc,benchmark: init queue_size_bytes --- .../benchmarks/rlc/rlc_handle_status_report.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/benchmarks/rlc/rlc_handle_status_report.cpp b/tests/benchmarks/rlc/rlc_handle_status_report.cpp index 0ee8993d8f..4ab0a4e04a 100644 --- a/tests/benchmarks/rlc/rlc_handle_status_report.cpp +++ b/tests/benchmarks/rlc/rlc_handle_status_report.cpp @@ -90,14 +90,15 @@ void benchmark_status_pdu_handling(rlc_am_status_pdu status, const bench_params& // Set Tx config rlc_tx_am_config config; - config.sn_field_length = rlc_am_sn_size::size18bits; - config.pdcp_sn_len = pdcp_sn_size::size18bits; - config.t_poll_retx = 45; - config.max_retx_thresh = 4; - config.poll_pdu = 4; - config.poll_byte = 25; - config.queue_size = 4096; - config.max_window = 0; + config.sn_field_length = rlc_am_sn_size::size18bits; + config.pdcp_sn_len = pdcp_sn_size::size18bits; + config.t_poll_retx = 45; + config.max_retx_thresh = 4; + config.poll_pdu = 4; + config.poll_byte = 25; + config.queue_size = 4096; + config.queue_size_bytes = 4096 * 1507; + config.max_window = 0; // Create test frame auto tester = std::make_unique(config.sn_field_length); From 0d35f401dc3d58d58377420732a27d22c645b4ae Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 5 Aug 2024 16:38:08 +0200 Subject: [PATCH 252/407] cu_cp,rrc: refactor measurement types --- apps/units/cu_cp/cu_cp_config_translators.cpp | 10 +- include/srsran/rrc/meas_types.h | 119 +++--- .../rrc_measurement_types_asn1_converters.h | 388 +++++++++--------- .../cell_meas_manager_test_helpers.cpp | 42 +- .../cu_cp/cu_cp_test_environment.cpp | 16 +- tests/unittests/rrc/rrc_ue_test_messages.cpp | 2 +- 6 files changed, 283 insertions(+), 294 deletions(-) diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index 234270a1c4..e34016b74f 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -286,13 +286,13 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co periodical.include_beam_meass = true; periodical.use_allowed_cell_list = false; - report_cfg.periodical = periodical; + report_cfg = periodical; } else { - srs_cu_cp::rrc_event_trigger_cfg event_trigger_cfg; + srs_cu_cp::rrc_event_trigger_cfg event_trigger_cfg = {}; // event id // A3 event config is currently the only supported event. - auto& event_a3 = event_trigger_cfg.event_id.event_a3.emplace(); + srs_cu_cp::rrc_event_a3 event_a3; if (report_cfg_item.a3_report_type.empty() or !report_cfg_item.a3_offset_db.has_value() or !report_cfg_item.a3_hysteresis_db.has_value()) { @@ -314,6 +314,8 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co event_a3.use_allowed_cell_list = false; + event_trigger_cfg.event_id = event_a3; + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; if (report_cfg_item.report_interval_ms.has_value()) { event_trigger_cfg.report_interv = report_cfg_item.report_interval_ms.value(); @@ -332,7 +334,7 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co report_quant_rs_idxes.sinr = true; event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - report_cfg.event_triggered = event_trigger_cfg; + report_cfg = event_trigger_cfg; } // Store config. diff --git a/include/srsran/rrc/meas_types.h b/include/srsran/rrc/meas_types.h index 7af6607d91..759ec33e5f 100644 --- a/include/srsran/rrc/meas_types.h +++ b/include/srsran/rrc/meas_types.h @@ -10,12 +10,11 @@ #pragma once -#include "srsran/adt/optional.h" #include "srsran/adt/slotted_array.h" -#include "srsran/ran/nr_cgi.h" #include "srsran/ran/pci.h" #include "srsran/ran/subcarrier_spacing.h" #include +#include #include namespace srsran { @@ -123,9 +122,10 @@ inline bool operator==(const rrc_ssb_mtc2& lhs, const rrc_ssb_mtc2& rhs) }; struct rrc_ssb_to_measure { - std::optional short_bitmap; - std::optional medium_bitmap; - std::optional long_bitmap; + enum class bitmap_type_t : uint8_t { short_bitmap, medium_bitmap, long_bitmap }; + + bitmap_type_t type; + uint64_t bitmap; }; struct rrc_ssb_to_measure_setup_release { @@ -145,11 +145,10 @@ struct rrc_csi_rs_meas_bw { }; struct rrc_slot_cfg { - std::optional ms4; - std::optional ms5; - std::optional ms10; - std::optional ms20; - std::optional ms40; + enum class period_t : uint8_t { ms4, ms5, ms10, ms20, ms40 }; + + period_t period; + uint16_t offset; }; struct rrc_associated_ssb { @@ -157,10 +156,10 @@ struct rrc_associated_ssb { bool is_quasi_colocated; }; -struct rrc_freq_domain_alloc { - std::optional row1; - std::optional row2; -}; +using rrc_freq_domain_alloc_row1 = uint8_t; +using rrc_freq_domain_alloc_row2 = uint16_t; + +using rrc_freq_domain_alloc = std::variant; struct rrc_csi_rs_res_mob { uint8_t csi_rs_idx; @@ -259,10 +258,7 @@ struct rrc_n4 { uint8_t cyclic_shift_n4; }; -struct rrc_tx_comb { - std::optional n2; - std::optional n4; -}; +using rrc_tx_comb = std::variant; struct rrc_res_map { uint8_t start_position; @@ -277,46 +273,50 @@ struct rrc_freq_hop { }; struct rrc_srs_periodicity_and_offset { - bool is_sl1; - std::optional sl2; - std::optional sl4; - std::optional sl5; - std::optional sl8; - std::optional sl10; - std::optional sl16; - std::optional sl20; - std::optional sl32; - std::optional sl40; - std::optional sl64; - std::optional sl80; - std::optional sl160; - std::optional sl320; - std::optional sl640; - std::optional sl1280; - std::optional sl2560; -}; - -struct rrc_semi_persistent_periodic { + enum class period_t : uint16_t { + ms1, + ms2, + ms4, + ms5, + ms8, + ms10, + ms16, + ms20, + ms32, + ms40, + ms64, + ms80, + ms160, + ms320, + ms640, + ms1280, + ms2560 + }; + + period_t period; + uint16_t offset; +}; + +struct rrc_periodic { rrc_srs_periodicity_and_offset periodicity_and_offset_sp_p; }; -struct rrc_res_type { - bool is_aperiodic; - std::optional semi_persistent; - std::optional periodic; +struct rrc_semi_persistent { + rrc_srs_periodicity_and_offset periodicity_and_offset_sp_p; }; +using rrc_res_type = std::variant; + struct rrc_srs { uint8_t res_id; uint8_t ul_bwp; }; struct rrc_srs_spatial_relation_info { - struct rrc_ref_sig_ { - std::optional ssb_idx; - std::optional csi_rs_idx; - std::optional srs; - }; + enum class ssb_idx_t : uint8_t; + enum class csi_rs_idx_t : uint8_t; + + using rrc_ref_sig_ = std::variant; std::optional serving_cell_id; rrc_ref_sig_ ref_sig; @@ -417,14 +417,7 @@ struct rrc_event_a6 { bool use_allowed_cell_list; }; -struct rrc_event_id { - std::optional event_a1; - std::optional event_a2; - std::optional event_a3; - std::optional event_a4; - std::optional event_a5; - std::optional event_a6; -}; +using rrc_event_id = std::variant; struct rrc_event_trigger_cfg { bool report_add_neigh_meas_present; @@ -461,13 +454,8 @@ struct rrc_cond_event_a5 { uint16_t time_to_trigger; }; -struct rrc_report_cfg_nr { - // choice - std::optional periodical; - std::optional event_triggered; - std::optional report_cgi; - std::optional report_sftd; -}; +using rrc_report_cfg_nr = + std::variant; struct rrc_report_cfg_to_add_mod { report_cfg_id_t report_cfg_id; @@ -481,8 +469,10 @@ struct rrc_meas_id_to_add_mod { }; struct rrc_s_measure_cfg { - std::optional ssb_rsrp; - std::optional csi_rsrp; + enum class measure_type_t : uint8_t { ssb_rsrp, csi_rsrp }; + + measure_type_t type; + uint8_t measure_config; }; struct rrc_filt_cfg { @@ -582,7 +572,6 @@ struct rrc_meas_result_serv_mo { }; struct rrc_meas_result_neigh_cells { - // choice std::vector meas_result_list_nr; }; diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h index 642d975b12..57b54f5335 100644 --- a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h @@ -10,7 +10,6 @@ #pragma once -#include "srsran/adt/optional.h" #include "srsran/asn1/asn1_utils.h" #include "srsran/asn1/rrc_nr/common.h" #include "srsran/asn1/rrc_nr/dl_dcch_msg.h" @@ -218,23 +217,22 @@ inline asn1::rrc_nr::ssb_cfg_mob_s ssb_cfg_mob_to_rrc_asn1(const rrc_ssb_cfg_mob // setup asn1_ssb_cfg_mob.ssb_to_measure.set_setup(); // short bitmap - if (ssb_to_measure.setup.value().short_bitmap.has_value()) { + if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::short_bitmap) { asn1_ssb_cfg_mob.ssb_to_measure.setup().set_short_bitmap(); asn1_ssb_cfg_mob.ssb_to_measure.setup().short_bitmap().from_number( - ssb_to_measure.setup.value().short_bitmap.value()); - } else if (ssb_to_measure.setup.value().medium_bitmap.has_value()) { - // medium bitmap + static_cast(ssb_to_measure.setup.value().bitmap)); + } + // medium bitmap + if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::medium_bitmap) { asn1_ssb_cfg_mob.ssb_to_measure.setup().set_medium_bitmap(); asn1_ssb_cfg_mob.ssb_to_measure.setup().medium_bitmap().from_number( - ssb_to_measure.setup.value().medium_bitmap.value()); - } else if (ssb_to_measure.setup.value().long_bitmap.has_value()) { - // long bitmap + static_cast(ssb_to_measure.setup.value().bitmap)); + } + // long bitmap + if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::long_bitmap) { asn1_ssb_cfg_mob.ssb_to_measure.setup().set_long_bitmap(); - asn1_ssb_cfg_mob.ssb_to_measure.setup().long_bitmap().from_number( - ssb_to_measure.setup.value().long_bitmap.value()); + asn1_ssb_cfg_mob.ssb_to_measure.setup().long_bitmap().from_number(ssb_to_measure.setup.value().bitmap); } - // error - report_fatal_error("Cannot convert SSB to measure to ASN.1 type"); } } @@ -285,24 +283,20 @@ csi_res_cfg_mob_to_rrc_asn1(const rrc_csi_rs_res_cfg_mob_setup_release& csi_rs_r // csi rs idx asn1_csi_rs_res_mob.csi_rs_idx = csi_rs_res_mob.csi_rs_idx; // slot cfg - if (csi_rs_res_mob.slot_cfg.ms4.has_value()) { - asn1_csi_rs_res_mob.slot_cfg.set_ms4(); - asn1_csi_rs_res_mob.slot_cfg.ms4() = csi_rs_res_mob.slot_cfg.ms4.value(); - } else if (csi_rs_res_mob.slot_cfg.ms5.has_value()) { - asn1_csi_rs_res_mob.slot_cfg.set_ms5(); - asn1_csi_rs_res_mob.slot_cfg.ms5() = csi_rs_res_mob.slot_cfg.ms5.value(); - } else if (csi_rs_res_mob.slot_cfg.ms10.has_value()) { - asn1_csi_rs_res_mob.slot_cfg.set_ms10(); - asn1_csi_rs_res_mob.slot_cfg.ms10() = csi_rs_res_mob.slot_cfg.ms10.value(); - } else if (csi_rs_res_mob.slot_cfg.ms20.has_value()) { - asn1_csi_rs_res_mob.slot_cfg.set_ms20(); - asn1_csi_rs_res_mob.slot_cfg.ms20() = csi_rs_res_mob.slot_cfg.ms20.value(); - } else if (csi_rs_res_mob.slot_cfg.ms40.has_value()) { - asn1_csi_rs_res_mob.slot_cfg.set_ms40(); - asn1_csi_rs_res_mob.slot_cfg.ms40() = csi_rs_res_mob.slot_cfg.ms40.value(); - } else { - // error - report_fatal_error("Cannot convert slot cfg to ASN.1 type"); + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms4) { + asn1_csi_rs_res_mob.slot_cfg.set_ms4() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms5) { + asn1_csi_rs_res_mob.slot_cfg.set_ms5() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms10) { + asn1_csi_rs_res_mob.slot_cfg.set_ms10() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms20) { + asn1_csi_rs_res_mob.slot_cfg.set_ms20() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms40) { + asn1_csi_rs_res_mob.slot_cfg.set_ms40() = csi_rs_res_mob.slot_cfg.offset; } // associated ssb if (csi_rs_res_mob.associated_ssb.has_value()) { @@ -312,15 +306,15 @@ csi_res_cfg_mob_to_rrc_asn1(const rrc_csi_rs_res_cfg_mob_setup_release& csi_rs_r csi_rs_res_mob.associated_ssb.value().is_quasi_colocated; } // freq domain alloc - if (csi_rs_res_mob.freq_domain_alloc.row1.has_value()) { + if (std::holds_alternative(csi_rs_res_mob.freq_domain_alloc)) { asn1_csi_rs_res_mob.freq_domain_alloc.set_row1(); - asn1_csi_rs_res_mob.freq_domain_alloc.row1().from_number(csi_rs_res_mob.freq_domain_alloc.row1.value()); - } else if (csi_rs_res_mob.freq_domain_alloc.row2.has_value()) { + asn1_csi_rs_res_mob.freq_domain_alloc.row1().from_number( + std::get(csi_rs_res_mob.freq_domain_alloc)); + } + if (std::holds_alternative(csi_rs_res_mob.freq_domain_alloc)) { asn1_csi_rs_res_mob.freq_domain_alloc.set_row2(); - asn1_csi_rs_res_mob.freq_domain_alloc.row2().from_number(csi_rs_res_mob.freq_domain_alloc.row2.value()); - } else { - // error - report_fatal_error("Cannot convert freq domain alloc to ASN.1 type"); + asn1_csi_rs_res_mob.freq_domain_alloc.row2().from_number( + std::get(csi_rs_res_mob.freq_domain_alloc)); } // first ofdm symbol in time domain asn1_csi_rs_res_mob.first_ofdm_symbol_in_time_domain = csi_rs_res_mob.first_ofdm_symbol_in_time_domain; @@ -574,59 +568,56 @@ template void srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_periodicity_and_offset& asn1_srs_period_and_offset, const rrc_srs_periodicity_and_offset& srs_period_and_offset) { - if (srs_period_and_offset.is_sl1) { + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms1) { asn1_srs_period_and_offset.set_sl1(); - } else if (srs_period_and_offset.sl2.has_value()) { - asn1_srs_period_and_offset.set_sl2(); - asn1_srs_period_and_offset.sl2() = srs_period_and_offset.sl2.value(); - } else if (srs_period_and_offset.sl4.has_value()) { - asn1_srs_period_and_offset.set_sl4(); - asn1_srs_period_and_offset.sl4() = srs_period_and_offset.sl4.value(); - } else if (srs_period_and_offset.sl5.has_value()) { - asn1_srs_period_and_offset.set_sl5(); - asn1_srs_period_and_offset.sl5() = srs_period_and_offset.sl5.value(); - } else if (srs_period_and_offset.sl8.has_value()) { - asn1_srs_period_and_offset.set_sl8(); - asn1_srs_period_and_offset.sl8() = srs_period_and_offset.sl8.value(); - } else if (srs_period_and_offset.sl10.has_value()) { - asn1_srs_period_and_offset.set_sl10(); - asn1_srs_period_and_offset.sl10() = srs_period_and_offset.sl10.value(); - } else if (srs_period_and_offset.sl16.has_value()) { - asn1_srs_period_and_offset.set_sl16(); - asn1_srs_period_and_offset.sl16() = srs_period_and_offset.sl16.value(); - } else if (srs_period_and_offset.sl20.has_value()) { - asn1_srs_period_and_offset.set_sl20(); - asn1_srs_period_and_offset.sl20() = srs_period_and_offset.sl20.value(); - } else if (srs_period_and_offset.sl32.has_value()) { - asn1_srs_period_and_offset.set_sl32(); - asn1_srs_period_and_offset.sl32() = srs_period_and_offset.sl32.value(); - } else if (srs_period_and_offset.sl40.has_value()) { - asn1_srs_period_and_offset.set_sl40(); - asn1_srs_period_and_offset.sl40() = srs_period_and_offset.sl40.value(); - } else if (srs_period_and_offset.sl64.has_value()) { - asn1_srs_period_and_offset.set_sl64(); - asn1_srs_period_and_offset.sl64() = srs_period_and_offset.sl64.value(); - } else if (srs_period_and_offset.sl80.has_value()) { - asn1_srs_period_and_offset.set_sl80(); - asn1_srs_period_and_offset.sl80() = srs_period_and_offset.sl80.value(); - } else if (srs_period_and_offset.sl160.has_value()) { - asn1_srs_period_and_offset.set_sl160(); - asn1_srs_period_and_offset.sl160() = srs_period_and_offset.sl160.value(); - } else if (srs_period_and_offset.sl320.has_value()) { - asn1_srs_period_and_offset.set_sl320(); - asn1_srs_period_and_offset.sl320() = srs_period_and_offset.sl320.value(); - } else if (srs_period_and_offset.sl640.has_value()) { - asn1_srs_period_and_offset.set_sl640(); - asn1_srs_period_and_offset.sl640() = srs_period_and_offset.sl640.value(); - } else if (srs_period_and_offset.sl1280.has_value()) { - asn1_srs_period_and_offset.set_sl1280(); - asn1_srs_period_and_offset.sl1280() = srs_period_and_offset.sl1280.value(); - } else if (srs_period_and_offset.sl2560.has_value()) { - asn1_srs_period_and_offset.set_sl2560(); - asn1_srs_period_and_offset.sl2560() = srs_period_and_offset.sl2560.value(); - } else { - // error - report_fatal_error("Cannot convert SRS periodicity and offset to ASN.1 type"); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms2) { + asn1_srs_period_and_offset.set_sl2() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms4) { + asn1_srs_period_and_offset.set_sl4() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms5) { + asn1_srs_period_and_offset.set_sl5() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms8) { + asn1_srs_period_and_offset.set_sl8() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms10) { + asn1_srs_period_and_offset.set_sl10() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms16) { + asn1_srs_period_and_offset.set_sl16() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms20) { + asn1_srs_period_and_offset.set_sl20() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms32) { + asn1_srs_period_and_offset.set_sl32() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms40) { + asn1_srs_period_and_offset.set_sl40() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms64) { + asn1_srs_period_and_offset.set_sl64() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms80) { + asn1_srs_period_and_offset.set_sl80() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms160) { + asn1_srs_period_and_offset.set_sl160() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms320) { + asn1_srs_period_and_offset.set_sl320() = srs_period_and_offset.offset; + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms640) { + asn1_srs_period_and_offset.set_sl640() = srs_period_and_offset.offset; + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms1280) { + asn1_srs_period_and_offset.set_sl1280() = srs_period_and_offset.offset; + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms2560) { + asn1_srs_period_and_offset.set_sl2560() = srs_period_and_offset.offset; } }; @@ -647,17 +638,16 @@ inline asn1::rrc_nr::srs_res_s srs_res_to_rrc_asn1(const rrc_srs_res& srs_res) } // tx comb - if (srs_res.tx_comb.n2.has_value()) { + if (const auto* n2 = std::get_if(&srs_res.tx_comb); n2 != nullptr) { asn1_srs_res.tx_comb.set_n2(); - asn1_srs_res.tx_comb.n2().comb_offset_n2 = srs_res.tx_comb.n2.value().comb_offset_n2; - asn1_srs_res.tx_comb.n2().cyclic_shift_n2 = srs_res.tx_comb.n2.value().cyclic_shift_n2; - } else if (srs_res.tx_comb.n4.has_value()) { + asn1_srs_res.tx_comb.n2().comb_offset_n2 = n2->comb_offset_n2; + asn1_srs_res.tx_comb.n2().cyclic_shift_n2 = n2->cyclic_shift_n2; + } + + if (const auto* n4 = std::get_if(&srs_res.tx_comb); n4 != nullptr) { asn1_srs_res.tx_comb.set_n4(); - asn1_srs_res.tx_comb.n4().comb_offset_n4 = srs_res.tx_comb.n4.value().comb_offset_n4; - asn1_srs_res.tx_comb.n4().cyclic_shift_n4 = srs_res.tx_comb.n4.value().cyclic_shift_n4; - } else { - // error - report_fatal_error("Cannot convert tx comb to ASN.1 type"); + asn1_srs_res.tx_comb.n4().comb_offset_n4 = n4->comb_offset_n4; + asn1_srs_res.tx_comb.n4().cyclic_shift_n4 = n4->cyclic_shift_n4; } // res map @@ -680,21 +670,19 @@ inline asn1::rrc_nr::srs_res_s srs_res_to_rrc_asn1(const rrc_srs_res& srs_res) asn1::string_to_enum(asn1_srs_res.group_or_seq_hop, srs_res.group_or_seq_hop); // res type - if (srs_res.res_type.is_aperiodic) { + if (std::holds_alternative(srs_res.res_type)) { asn1_srs_res.res_type.set_aperiodic(); - } else if (srs_res.res_type.semi_persistent.has_value()) { + } + if (std::holds_alternative(srs_res.res_type)) { asn1_srs_res.res_type.set_semi_persistent(); srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_res.res_type.semi_persistent().periodicity_and_offset_sp, - srs_res.res_type.semi_persistent.value().periodicity_and_offset_sp_p); - } else if (srs_res.res_type.periodic.has_value()) { + std::get(srs_res.res_type).periodicity_and_offset_sp_p); + } + if (std::holds_alternative(srs_res.res_type)) { asn1_srs_res.res_type.set_periodic(); srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_res.res_type.periodic().periodicity_and_offset_p, - srs_res.res_type.periodic.value().periodicity_and_offset_sp_p); - } else { - // error - report_fatal_error("Cannot convert res type to ASN.1 type"); + std::get(srs_res.res_type).periodicity_and_offset_sp_p); } - // seq id asn1_srs_res.seq_id = srs_res.seq_id; @@ -707,21 +695,22 @@ inline asn1::rrc_nr::srs_res_s srs_res_to_rrc_asn1(const rrc_srs_res& srs_res) srs_res.spatial_relation_info.value().serving_cell_id.value(); } // ref sig - if (srs_res.spatial_relation_info.value().ref_sig.ssb_idx.has_value()) { - asn1_srs_res.spatial_relation_info.ref_sig.set_ssb_idx() = - srs_res.spatial_relation_info.value().ref_sig.ssb_idx.value(); - } else if (srs_res.spatial_relation_info.value().ref_sig.csi_rs_idx.has_value()) { - asn1_srs_res.spatial_relation_info.ref_sig.set_csi_rs_idx() = - srs_res.spatial_relation_info.value().ref_sig.csi_rs_idx.value(); - } else if (srs_res.spatial_relation_info.value().ref_sig.srs.has_value()) { + if (std::holds_alternative( + srs_res.spatial_relation_info.value().ref_sig)) { + asn1_srs_res.spatial_relation_info.ref_sig.set_ssb_idx() = static_cast( + std::get(srs_res.spatial_relation_info.value().ref_sig)); + } + if (std::holds_alternative( + srs_res.spatial_relation_info.value().ref_sig)) { + asn1_srs_res.spatial_relation_info.ref_sig.set_csi_rs_idx() = static_cast( + std::get(srs_res.spatial_relation_info.value().ref_sig)); + } + if (std::holds_alternative(srs_res.spatial_relation_info.value().ref_sig)) { asn1_srs_res.spatial_relation_info.ref_sig.set_srs(); asn1_srs_res.spatial_relation_info.ref_sig.srs().res_id = - srs_res.spatial_relation_info.value().ref_sig.srs.value().res_id; + std::get(srs_res.spatial_relation_info.value().ref_sig).res_id; asn1_srs_res.spatial_relation_info.ref_sig.srs().ul_bwp = - srs_res.spatial_relation_info.value().ref_sig.srs.value().ul_bwp; - } else { - // error - report_fatal_error("Cannot convert ref sig to ASN.1 type"); + std::get(srs_res.spatial_relation_info.value().ref_sig).ul_bwp; } } @@ -838,157 +827,159 @@ void meas_trigger_quant_to_rrc_asn1(asn1_meas_trigger_quant_quant_offset& asn1_m inline asn1::rrc_nr::event_trigger_cfg_s event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigger_cfg& event_triggered_cfg) { - asn1::rrc_nr::event_trigger_cfg_s asn1_event_triggered_cfg; + asn1::rrc_nr::event_trigger_cfg_s asn1_event_trigger_cfg = {}; // report add neigh meas present - asn1_event_triggered_cfg.report_add_neigh_meas_present = event_triggered_cfg.report_add_neigh_meas_present; + asn1_event_trigger_cfg.report_add_neigh_meas_present = event_triggered_cfg.report_add_neigh_meas_present; // event id - if (event_triggered_cfg.event_id.event_a1.has_value()) { + if (const auto* a1 = std::get_if(&event_triggered_cfg.event_id); a1 != nullptr) { // event a1 - auto& asn1_event_a1 = asn1_event_triggered_cfg.event_id.set_event_a1(); + auto& asn1_event_a1 = asn1_event_trigger_cfg.event_id.set_event_a1(); // a1 thres - meas_trigger_quant_to_rrc_asn1(asn1_event_a1.a1_thres, event_triggered_cfg.event_id.event_a1.value().a1_thres); + meas_trigger_quant_to_rrc_asn1(asn1_event_a1.a1_thres, a1->a1_thres); // report on leave - asn1_event_a1.report_on_leave = event_triggered_cfg.event_id.event_a1.value().report_on_leave; + asn1_event_a1.report_on_leave = a1->report_on_leave; // hysteresis - asn1_event_a1.hysteresis = event_triggered_cfg.event_id.event_a1.value().hysteresis; + asn1_event_a1.hysteresis = a1->hysteresis; // time to trigger - asn1::number_to_enum(asn1_event_a1.time_to_trigger, event_triggered_cfg.event_id.event_a1.value().time_to_trigger); - } else if (event_triggered_cfg.event_id.event_a2.has_value()) { + asn1::number_to_enum(asn1_event_a1.time_to_trigger, a1->time_to_trigger); + } + if (const auto* a2 = std::get_if(&event_triggered_cfg.event_id); a2 != nullptr) { // event a2 - auto& asn1_event_a2 = asn1_event_triggered_cfg.event_id.set_event_a2(); + auto& asn1_event_a2 = asn1_event_trigger_cfg.event_id.set_event_a2(); // a2 thres - meas_trigger_quant_to_rrc_asn1(asn1_event_a2.a2_thres, event_triggered_cfg.event_id.event_a2.value().a2_thres); + meas_trigger_quant_to_rrc_asn1(asn1_event_a2.a2_thres, a2->a2_thres); // report on leave - asn1_event_a2.report_on_leave = event_triggered_cfg.event_id.event_a2.value().report_on_leave; + asn1_event_a2.report_on_leave = a2->report_on_leave; // hysteresis - asn1_event_a2.hysteresis = event_triggered_cfg.event_id.event_a2.value().hysteresis; + asn1_event_a2.hysteresis = a2->hysteresis; // time to trigger - asn1::number_to_enum(asn1_event_a2.time_to_trigger, event_triggered_cfg.event_id.event_a2.value().time_to_trigger); - } else if (event_triggered_cfg.event_id.event_a3.has_value()) { + asn1::number_to_enum(asn1_event_a2.time_to_trigger, a2->time_to_trigger); + } + if (const auto* a3 = std::get_if(&event_triggered_cfg.event_id); a3 != nullptr) { // event a3 - auto& asn1_event_a3 = asn1_event_triggered_cfg.event_id.set_event_a3(); + auto& asn1_event_a3 = asn1_event_trigger_cfg.event_id.set_event_a3(); // a3 offset - meas_trigger_quant_to_rrc_asn1(asn1_event_a3.a3_offset, event_triggered_cfg.event_id.event_a3.value().a3_offset); + meas_trigger_quant_to_rrc_asn1(asn1_event_a3.a3_offset, a3->a3_offset); // report on leave - asn1_event_a3.report_on_leave = event_triggered_cfg.event_id.event_a3.value().report_on_leave; + asn1_event_a3.report_on_leave = a3->report_on_leave; // hysteresis - asn1_event_a3.hysteresis = event_triggered_cfg.event_id.event_a3.value().hysteresis; + asn1_event_a3.hysteresis = a3->hysteresis; // time to trigger - asn1::number_to_enum(asn1_event_a3.time_to_trigger, event_triggered_cfg.event_id.event_a3.value().time_to_trigger); + asn1::number_to_enum(asn1_event_a3.time_to_trigger, a3->time_to_trigger); // use allowed cell list - asn1_event_a3.use_allowed_cell_list = event_triggered_cfg.event_id.event_a3.value().use_allowed_cell_list; - } else if (event_triggered_cfg.event_id.event_a4.has_value()) { + asn1_event_a3.use_allowed_cell_list = a3->use_allowed_cell_list; + } + if (const auto* a4 = std::get_if(&event_triggered_cfg.event_id); a4 != nullptr) { // event a4 - auto& asn1_event_a4 = asn1_event_triggered_cfg.event_id.set_event_a4(); + auto& asn1_event_a4 = asn1_event_trigger_cfg.event_id.set_event_a4(); // a4 thres - meas_trigger_quant_to_rrc_asn1(asn1_event_a4.a4_thres, event_triggered_cfg.event_id.event_a4.value().a4_thres); + meas_trigger_quant_to_rrc_asn1(asn1_event_a4.a4_thres, a4->a4_thres); // report on leave - asn1_event_a4.report_on_leave = event_triggered_cfg.event_id.event_a4.value().report_on_leave; + asn1_event_a4.report_on_leave = a4->report_on_leave; // hysteresis - asn1_event_a4.hysteresis = event_triggered_cfg.event_id.event_a4.value().hysteresis; + asn1_event_a4.hysteresis = a4->hysteresis; // time to trigger - asn1::number_to_enum(asn1_event_a4.time_to_trigger, event_triggered_cfg.event_id.event_a4.value().time_to_trigger); + asn1::number_to_enum(asn1_event_a4.time_to_trigger, a4->time_to_trigger); // use allowed cell list - asn1_event_a4.use_allowed_cell_list = event_triggered_cfg.event_id.event_a4.value().use_allowed_cell_list; - } else if (event_triggered_cfg.event_id.event_a5.has_value()) { + asn1_event_a4.use_allowed_cell_list = a4->use_allowed_cell_list; + } + if (const auto* a5 = std::get_if(&event_triggered_cfg.event_id); a5 != nullptr) { // event a5 - auto& asn1_event_a5 = asn1_event_triggered_cfg.event_id.set_event_a5(); + auto& asn1_event_a5 = asn1_event_trigger_cfg.event_id.set_event_a5(); // a5 thres 1 - meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres1, event_triggered_cfg.event_id.event_a5.value().a5_thres_1); + meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres1, a5->a5_thres_1); // a5 thres 2 - meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres2, event_triggered_cfg.event_id.event_a5.value().a5_thres_2); + meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres2, a5->a5_thres_2); // report on leave - asn1_event_a5.report_on_leave = event_triggered_cfg.event_id.event_a5.value().report_on_leave; + asn1_event_a5.report_on_leave = a5->report_on_leave; // hysteresis - asn1_event_a5.hysteresis = event_triggered_cfg.event_id.event_a5.value().hysteresis; + asn1_event_a5.hysteresis = a5->hysteresis; // time to trigger - asn1::number_to_enum(asn1_event_a5.time_to_trigger, event_triggered_cfg.event_id.event_a5.value().time_to_trigger); + asn1::number_to_enum(asn1_event_a5.time_to_trigger, a5->time_to_trigger); // use allowed cell list - asn1_event_a5.use_allowed_cell_list = event_triggered_cfg.event_id.event_a5.value().use_allowed_cell_list; - } else if (event_triggered_cfg.event_id.event_a6.has_value()) { + asn1_event_a5.use_allowed_cell_list = a5->use_allowed_cell_list; + } + if (const auto* a6 = std::get_if(&event_triggered_cfg.event_id); a6 != nullptr) { // event a6 - auto& asn1_event_a6 = asn1_event_triggered_cfg.event_id.set_event_a6(); + auto& asn1_event_a6 = asn1_event_trigger_cfg.event_id.set_event_a6(); // a6 offset - meas_trigger_quant_to_rrc_asn1(asn1_event_a6.a6_offset, event_triggered_cfg.event_id.event_a6.value().a6_offset); + meas_trigger_quant_to_rrc_asn1(asn1_event_a6.a6_offset, a6->a6_offset); // report on leave - asn1_event_a6.report_on_leave = event_triggered_cfg.event_id.event_a6.value().report_on_leave; + asn1_event_a6.report_on_leave = a6->report_on_leave; // hysteresis - asn1_event_a6.hysteresis = event_triggered_cfg.event_id.event_a6.value().hysteresis; + asn1_event_a6.hysteresis = a6->hysteresis; // time to trigger - asn1::number_to_enum(asn1_event_a6.time_to_trigger, event_triggered_cfg.event_id.event_a6.value().time_to_trigger); + asn1::number_to_enum(asn1_event_a6.time_to_trigger, a6->time_to_trigger); // use allowed cell list - asn1_event_a6.use_allowed_cell_list = event_triggered_cfg.event_id.event_a6.value().use_allowed_cell_list; - } else { - // error - report_fatal_error("Cannot convert event id to ASN.1 type"); + asn1_event_a6.use_allowed_cell_list = a6->use_allowed_cell_list; } // rs type - asn1_event_triggered_cfg.rs_type = rrc_nr_rs_type_to_asn1(event_triggered_cfg.rs_type); + asn1_event_trigger_cfg.rs_type = rrc_nr_rs_type_to_asn1(event_triggered_cfg.rs_type); // report interv // report interv. This struct mixes ms and minutes so we need to convert the value before conversion if (event_triggered_cfg.report_interv < 60000) { - asn1::number_to_enum(asn1_event_triggered_cfg.report_interv, event_triggered_cfg.report_interv); + asn1::number_to_enum(asn1_event_trigger_cfg.report_interv, event_triggered_cfg.report_interv); } else { - asn1::number_to_enum(asn1_event_triggered_cfg.report_interv, event_triggered_cfg.report_interv / 60000); + asn1::number_to_enum(asn1_event_trigger_cfg.report_interv, event_triggered_cfg.report_interv / 60000); } // report amount - asn1::number_to_enum(asn1_event_triggered_cfg.report_amount, event_triggered_cfg.report_amount); + asn1::number_to_enum(asn1_event_trigger_cfg.report_amount, event_triggered_cfg.report_amount); // report quant cell - asn1_event_triggered_cfg.report_quant_cell = meas_report_quant_to_rrc_asn1(event_triggered_cfg.report_quant_cell); + asn1_event_trigger_cfg.report_quant_cell = meas_report_quant_to_rrc_asn1(event_triggered_cfg.report_quant_cell); // max report cells - asn1_event_triggered_cfg.max_report_cells = event_triggered_cfg.max_report_cells; + asn1_event_trigger_cfg.max_report_cells = event_triggered_cfg.max_report_cells; // report quant rx idxes if (event_triggered_cfg.report_quant_rs_idxes.has_value()) { - asn1_event_triggered_cfg.report_quant_rs_idxes_present = true; - asn1_event_triggered_cfg.report_quant_rs_idxes = + asn1_event_trigger_cfg.report_quant_rs_idxes_present = true; + asn1_event_trigger_cfg.report_quant_rs_idxes = meas_report_quant_to_rrc_asn1(event_triggered_cfg.report_quant_rs_idxes.value()); } // max nrof rs idxes to report if (event_triggered_cfg.max_nrof_rs_idxes_to_report.has_value()) { - asn1_event_triggered_cfg.max_nrof_rs_idxes_to_report_present = true; - asn1_event_triggered_cfg.max_nrof_rs_idxes_to_report = event_triggered_cfg.max_nrof_rs_idxes_to_report.value(); + asn1_event_trigger_cfg.max_nrof_rs_idxes_to_report_present = true; + asn1_event_trigger_cfg.max_nrof_rs_idxes_to_report = event_triggered_cfg.max_nrof_rs_idxes_to_report.value(); } // include beam meass - asn1_event_triggered_cfg.include_beam_meass = event_triggered_cfg.include_beam_meass; + asn1_event_trigger_cfg.include_beam_meass = event_triggered_cfg.include_beam_meass; - return asn1_event_triggered_cfg; + return asn1_event_trigger_cfg; } inline asn1::rrc_nr::report_cfg_nr_s report_cfg_nr_to_rrc_asn1(const rrc_report_cfg_nr& report_cfg_nr) { asn1::rrc_nr::report_cfg_nr_s asn1_report_cfg_nr; - if (report_cfg_nr.periodical.has_value()) { + if (const auto* periodical = std::get_if(&report_cfg_nr); periodical != nullptr) { // periodical - asn1_report_cfg_nr.report_type.set_periodical() = - periodical_report_cfg_to_rrc_asn1(report_cfg_nr.periodical.value()); - } else if (report_cfg_nr.event_triggered.has_value()) { + asn1_report_cfg_nr.report_type.set_periodical() = periodical_report_cfg_to_rrc_asn1(*periodical); + } + + if (const auto* event_triggered = std::get_if(&report_cfg_nr); event_triggered != nullptr) { // event triggered - asn1_report_cfg_nr.report_type.set_event_triggered() = - event_triggered_report_cfg_to_rrc_asn1(report_cfg_nr.event_triggered.value()); - } else if (report_cfg_nr.report_cgi.has_value()) { + asn1_report_cfg_nr.report_type.set_event_triggered() = event_triggered_report_cfg_to_rrc_asn1(*event_triggered); + } + + if (const auto* report_cgi = std::get_if(&report_cfg_nr); report_cgi != nullptr) { // report cgi asn1_report_cfg_nr.report_type.set_report_cgi(); - asn1_report_cfg_nr.report_type.report_cgi().cell_for_which_to_report_cgi = - report_cfg_nr.report_cgi.value().cell_for_which_to_report_cgi; - } else if (report_cfg_nr.report_sftd.has_value()) { + asn1_report_cfg_nr.report_type.report_cgi().cell_for_which_to_report_cgi = report_cgi->cell_for_which_to_report_cgi; + } + + if (const auto* report_sftd = std::get_if(&report_cfg_nr); report_sftd != nullptr) { // report sftd asn1_report_cfg_nr.report_type.set_report_sftd(); - asn1_report_cfg_nr.report_type.report_sftd().report_sftd_meas = report_cfg_nr.report_sftd.value().report_sftd_meas; - asn1_report_cfg_nr.report_type.report_sftd().report_rsrp = report_cfg_nr.report_sftd.value().report_rsrp; - } else { - // error - report_fatal_error("Cannot convert report cfg nr to ASN.1 type"); + asn1_report_cfg_nr.report_type.report_sftd().report_sftd_meas = report_sftd->report_sftd_meas; + asn1_report_cfg_nr.report_type.report_sftd().report_rsrp = report_sftd->report_rsrp; } return asn1_report_cfg_nr; @@ -1105,13 +1096,12 @@ inline asn1::rrc_nr::meas_cfg_s meas_config_to_rrc_asn1(const rrc_meas_cfg& meas // s measure cfg if (meas_cfg.s_measure_cfg.has_value()) { asn1_meas_cfg.s_measure_cfg_present = true; - if (meas_cfg.s_measure_cfg.value().ssb_rsrp.has_value()) { - asn1_meas_cfg.s_measure_cfg.set_ssb_rsrp() = meas_cfg.s_measure_cfg.value().ssb_rsrp.value(); - } else if (meas_cfg.s_measure_cfg.value().csi_rsrp.has_value()) { - asn1_meas_cfg.s_measure_cfg.set_csi_rsrp() = meas_cfg.s_measure_cfg.value().csi_rsrp.value(); - } else { - // error - report_fatal_error("Cannot convert s measure cfg to ASN.1 type"); + if (meas_cfg.s_measure_cfg.value().type == rrc_s_measure_cfg::measure_type_t::ssb_rsrp) { + asn1_meas_cfg.s_measure_cfg.set_ssb_rsrp() = meas_cfg.s_measure_cfg.value().measure_config; + } + + if (meas_cfg.s_measure_cfg.value().type == rrc_s_measure_cfg::measure_type_t::csi_rsrp) { + asn1_meas_cfg.s_measure_cfg.set_csi_rsrp() = meas_cfg.s_measure_cfg.value().measure_config; } } diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp index b73bec3ae3..9e71cd1d83 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp @@ -96,8 +96,8 @@ void cell_meas_manager_test::create_default_manager() cfg.cells.emplace(cell_cfg.serving_cell_cfg.nci, cell_cfg); // Add periodic event. - rrc_report_cfg_nr periodic_report_cfg; - auto& periodical_cfg = periodic_report_cfg.periodical.emplace(); + rrc_report_cfg_nr periodic_report_cfg; + rrc_periodical_report_cfg periodical_cfg; periodical_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; periodical_cfg.report_interv = 1024; @@ -107,18 +107,20 @@ void cell_meas_manager_test::create_default_manager() periodical_cfg.report_quant_cell.sinr = true; periodical_cfg.max_report_cells = 4; - periodic_report_cfg.periodical = periodical_cfg; + periodic_report_cfg = periodical_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), periodic_report_cfg); // Add A3 event. - rrc_report_cfg_nr a3_report_cfg; - auto& event_trigger_cfg = a3_report_cfg.event_triggered.emplace(); - auto& event_a3 = a3_report_cfg.event_triggered.value().event_id.event_a3.emplace(); + rrc_report_cfg_nr a3_report_cfg; + rrc_event_trigger_cfg event_trigger_cfg = {}; + rrc_event_a3 event_a3; event_a3.a3_offset.rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_trigger_cfg.event_id = event_a3; + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; event_trigger_cfg.report_interv = 1024; event_trigger_cfg.report_amount = -1; @@ -133,7 +135,7 @@ void cell_meas_manager_test::create_default_manager() report_quant_rs_idxes.sinr = true; event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - a3_report_cfg.event_triggered = event_trigger_cfg; + a3_report_cfg = event_trigger_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); manager = std::make_unique(cfg, mobility_manager, ue_mng); @@ -172,8 +174,8 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r cfg.cells.emplace(cell_cfg.serving_cell_cfg.nci, cell_cfg); // Add periodic event. - rrc_report_cfg_nr periodic_report_cfg; - auto& periodical_cfg = periodic_report_cfg.periodical.emplace(); + rrc_report_cfg_nr periodic_report_cfg; + rrc_periodical_report_cfg periodical_cfg; periodical_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; periodical_cfg.report_interv = 1024; @@ -183,18 +185,20 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r periodical_cfg.report_quant_cell.sinr = true; periodical_cfg.max_report_cells = 4; - periodic_report_cfg.periodical = periodical_cfg; + periodic_report_cfg = periodical_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), periodic_report_cfg); // Add A3 event. - rrc_report_cfg_nr a3_report_cfg; - auto& event_trigger_cfg = a3_report_cfg.event_triggered.emplace(); - auto& event_a3 = a3_report_cfg.event_triggered.value().event_id.event_a3.emplace(); + rrc_report_cfg_nr a3_report_cfg; + rrc_event_trigger_cfg event_trigger_cfg = {}; + rrc_event_a3 event_a3; event_a3.a3_offset.rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_trigger_cfg.event_id = event_a3; + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; event_trigger_cfg.report_interv = 1024; event_trigger_cfg.report_amount = -1; @@ -209,7 +213,7 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r report_quant_rs_idxes.sinr = true; event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - a3_report_cfg.event_triggered = event_trigger_cfg; + a3_report_cfg = event_trigger_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); manager = std::make_unique(cfg, mobility_manager, ue_mng); @@ -239,14 +243,16 @@ void cell_meas_manager_test::create_manager_without_ncells_and_periodic_report() cfg.cells.emplace(cell_cfg.serving_cell_cfg.nci, cell_cfg); // Add A3 event. - rrc_report_cfg_nr a3_report_cfg; - auto& event_trigger_cfg = a3_report_cfg.event_triggered.emplace(); - auto& event_a3 = a3_report_cfg.event_triggered.value().event_id.event_a3.emplace(); + rrc_report_cfg_nr a3_report_cfg; + rrc_event_trigger_cfg event_trigger_cfg = {}; + rrc_event_a3 event_a3; event_a3.a3_offset.rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_trigger_cfg.event_id = event_a3; + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; event_trigger_cfg.report_interv = 1024; event_trigger_cfg.report_amount = -1; @@ -261,7 +267,7 @@ void cell_meas_manager_test::create_manager_without_ncells_and_periodic_report() report_quant_rs_idxes.sinr = true; event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - a3_report_cfg.event_triggered = event_trigger_cfg; + a3_report_cfg = event_trigger_cfg = {}; cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), a3_report_cfg); manager = std::make_unique(cfg, mobility_manager, ue_mng); diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index ff512804f0..953de7a38c 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -142,8 +142,8 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : // Add periodic event { - rrc_report_cfg_nr periodic_report_cfg; - auto& periodical_cfg = periodic_report_cfg.periodical.emplace(); + rrc_report_cfg_nr periodic_report_cfg; + rrc_periodical_report_cfg periodical_cfg; periodical_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; periodical_cfg.report_interv = 1024; @@ -153,20 +153,22 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : periodical_cfg.report_quant_cell.sinr = true; periodical_cfg.max_report_cells = 4; - periodic_report_cfg.periodical = periodical_cfg; + periodic_report_cfg = periodical_cfg; meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), periodic_report_cfg); } // Add event A3 { - rrc_report_cfg_nr a3_report_cfg; - auto& event_trigger_cfg = a3_report_cfg.event_triggered.emplace(); - auto& event_a3 = a3_report_cfg.event_triggered.value().event_id.event_a3.emplace(); + rrc_report_cfg_nr a3_report_cfg; + rrc_event_trigger_cfg event_trigger_cfg = {}; + rrc_event_a3 event_a3; event_a3.a3_offset.rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_trigger_cfg.event_id = event_a3; + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; event_trigger_cfg.report_interv = 1024; event_trigger_cfg.report_amount = -1; @@ -181,7 +183,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : report_quant_rs_idxes.sinr = true; event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - a3_report_cfg.event_triggered = event_trigger_cfg; + a3_report_cfg = event_trigger_cfg; meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); } } diff --git a/tests/unittests/rrc/rrc_ue_test_messages.cpp b/tests/unittests/rrc/rrc_ue_test_messages.cpp index 6e0b8439fd..8ff9380582 100644 --- a/tests/unittests/rrc/rrc_ue_test_messages.cpp +++ b/tests/unittests/rrc/rrc_ue_test_messages.cpp @@ -97,7 +97,7 @@ rrc_meas_cfg srsran::srs_cu_cp::generate_dummy_meas_config() periodical.include_beam_meass = true; periodical.use_allowed_cell_list = false; - report_cfg_nr.periodical = periodical; + report_cfg_nr = periodical; report_cfg_to_add_mod.report_cfg = report_cfg_nr; meas_cfg.report_cfg_to_add_mod_list.push_back(report_cfg_to_add_mod); From 8e78ab1b7d214ac4f8906fbf566997ef3adff973 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 5 Aug 2024 16:55:52 +0200 Subject: [PATCH 253/407] cu_cp,rrc: add support for measurement events a1, a2, a4, a5, and a6 --- apps/units/cu_cp/cu_cp_config_translators.cpp | 216 ++++++++++++------ apps/units/cu_cp/cu_cp_unit_config.h | 20 +- .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 40 +++- .../cu_cp/cu_cp_unit_config_validator.cpp | 36 ++- .../cu_cp/cu_cp_unit_config_yaml_writer.cpp | 38 +-- configs/mobility.yml | 9 +- include/srsran/rrc/meas_types.h | 58 ++--- .../rrc_measurement_types_asn1_converters.h | 129 +++++------ .../cell_meas_manager_test_helpers.cpp | 27 ++- .../cu_cp/cu_cp_test_environment.cpp | 18 +- 10 files changed, 339 insertions(+), 252 deletions(-) diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index e34016b74f..5a0bcf6100 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -175,6 +175,148 @@ static srs_cu_cp::rrc_ssb_mtc generate_rrc_ssb_mtc(unsigned period, unsigned off return ssb_mtc; } +static srs_cu_cp::rrc_periodical_report_cfg +generate_cu_cp_periodical_report_config(const cu_cp_unit_report_config& report_cfg_item) +{ + srs_cu_cp::rrc_periodical_report_cfg periodical; + + periodical.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; + periodical.report_interv = report_cfg_item.report_interval_ms; + periodical.report_amount = -1; + periodical.report_quant_cell.rsrp = true; + periodical.report_quant_cell.rsrq = true; + periodical.report_quant_cell.sinr = true; + periodical.max_report_cells = 4; + + srs_cu_cp::rrc_meas_report_quant report_quant_rs_idxes; + report_quant_rs_idxes.rsrp = true; + report_quant_rs_idxes.rsrq = true; + report_quant_rs_idxes.sinr = true; + periodical.report_quant_rs_idxes = report_quant_rs_idxes; + + periodical.max_nrof_rs_idxes_to_report = 4; + periodical.include_beam_meass = true; + periodical.use_allowed_cell_list = false; + + return periodical; +} + +static srs_cu_cp::rrc_event_trigger_cfg +generate_cu_cp_event_trigger_report_config(const cu_cp_unit_report_config& report_cfg_item) +{ + srs_cu_cp::rrc_event_trigger_cfg event_trigger_cfg; + + { + srs_cu_cp::rrc_event_id event_id; + + if (report_cfg_item.event_triggered_report_type.value() == "a1") { + event_id.id = srs_cu_cp::rrc_event_id::event_id_t::a1; + } + if (report_cfg_item.event_triggered_report_type.value() == "a2") { + event_id.id = srs_cu_cp::rrc_event_id::event_id_t::a2; + } + if (report_cfg_item.event_triggered_report_type.value() == "a3") { + event_id.id = srs_cu_cp::rrc_event_id::event_id_t::a3; + } + if (report_cfg_item.event_triggered_report_type.value() == "a4") { + event_id.id = srs_cu_cp::rrc_event_id::event_id_t::a4; + } + if (report_cfg_item.event_triggered_report_type.value() == "a5") { + event_id.id = srs_cu_cp::rrc_event_id::event_id_t::a5; + } + if (report_cfg_item.event_triggered_report_type.value() == "a6") { + event_id.id = srs_cu_cp::rrc_event_id::event_id_t::a6; + } + + event_id.meas_trigger_quant_thres_or_offset.emplace(); + + // Event id + if (report_cfg_item.event_triggered_report_type.value() == "a1" or + report_cfg_item.event_triggered_report_type.value() == "a2" or + report_cfg_item.event_triggered_report_type.value() == "a4" or + report_cfg_item.event_triggered_report_type.value() == "a5") { + if (report_cfg_item.event_triggered_report_type.value() == "a5") { + event_id.meas_trigger_quant_thres_2.emplace(); + } + // Meas trigger quantity threshold + if (report_cfg_item.meas_trigger_quantity.value() == "rsrp") { + event_id.meas_trigger_quant_thres_or_offset.value().rsrp = + report_cfg_item.meas_trigger_quantity_threshold_db.value(); + if (report_cfg_item.event_triggered_report_type.value() == "a5") { + event_id.meas_trigger_quant_thres_2.value().rsrp = + report_cfg_item.meas_trigger_quantity_threshold_2_db.value(); + } + } else if (report_cfg_item.meas_trigger_quantity.value() == "rsrq") { + event_id.meas_trigger_quant_thres_or_offset.value().rsrq = + report_cfg_item.meas_trigger_quantity_threshold_db.value(); + if (report_cfg_item.event_triggered_report_type.value() == "a5") { + event_id.meas_trigger_quant_thres_2.value().rsrq = + report_cfg_item.meas_trigger_quantity_threshold_2_db.value(); + } + } else if (report_cfg_item.meas_trigger_quantity.value() == "sinr") { + event_id.meas_trigger_quant_thres_or_offset.value().sinr = + report_cfg_item.meas_trigger_quantity_threshold_db.value(); + if (report_cfg_item.event_triggered_report_type.value() == "a5") { + event_id.meas_trigger_quant_thres_2.value().sinr = + report_cfg_item.meas_trigger_quantity_threshold_2_db.value(); + } + } + } + + if (report_cfg_item.event_triggered_report_type.value() == "a3" or + report_cfg_item.event_triggered_report_type.value() == "a6") { + // Meas trigger quantity offset + if (report_cfg_item.meas_trigger_quantity.value() == "rsrp") { + event_id.meas_trigger_quant_thres_or_offset.value().rsrp = + report_cfg_item.meas_trigger_quantity_offset_db.value(); + } else if (report_cfg_item.meas_trigger_quantity.value() == "rsrq") { + event_id.meas_trigger_quant_thres_or_offset.value().rsrq = + report_cfg_item.meas_trigger_quantity_offset_db.value(); + } else if (report_cfg_item.meas_trigger_quantity.value() == "sinr") { + event_id.meas_trigger_quant_thres_or_offset.value().sinr = + report_cfg_item.meas_trigger_quantity_offset_db.value(); + } + } + + if (report_cfg_item.event_triggered_report_type.value() == "a3" or + report_cfg_item.event_triggered_report_type.value() == "a4" or + report_cfg_item.event_triggered_report_type.value() == "a5" or + report_cfg_item.event_triggered_report_type.value() == "a6") { + // Report on leave + event_id.use_allowed_cell_list = false; + } + + // Common parameters + + // Report on leave + event_id.report_on_leave = false; + + // Hysteresis + event_id.hysteresis = report_cfg_item.hysteresis_db.value(); + + // Time to trigger + event_id.time_to_trigger = report_cfg_item.time_to_trigger_ms.value(); + + event_trigger_cfg.event_id = event_id; + } + + event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; + event_trigger_cfg.report_interv = report_cfg_item.report_interval_ms; + event_trigger_cfg.report_amount = -1; + event_trigger_cfg.report_quant_cell.rsrp = true; + event_trigger_cfg.report_quant_cell.rsrq = true; + event_trigger_cfg.report_quant_cell.sinr = true; + event_trigger_cfg.max_report_cells = 4; + + srs_cu_cp::rrc_meas_report_quant report_quant_rs_idxes; + report_quant_rs_idxes.rsrp = true; + report_quant_rs_idxes.rsrq = true; + report_quant_rs_idxes.sinr = true; + event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; + + return event_trigger_cfg; +} + srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_config& cu_cfg) { srs_cu_cp::cu_cp_configuration out_cfg = config_helpers::make_default_cu_cp_config(); @@ -262,79 +404,9 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co srs_cu_cp::rrc_report_cfg_nr report_cfg; if (report_cfg_item.report_type == "periodical") { - srs_cu_cp::rrc_periodical_report_cfg periodical; - - periodical.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; - if (report_cfg_item.report_interval_ms.has_value()) { - periodical.report_interv = report_cfg_item.report_interval_ms.value(); - } else { - periodical.report_interv = 1024; - } - periodical.report_amount = -1; - periodical.report_quant_cell.rsrp = true; - periodical.report_quant_cell.rsrq = true; - periodical.report_quant_cell.sinr = true; - periodical.max_report_cells = 4; - - srs_cu_cp::rrc_meas_report_quant report_quant_rs_idxes; - report_quant_rs_idxes.rsrp = true; - report_quant_rs_idxes.rsrq = true; - report_quant_rs_idxes.sinr = true; - periodical.report_quant_rs_idxes = report_quant_rs_idxes; - - periodical.max_nrof_rs_idxes_to_report = 4; - periodical.include_beam_meass = true; - periodical.use_allowed_cell_list = false; - - report_cfg = periodical; + report_cfg = generate_cu_cp_periodical_report_config(report_cfg_item); } else { - srs_cu_cp::rrc_event_trigger_cfg event_trigger_cfg = {}; - - // event id - // A3 event config is currently the only supported event. - srs_cu_cp::rrc_event_a3 event_a3; - - if (report_cfg_item.a3_report_type.empty() or !report_cfg_item.a3_offset_db.has_value() or - !report_cfg_item.a3_hysteresis_db.has_value()) { - report_error("Invalid measurement report configuration.\n"); - } - - if (report_cfg_item.a3_report_type == "rsrp") { - event_a3.a3_offset.rsrp = report_cfg_item.a3_offset_db.value(); - } else if (report_cfg_item.a3_report_type == "rsrq") { - event_a3.a3_offset.rsrq = report_cfg_item.a3_offset_db.value(); - } else if (report_cfg_item.a3_report_type == "sinr") { - event_a3.a3_offset.sinr = report_cfg_item.a3_offset_db.value(); - } - - event_a3.report_on_leave = false; - - event_a3.hysteresis = report_cfg_item.a3_hysteresis_db.value(); - event_a3.time_to_trigger = report_cfg_item.a3_time_to_trigger_ms.value(); - - event_a3.use_allowed_cell_list = false; - - event_trigger_cfg.event_id = event_a3; - - event_trigger_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; - if (report_cfg_item.report_interval_ms.has_value()) { - event_trigger_cfg.report_interv = report_cfg_item.report_interval_ms.value(); - } else { - event_trigger_cfg.report_interv = 1024; - } - event_trigger_cfg.report_amount = -1; - event_trigger_cfg.report_quant_cell.rsrp = true; - event_trigger_cfg.report_quant_cell.rsrq = true; - event_trigger_cfg.report_quant_cell.sinr = true; - event_trigger_cfg.max_report_cells = 4; - - srs_cu_cp::rrc_meas_report_quant report_quant_rs_idxes; - report_quant_rs_idxes.rsrp = true; - report_quant_rs_idxes.rsrq = true; - report_quant_rs_idxes.sinr = true; - event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - - report_cfg = event_trigger_cfg; + report_cfg = generate_cu_cp_event_trigger_report_config(report_cfg_item); } // Store config. diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index 333cbca084..582fbf3f97 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -23,14 +23,18 @@ namespace srsran { /// Report configuration, for now only supporting the A3 event. struct cu_cp_unit_report_config { - unsigned report_cfg_id; - std::string report_type; - std::optional report_interval_ms; - std::string a3_report_type; - /// [-30..30] Note the actual value is field value * 0.5 dB. E.g. putting a value of -6 here results in -3dB offset. - std::optional a3_offset_db; - std::optional a3_hysteresis_db; - std::optional a3_time_to_trigger_ms; + unsigned report_cfg_id; + std::string report_type; + unsigned report_interval_ms; + + std::optional event_triggered_report_type; + std::optional meas_trigger_quantity; + std::optional meas_trigger_quantity_threshold_db; + std::optional meas_trigger_quantity_threshold_2_db; + std::optional meas_trigger_quantity_offset_db; ///< [-30..30] Note the actual value is field value * 0.5 dB. E.g. + ///< putting a value of -6 here results in -3dB offset. + std::optional hysteresis_db; + std::optional time_to_trigger_ms; }; struct cu_cp_unit_neighbor_cell_config_item { diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp index db9a793860..2ee464c08f 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -52,25 +52,45 @@ static void configure_cli11_report_args(CLI::App& app, cu_cp_unit_report_config& ->check(CLI::Range(1, 64)); add_option(app, "--report_type", report_params.report_type, "Type of the report configuration") ->check(CLI::IsMember({"periodical", "event_triggered"})); + add_option(app, + "--event_triggered_report_type", + report_params.event_triggered_report_type, + "Type of the event triggered report") + ->check(CLI::IsMember({"a1", "a2", "a3", "a4", "a5", "a6"})); add_option(app, "--report_interval_ms", report_params.report_interval_ms, "Report interval in ms") ->check( CLI::IsMember({120, 240, 480, 640, 1024, 2048, 5120, 10240, 20480, 40960, 60000, 360000, 720000, 1800000})); - add_option(app, "--a3_report_type", report_params.a3_report_type, "A3 report type") + add_option(app, + "--meas_trigger_quantity", + report_params.meas_trigger_quantity, + "Measurement trigger quantity (RSRP/RSRQ/SINR)") ->check(CLI::IsMember({"rsrp", "rsrq", "sinr"})); add_option(app, - "--a3_offset_db", - report_params.a3_offset_db, - "A3 offset in dB used for measurement report trigger. Note the actual value is field value * 0.5 dB") + "--meas_trigger_quantitiy_threshold_db", + report_params.meas_trigger_quantity_threshold_db, + "Measurement trigger quantity threshold in dB used for measurement report trigger of event A1/A2/A4/A5") + ->check(CLI::Range(0, 127)); + add_option(app, + "--meas_trigger_quantitiy_threshold_2_db", + report_params.meas_trigger_quantity_threshold_2_db, + "Measurement trigger quantity threshold 2 in dB used for measurement report trigger of event A5") + ->check(CLI::Range(0, 127)); + add_option(app, + "--meas_trigger_quantity_offset_db", + report_params.meas_trigger_quantity_offset_db, + "Measurement trigger quantity offset in dB used for measurement report trigger of event A3/A6. Note the " + "actual value is field value * 0.5 dB") + ->check(CLI::Range(-30, 30)); add_option(app, - "--a3_hysteresis_db", - report_params.a3_hysteresis_db, - "A3 hysteresis in dB used for measurement report trigger. Note the actual value is field value * 0.5 dB") + "--hysteresis_db", + report_params.hysteresis_db, + "Hysteresis in dB used for measurement report trigger. Note the actual value is field value * 0.5 dB") ->check(CLI::Range(0, 30)); add_option(app, - "--a3_time_to_trigger_ms", - report_params.a3_time_to_trigger_ms, - "Time in ms during which A3 condition must be met before measurement report trigger") + "--time_to_trigger_ms", + report_params.time_to_trigger_ms, + "Time in ms during which a condition must be met before measurement report trigger") ->check(CLI::IsMember({0, 40, 64, 80, 100, 128, 160, 256, 320, 480, 512, 640, 1024, 1280, 2560, 5120})); } diff --git a/apps/units/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/cu_cp/cu_cp_unit_config_validator.cpp index 0b27421ef0..25528055ca 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_validator.cpp @@ -21,14 +21,48 @@ using namespace srsran; static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobility_config& config) { - // check that report config ids are unique std::map report_cfg_ids_to_report_type; for (const auto& report_cfg : config.report_configs) { + // check that report config ids are unique if (report_cfg_ids_to_report_type.find(report_cfg.report_cfg_id) != report_cfg_ids_to_report_type.end()) { fmt::print("Report config ids must be unique\n"); return false; } report_cfg_ids_to_report_type.emplace(report_cfg.report_cfg_id, report_cfg.report_type); + + // check that report configs are valid + if (report_cfg.report_type == "event_triggered") { + if (!report_cfg.event_triggered_report_type.has_value()) { + fmt::print("Invalid CU-CP configuration. If report type is set to \"event_triggered\" then " + "\"event_triggered_report_type\" must be set\n"); + return false; + } + + if (report_cfg.event_triggered_report_type.value() == "a1" or + report_cfg.event_triggered_report_type.value() == "a2" or + report_cfg.event_triggered_report_type.value() == "a4") { + if (!report_cfg.meas_trigger_quantity.has_value() or + !report_cfg.meas_trigger_quantity_threshold_db.has_value() or !report_cfg.hysteresis_db.has_value() or + !report_cfg.time_to_trigger_ms.has_value()) { + fmt::print("Invalid event A1/A2/A4 measurement report configuration.\n"); + } + } + if (report_cfg.event_triggered_report_type.value() == "a3" or + report_cfg.event_triggered_report_type.value() == "a6") { + if (!report_cfg.meas_trigger_quantity.has_value() or !report_cfg.meas_trigger_quantity_offset_db.has_value() or + !report_cfg.hysteresis_db.has_value() or !report_cfg.time_to_trigger_ms.has_value()) { + fmt::print("Invalid event A3/A6 measurement report configuration.\n"); + } + } + if (report_cfg.event_triggered_report_type.value() == "a5") { + if (!report_cfg.meas_trigger_quantity.has_value() or + !report_cfg.meas_trigger_quantity_threshold_db.has_value() or + !report_cfg.meas_trigger_quantity_threshold_2_db.has_value() or !report_cfg.hysteresis_db.has_value() or + !report_cfg.time_to_trigger_ms.has_value()) { + fmt::print("Invalid event A5 measurement report configuration.\n"); + } + } + } } std::map> cell_to_report_cfg_id; diff --git a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp index 921b5bb3cd..e6dd6f4eb3 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp @@ -86,22 +86,32 @@ static YAML::Node build_cu_cp_mobility_report_section(const cu_cp_unit_report_co { YAML::Node node; - node["report_cfg_id"] = config.report_cfg_id; - node["report_type"] = config.report_type; - node["a3_report_type"] = config.a3_report_type; - if (config.report_interval_ms) { - node["report_interval_ms"] = config.report_interval_ms.value(); - } - if (config.a3_offset_db) { - node["a3_offset_db"] = config.a3_offset_db.value(); - } - if (config.a3_hysteresis_db) { - node["a3_hysteresis_db"] = config.a3_hysteresis_db.value(); - } - if (config.a3_time_to_trigger_ms) { - node["a3_time_to_trigger_ms"] = config.a3_time_to_trigger_ms.value(); + node["report_cfg_id"] = config.report_cfg_id; + node["report_type"] = config.report_type; + if (config.event_triggered_report_type) { + node["event_triggered_report_type"] = config.event_triggered_report_type.value(); + if (config.meas_trigger_quantity_threshold_db) { + node["meas_trigger_quantity_threshold_db"] = config.meas_trigger_quantity_threshold_db.value(); + } + if (config.meas_trigger_quantity_threshold_2_db) { + node["meas_trigger_quantity_threshold_2_db"] = config.meas_trigger_quantity_threshold_2_db.value(); + } + if (config.meas_trigger_quantity_offset_db) { + node["meas_trigger_quantity_offset_db"] = config.meas_trigger_quantity_offset_db.value(); + } + if (config.hysteresis_db) { + node["hysteresis_db"] = config.hysteresis_db.value(); + } + if (config.meas_trigger_quantity) { + node["meas_trigger_quantity"] = config.meas_trigger_quantity.value(); + } + if (config.time_to_trigger_ms) { + node["time_to_trigger_ms"] = config.time_to_trigger_ms.value(); + } } + node["report_interval_ms"] = config.report_interval_ms; + return node; } diff --git a/configs/mobility.yml b/configs/mobility.yml index 830d9d15cb..a089e045c4 100644 --- a/configs/mobility.yml +++ b/configs/mobility.yml @@ -30,8 +30,9 @@ cu_cp: report_interval_ms: 1024 - report_cfg_id: 2 report_type: event_triggered - a3_report_type: rsrp - a3_offset_db: 6 - a3_hysteresis_db: 0 - a3_time_to_trigger_ms: 100 + event_triggered_report_type: a3 + meas_trigger_quantity: rsrp + meas_trigger_quantity_offset_db: 6 + hysteresis_db: 0 + time_to_trigger_ms: 100 report_interval_ms: 1024 diff --git a/include/srsran/rrc/meas_types.h b/include/srsran/rrc/meas_types.h index 759ec33e5f..2452bf00b5 100644 --- a/include/srsran/rrc/meas_types.h +++ b/include/srsran/rrc/meas_types.h @@ -368,57 +368,27 @@ struct rrc_meas_trigger_quant { std::optional sinr; }; -struct rrc_event_a1 { - rrc_meas_trigger_quant a1_thres; - bool report_on_leave; - uint8_t hysteresis; - uint16_t time_to_trigger; -}; - -struct rrc_event_a2 { - rrc_meas_trigger_quant a2_thres; - bool report_on_leave; - uint8_t hysteresis; - uint16_t time_to_trigger; -}; - using rrc_meas_trigger_quant_offset = rrc_meas_trigger_quant; -struct rrc_event_a3 { - rrc_meas_trigger_quant_offset a3_offset; - bool report_on_leave; - uint8_t hysteresis; - uint16_t time_to_trigger; - bool use_allowed_cell_list; -}; +struct rrc_event_id { + enum class event_id_t : uint8_t { a1, a2, a3, a4, a5, a6 }; + // common parameters + event_id_t id; -struct rrc_event_a4 { - rrc_meas_trigger_quant a4_thres; - bool report_on_leave; - uint8_t hysteresis; - uint16_t time_to_trigger; - bool use_allowed_cell_list; -}; + bool report_on_leave; + uint8_t hysteresis; + uint16_t time_to_trigger; -struct rrc_event_a5 { - rrc_meas_trigger_quant a5_thres_1; - rrc_meas_trigger_quant a5_thres_2; - bool report_on_leave; - uint8_t hysteresis; - uint16_t time_to_trigger; - bool use_allowed_cell_list; -}; + // event A1/A2/A4/A5 + std::optional + meas_trigger_quant_thres_or_offset; ///< Threshold for the measurement trigger quantity of event A1/A2/A4/A5 or + ///< offset for event A3/A6 + std::optional + meas_trigger_quant_thres_2; ///< Threshold 2 for the measurement trigger quantity of event A5 -struct rrc_event_a6 { - rrc_meas_trigger_quant_offset a6_offset; - bool report_on_leave; - uint8_t hysteresis; - uint16_t time_to_trigger; - bool use_allowed_cell_list; + std::optional use_allowed_cell_list; ///< For event A3/A4/A5/A6 }; -using rrc_event_id = std::variant; - struct rrc_event_trigger_cfg { bool report_add_neigh_meas_present; rrc_event_id event_id; diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h index 57b54f5335..9c26edff17 100644 --- a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h @@ -832,88 +832,65 @@ event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigger_cfg& event_trigge // report add neigh meas present asn1_event_trigger_cfg.report_add_neigh_meas_present = event_triggered_cfg.report_add_neigh_meas_present; - // event id - if (const auto* a1 = std::get_if(&event_triggered_cfg.event_id); a1 != nullptr) { - // event a1 + const auto& event_id = event_triggered_cfg.event_id; + + // event a1 + if (event_id.id == rrc_event_id::event_id_t::a1) { auto& asn1_event_a1 = asn1_event_trigger_cfg.event_id.set_event_a1(); - // a1 thres - meas_trigger_quant_to_rrc_asn1(asn1_event_a1.a1_thres, a1->a1_thres); - // report on leave - asn1_event_a1.report_on_leave = a1->report_on_leave; - // hysteresis - asn1_event_a1.hysteresis = a1->hysteresis; - // time to trigger - asn1::number_to_enum(asn1_event_a1.time_to_trigger, a1->time_to_trigger); - } - if (const auto* a2 = std::get_if(&event_triggered_cfg.event_id); a2 != nullptr) { - // event a2 + meas_trigger_quant_to_rrc_asn1(asn1_event_a1.a1_thres, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a1.report_on_leave = event_id.report_on_leave; + asn1_event_a1.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a1.time_to_trigger, event_id.time_to_trigger); + } + + // event a2 + if (event_id.id == rrc_event_id::event_id_t::a2) { auto& asn1_event_a2 = asn1_event_trigger_cfg.event_id.set_event_a2(); - // a2 thres - meas_trigger_quant_to_rrc_asn1(asn1_event_a2.a2_thres, a2->a2_thres); - // report on leave - asn1_event_a2.report_on_leave = a2->report_on_leave; - // hysteresis - asn1_event_a2.hysteresis = a2->hysteresis; - // time to trigger - asn1::number_to_enum(asn1_event_a2.time_to_trigger, a2->time_to_trigger); - } - if (const auto* a3 = std::get_if(&event_triggered_cfg.event_id); a3 != nullptr) { - // event a3 + meas_trigger_quant_to_rrc_asn1(asn1_event_a2.a2_thres, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a2.report_on_leave = event_id.report_on_leave; + asn1_event_a2.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a2.time_to_trigger, event_id.time_to_trigger); + } + + // event a3 + if (event_id.id == rrc_event_id::event_id_t::a3) { auto& asn1_event_a3 = asn1_event_trigger_cfg.event_id.set_event_a3(); - // a3 offset - meas_trigger_quant_to_rrc_asn1(asn1_event_a3.a3_offset, a3->a3_offset); - // report on leave - asn1_event_a3.report_on_leave = a3->report_on_leave; - // hysteresis - asn1_event_a3.hysteresis = a3->hysteresis; - // time to trigger - asn1::number_to_enum(asn1_event_a3.time_to_trigger, a3->time_to_trigger); - // use allowed cell list - asn1_event_a3.use_allowed_cell_list = a3->use_allowed_cell_list; - } - if (const auto* a4 = std::get_if(&event_triggered_cfg.event_id); a4 != nullptr) { - // event a4 + meas_trigger_quant_to_rrc_asn1(asn1_event_a3.a3_offset, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a3.report_on_leave = event_id.report_on_leave; + asn1_event_a3.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a3.time_to_trigger, event_id.time_to_trigger); + asn1_event_a3.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // event a4 + if (event_id.id == rrc_event_id::event_id_t::a4) { auto& asn1_event_a4 = asn1_event_trigger_cfg.event_id.set_event_a4(); - // a4 thres - meas_trigger_quant_to_rrc_asn1(asn1_event_a4.a4_thres, a4->a4_thres); - // report on leave - asn1_event_a4.report_on_leave = a4->report_on_leave; - // hysteresis - asn1_event_a4.hysteresis = a4->hysteresis; - // time to trigger - asn1::number_to_enum(asn1_event_a4.time_to_trigger, a4->time_to_trigger); - // use allowed cell list - asn1_event_a4.use_allowed_cell_list = a4->use_allowed_cell_list; - } - if (const auto* a5 = std::get_if(&event_triggered_cfg.event_id); a5 != nullptr) { - // event a5 + meas_trigger_quant_to_rrc_asn1(asn1_event_a4.a4_thres, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a4.report_on_leave = event_id.report_on_leave; + asn1_event_a4.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a4.time_to_trigger, event_id.time_to_trigger); + asn1_event_a4.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // event a5 + if (event_id.id == rrc_event_id::event_id_t::a5) { auto& asn1_event_a5 = asn1_event_trigger_cfg.event_id.set_event_a5(); - // a5 thres 1 - meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres1, a5->a5_thres_1); - // a5 thres 2 - meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres2, a5->a5_thres_2); - // report on leave - asn1_event_a5.report_on_leave = a5->report_on_leave; - // hysteresis - asn1_event_a5.hysteresis = a5->hysteresis; - // time to trigger - asn1::number_to_enum(asn1_event_a5.time_to_trigger, a5->time_to_trigger); - // use allowed cell list - asn1_event_a5.use_allowed_cell_list = a5->use_allowed_cell_list; - } - if (const auto* a6 = std::get_if(&event_triggered_cfg.event_id); a6 != nullptr) { - // event a6 + meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres1, event_id.meas_trigger_quant_thres_or_offset.value()); + meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres2, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a5.report_on_leave = event_id.report_on_leave; + asn1_event_a5.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a5.time_to_trigger, event_id.time_to_trigger); + asn1_event_a5.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // event a6 + if (event_id.id == rrc_event_id::event_id_t::a6) { auto& asn1_event_a6 = asn1_event_trigger_cfg.event_id.set_event_a6(); - // a6 offset - meas_trigger_quant_to_rrc_asn1(asn1_event_a6.a6_offset, a6->a6_offset); - // report on leave - asn1_event_a6.report_on_leave = a6->report_on_leave; - // hysteresis - asn1_event_a6.hysteresis = a6->hysteresis; - // time to trigger - asn1::number_to_enum(asn1_event_a6.time_to_trigger, a6->time_to_trigger); - // use allowed cell list - asn1_event_a6.use_allowed_cell_list = a6->use_allowed_cell_list; + meas_trigger_quant_to_rrc_asn1(asn1_event_a6.a6_offset, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a6.report_on_leave = event_id.report_on_leave; + asn1_event_a6.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a6.time_to_trigger, event_id.time_to_trigger); + asn1_event_a6.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); } // rs type diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp index 9e71cd1d83..d05b3ac5f8 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp @@ -114,10 +114,11 @@ void cell_meas_manager_test::create_default_manager() rrc_report_cfg_nr a3_report_cfg; rrc_event_trigger_cfg event_trigger_cfg = {}; - rrc_event_a3 event_a3; - event_a3.a3_offset.rsrp.emplace() = 6; - event_a3.hysteresis = 0; - event_a3.time_to_trigger = 100; + rrc_event_id event_a3; + event_a3.meas_trigger_quant_thres_or_offset.emplace(); + event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; + event_a3.hysteresis = 0; + event_a3.time_to_trigger = 100; event_trigger_cfg.event_id = event_a3; @@ -192,10 +193,11 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r rrc_report_cfg_nr a3_report_cfg; rrc_event_trigger_cfg event_trigger_cfg = {}; - rrc_event_a3 event_a3; - event_a3.a3_offset.rsrp.emplace() = 6; - event_a3.hysteresis = 0; - event_a3.time_to_trigger = 100; + rrc_event_id event_a3; + event_a3.meas_trigger_quant_thres_or_offset.emplace(); + event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; + event_a3.hysteresis = 0; + event_a3.time_to_trigger = 100; event_trigger_cfg.event_id = event_a3; @@ -245,11 +247,12 @@ void cell_meas_manager_test::create_manager_without_ncells_and_periodic_report() // Add A3 event. rrc_report_cfg_nr a3_report_cfg; rrc_event_trigger_cfg event_trigger_cfg = {}; - rrc_event_a3 event_a3; - event_a3.a3_offset.rsrp.emplace() = 6; - event_a3.hysteresis = 0; - event_a3.time_to_trigger = 100; + rrc_event_id event_a3; + event_a3.meas_trigger_quant_thres_or_offset.emplace(); + event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; + event_a3.hysteresis = 0; + event_a3.time_to_trigger = 100; event_trigger_cfg.event_id = event_a3; diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index 953de7a38c..e291bf0de6 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -142,9 +142,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : // Add periodic event { - rrc_report_cfg_nr periodic_report_cfg; rrc_periodical_report_cfg periodical_cfg; - periodical_cfg.rs_type = srs_cu_cp::rrc_nr_rs_type::ssb; periodical_cfg.report_interv = 1024; periodical_cfg.report_amount = -1; @@ -153,19 +151,18 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : periodical_cfg.report_quant_cell.sinr = true; periodical_cfg.max_report_cells = 4; - periodic_report_cfg = periodical_cfg; - meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), periodic_report_cfg); + meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), rrc_report_cfg_nr{periodical_cfg}); } // Add event A3 { - rrc_report_cfg_nr a3_report_cfg; rrc_event_trigger_cfg event_trigger_cfg = {}; - rrc_event_a3 event_a3; - event_a3.a3_offset.rsrp.emplace() = 6; - event_a3.hysteresis = 0; - event_a3.time_to_trigger = 100; + rrc_event_id event_a3; + event_a3.meas_trigger_quant_thres_or_offset.emplace(); + event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; + event_a3.hysteresis = 0; + event_a3.time_to_trigger = 100; event_trigger_cfg.event_id = event_a3; @@ -183,8 +180,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : report_quant_rs_idxes.sinr = true; event_trigger_cfg.report_quant_rs_idxes = report_quant_rs_idxes; - a3_report_cfg = event_trigger_cfg; - meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); + meas_mng_cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), rrc_report_cfg_nr{event_trigger_cfg}); } } cu_cp_cfg.mobility.meas_manager_config = meas_mng_cfg; From e986618b8018ee2b69cb439a00bc587706a31866 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 9 Aug 2024 11:29:51 +0200 Subject: [PATCH 254/407] cu_cp,rrc: improve documentation --- include/srsran/rrc/meas_types.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/srsran/rrc/meas_types.h b/include/srsran/rrc/meas_types.h index 2452bf00b5..e8a36f377f 100644 --- a/include/srsran/rrc/meas_types.h +++ b/include/srsran/rrc/meas_types.h @@ -122,7 +122,9 @@ inline bool operator==(const rrc_ssb_mtc2& lhs, const rrc_ssb_mtc2& rhs) }; struct rrc_ssb_to_measure { - enum class bitmap_type_t : uint8_t { short_bitmap, medium_bitmap, long_bitmap }; + enum class bitmap_type_t : uint8_t { /* uint8_t */ short_bitmap, + /* uint8_t */ medium_bitmap, + /* uint64_t */ long_bitmap }; bitmap_type_t type; uint64_t bitmap; From 124d8187fa755ad11912c3731b0ab72535c52523 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 9 Aug 2024 11:30:13 +0200 Subject: [PATCH 255/407] cu_cp,rrc: add cpp files for helper functions --- lib/rrc/CMakeLists.txt | 3 + lib/rrc/ue/procedures/rrc_setup_procedure.cpp | 1 + lib/rrc/ue/procedures/rrc_setup_procedure.h | 2 +- lib/rrc/ue/rrc_asn1_converters.cpp | 230 +++ lib/rrc/ue/rrc_asn1_converters.h | 243 +-- lib/rrc/ue/rrc_asn1_helpers.cpp | 281 ++++ lib/rrc/ue/rrc_asn1_helpers.h | 274 +--- .../rrc_measurement_types_asn1_converters.cpp | 1256 ++++++++++++++++ .../rrc_measurement_types_asn1_converters.h | 1321 ++--------------- 9 files changed, 1928 insertions(+), 1683 deletions(-) create mode 100644 lib/rrc/ue/rrc_asn1_converters.cpp create mode 100644 lib/rrc/ue/rrc_asn1_helpers.cpp create mode 100644 lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp diff --git a/lib/rrc/CMakeLists.txt b/lib/rrc/CMakeLists.txt index 9c9b1ef646..7a96caae1c 100644 --- a/lib/rrc/CMakeLists.txt +++ b/lib/rrc/CMakeLists.txt @@ -10,6 +10,9 @@ set(SOURCES rrc_du_factory.cpp rrc_du_impl.cpp ue/meas_types_validators.cpp + ue/rrc_asn1_helpers.cpp + ue/rrc_asn1_converters.cpp + ue/rrc_measurement_types_asn1_converters.cpp ue/rrc_ue_impl.cpp ue/rrc_ue_context.cpp ue/rrc_ue_message_handlers.cpp diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp index 38671fc81b..01f09e676d 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp @@ -10,6 +10,7 @@ #include "rrc_setup_procedure.h" #include "../rrc_asn1_helpers.h" +#include "ue/rrc_asn1_converters.h" #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" #include diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.h b/lib/rrc/ue/procedures/rrc_setup_procedure.h index 822561c183..e8570fdbc9 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.h +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.h @@ -62,7 +62,7 @@ class rrc_setup_procedure rrc_ue_setup_proc_notifier& rrc_ue_notifier_, rrc_ue_srb_handler& srb_notifier_, rrc_ue_nas_notifier& nas_notifier_, - rrc_ue_event_manager& ev_mng_, + rrc_ue_event_manager& event_mng_, rrc_ue_logger& logger_); void operator()(coro_context>& ctx); diff --git a/lib/rrc/ue/rrc_asn1_converters.cpp b/lib/rrc/ue/rrc_asn1_converters.cpp new file mode 100644 index 0000000000..ec2cdcafb3 --- /dev/null +++ b/lib/rrc/ue/rrc_asn1_converters.cpp @@ -0,0 +1,230 @@ +/* + * + * 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 "rrc_asn1_converters.h" + +using namespace srsran; +using namespace srs_cu_cp; + +asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_e_ +srsran::srs_cu_cp::discard_timer_to_asn1(pdcp_discard_timer discard_timer) +{ + asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_e_ asn1_discard_timer; + + asn1::number_to_enum(asn1_discard_timer, pdcp_discard_timer_to_int(discard_timer)); + + return asn1_discard_timer; +} + +asn1::rrc_nr::pdcp_cfg_s::t_reordering_e_ srsran::srs_cu_cp::t_reordering_to_asn1(pdcp_t_reordering t_reordering) +{ + asn1::rrc_nr::pdcp_cfg_s::t_reordering_e_ asn1_t_reordering; + + asn1::number_to_enum(asn1_t_reordering, pdcp_t_reordering_to_int(t_reordering)); + + return asn1_t_reordering; +} + +asn1::rrc_nr::pdcp_cfg_s srsran::srs_cu_cp::pdcp_config_to_rrc_nr_asn1(pdcp_config pdcp_cfg) +{ + asn1::rrc_nr::pdcp_cfg_s rrc_pdcp_cfg; + + // t reordering -- Need S + if (pdcp_cfg.rx.t_reordering != pdcp_t_reordering::infinity) { + rrc_pdcp_cfg.t_reordering_present = true; + rrc_pdcp_cfg.t_reordering = t_reordering_to_asn1(pdcp_cfg.rx.t_reordering); + } + + // ciphering disabled present -- Cond ConnectedTo5GC + if (!pdcp_cfg.ciphering_required) { + rrc_pdcp_cfg.ciphering_disabled_present = true; + // this is an extension field. + rrc_pdcp_cfg.ext = true; + } + + // more than one rlc + rrc_pdcp_cfg.more_than_one_rlc_present = false; // not supported. + + // no more configurable parameters for SRBs + if (pdcp_cfg.rb_type == pdcp_rb_type::srb) { + return rrc_pdcp_cfg; + } + + // drb -- Cond DRB + rrc_pdcp_cfg.drb_present = true; + + // hdr compress + rrc_pdcp_cfg.drb.hdr_compress.set_not_used(); // not supported. + + // discard timer -- Cond Setup + if (pdcp_cfg.tx.discard_timer.has_value()) { + rrc_pdcp_cfg.drb.discard_timer_present = true; + rrc_pdcp_cfg.drb.discard_timer = discard_timer_to_asn1(pdcp_cfg.tx.discard_timer.value()); + } + + // pdcp sn size ul -- Cond Setup2 + rrc_pdcp_cfg.drb.pdcp_sn_size_ul_present = true; + asn1::number_to_enum(rrc_pdcp_cfg.drb.pdcp_sn_size_ul, pdcp_sn_size_to_uint(pdcp_cfg.rx.sn_size)); + + // pdcp sn size dl -- Cond Setup2 + rrc_pdcp_cfg.drb.pdcp_sn_size_dl_present = true; + asn1::number_to_enum(rrc_pdcp_cfg.drb.pdcp_sn_size_dl, pdcp_sn_size_to_uint(pdcp_cfg.tx.sn_size)); + + // integrity protection present + rrc_pdcp_cfg.drb.integrity_protection_present = pdcp_cfg.integrity_protection_required; + + // status report required present + rrc_pdcp_cfg.drb.status_report_required_present = pdcp_cfg.tx.status_report_required; + + // out of order delivery present + rrc_pdcp_cfg.drb.out_of_order_delivery_present = pdcp_cfg.rx.out_of_order_delivery; + + return rrc_pdcp_cfg; +} + +asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options +srsran::srs_cu_cp::sdap_hdr_ul_cfg_to_rrc_asn1(sdap_hdr_ul_cfg hdr_cfg) +{ + asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options asn1_hdr_ul_opts; + + if (hdr_cfg == sdap_hdr_ul_cfg::absent) { + asn1_hdr_ul_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options::absent; + } else { + asn1_hdr_ul_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options::present; + } + + return asn1_hdr_ul_opts; +} + +asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options +srsran::srs_cu_cp::sdap_hdr_dl_cfg_to_rrc_asn1(sdap_hdr_dl_cfg hdr_cfg) +{ + asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options asn1_hdr_dl_opts; + + if (hdr_cfg == sdap_hdr_dl_cfg::absent) { + asn1_hdr_dl_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options::absent; + } else { + asn1_hdr_dl_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options::present; + } + + return asn1_hdr_dl_opts; +} + +asn1::rrc_nr::sdap_cfg_s srsran::srs_cu_cp::sdap_config_to_rrc_asn1(const sdap_config_t& sdap_cfg) +{ + asn1::rrc_nr::sdap_cfg_s asn1_sdap_cfg; + + // pdu session + asn1_sdap_cfg.pdu_session = pdu_session_id_to_uint(sdap_cfg.pdu_session); + + // sdap hdr dl + asn1_sdap_cfg.sdap_hdr_dl = sdap_hdr_dl_cfg_to_rrc_asn1(sdap_cfg.sdap_hdr_dl); + + // sdap hdr ul + asn1_sdap_cfg.sdap_hdr_ul = sdap_hdr_ul_cfg_to_rrc_asn1(sdap_cfg.sdap_hdr_ul); + + // default drb + asn1_sdap_cfg.default_drb = sdap_cfg.default_drb; + + // mapped qos flow to add + for (const auto& mapped_qps_flow_to_add : sdap_cfg.mapped_qos_flows_to_add) { + asn1_sdap_cfg.mapped_qos_flows_to_add.push_back(qos_flow_id_to_uint(mapped_qps_flow_to_add)); + } + + // mapped qos flow to release + for (const auto& mapped_qps_flow_to_release : sdap_cfg.mapped_qos_flows_to_release) { + asn1_sdap_cfg.mapped_qos_flows_to_release.push_back(qos_flow_id_to_uint(mapped_qps_flow_to_release)); + } + + return asn1_sdap_cfg; +} + +asn1::rrc_nr::ciphering_algorithm_e +srsran::srs_cu_cp::ciphering_algorithm_to_rrc_asn1(const security::ciphering_algorithm& ciphering_algo) +{ + asn1::rrc_nr::ciphering_algorithm_e asn1_ciphering_algo; + + switch (ciphering_algo) { + case srsran::security::ciphering_algorithm::nea0: + asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea0; + break; + case srsran::security::ciphering_algorithm::nea1: + asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea1; + break; + case srsran::security::ciphering_algorithm::nea2: + asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea2; + break; + case srsran::security::ciphering_algorithm::nea3: + asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea3; + break; + default: + // error + report_fatal_error("Cannot convert ciphering algorithm {} to ASN.1 type", ciphering_algo); + } + + return asn1_ciphering_algo; +} + +asn1::rrc_nr::integrity_prot_algorithm_e +srsran::srs_cu_cp::integrity_prot_algorithm_to_rrc_asn1(const security::integrity_algorithm& integrity_prot_algo) +{ + asn1::rrc_nr::integrity_prot_algorithm_e asn1_integrity_prot_algo; + + switch (integrity_prot_algo) { + case srsran::security::integrity_algorithm::nia0: + asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia0; + break; + case srsran::security::integrity_algorithm::nia1: + asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia1; + break; + case srsran::security::integrity_algorithm::nia2: + asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia2; + break; + case srsran::security::integrity_algorithm::nia3: + asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia3; + break; + default: + // error + report_fatal_error("Cannot convert integrity_prot algorithm {} to ASN.1 type", integrity_prot_algo); + } + + return asn1_integrity_prot_algo; +} + +cu_cp_five_g_s_tmsi srsran::srs_cu_cp::asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<48>& asn1_five_g_s_tmsi) +{ + bounded_bitset<48> five_g_s_tmsi(48); + five_g_s_tmsi.from_uint64(asn1_five_g_s_tmsi.to_number()); + + return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; +} + +cu_cp_five_g_s_tmsi srsran::srs_cu_cp::asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<39>& asn1_five_g_s_tmsi_part1, + const asn1::fixed_bitstring<9>& asn1_five_g_s_tmsi_part2) +{ + bounded_bitset<48> five_g_s_tmsi(48); + five_g_s_tmsi.from_uint64((asn1_five_g_s_tmsi_part2.to_number() << 39) + asn1_five_g_s_tmsi_part1.to_number()); + + return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; +} + +cu_cp_amf_identifier_t srsran::srs_cu_cp::asn1_to_amf_identifier(const asn1::fixed_bitstring<24>& asn1_amf_id) +{ + cu_cp_amf_identifier_t amf_id; + + uint32_t amf_identifier = 0; + amf_identifier = (uint32_t)asn1_amf_id.to_number(); + + amf_id.amf_region_id = amf_identifier >> 16U; + amf_id.amf_set_id = (amf_identifier - (amf_id.amf_region_id << 16U)) >> 6U; + amf_id.amf_pointer = (amf_identifier << 26U) >> 26U; + + return amf_id; +} diff --git a/lib/rrc/ue/rrc_asn1_converters.h b/lib/rrc/ue/rrc_asn1_converters.h index c2063bb12f..7aa31edee4 100644 --- a/lib/rrc/ue/rrc_asn1_converters.h +++ b/lib/rrc/ue/rrc_asn1_converters.h @@ -10,7 +10,6 @@ #pragma once -#include "srsran/adt/bounded_bitset.h" #include "srsran/asn1/asn1_utils.h" #include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" #include "srsran/cu_cp/cu_cp_types.h" @@ -26,26 +25,12 @@ namespace srs_cu_cp { /// \brief Converts type \c pdcp_discard_timer to an RRC NR ASN.1 type. /// \param[in] discard_timer discard timer object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_e_ discard_timer_to_asn1(pdcp_discard_timer discard_timer) -{ - asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_e_ asn1_discard_timer; - - asn1::number_to_enum(asn1_discard_timer, pdcp_discard_timer_to_int(discard_timer)); - - return asn1_discard_timer; -} +asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_e_ discard_timer_to_asn1(pdcp_discard_timer discard_timer); /// \brief Converts type \c pdcp_t_reordering to an RRC NR ASN.1 type. /// \param[in] t_reordering t-reordering object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline asn1::rrc_nr::pdcp_cfg_s::t_reordering_e_ t_reordering_to_asn1(pdcp_t_reordering t_reordering) -{ - asn1::rrc_nr::pdcp_cfg_s::t_reordering_e_ asn1_t_reordering; - - asn1::number_to_enum(asn1_t_reordering, pdcp_t_reordering_to_int(t_reordering)); - - return asn1_t_reordering; -} +asn1::rrc_nr::pdcp_cfg_s::t_reordering_e_ t_reordering_to_asn1(pdcp_t_reordering t_reordering); /// \brief Converts type \c pdcp_config_t to an RRC NR ASN.1 type. /// \param[in] pdcp_cfg pdcp config object. @@ -70,203 +55,51 @@ inline asn1::rrc_nr::pdcp_cfg_s::t_reordering_e_ t_reordering_to_asn1(pdcp_t_reo /// | field is absent. /// Setup2 | This field is mandatory present in case for radio bearer setup for RLC-AM and RLC-UM. /// | Otherwise, this field is absent, Need M. -inline asn1::rrc_nr::pdcp_cfg_s pdcp_config_to_rrc_nr_asn1(pdcp_config pdcp_cfg) -{ - asn1::rrc_nr::pdcp_cfg_s rrc_pdcp_cfg; - - // t reordering -- Need S - if (pdcp_cfg.rx.t_reordering != pdcp_t_reordering::infinity) { - rrc_pdcp_cfg.t_reordering_present = true; - rrc_pdcp_cfg.t_reordering = t_reordering_to_asn1(pdcp_cfg.rx.t_reordering); - } - - // ciphering disabled present -- Cond ConnectedTo5GC - if (!pdcp_cfg.ciphering_required) { - rrc_pdcp_cfg.ciphering_disabled_present = true; - // this is an extension field. - rrc_pdcp_cfg.ext = true; - } - - // more than one rlc - rrc_pdcp_cfg.more_than_one_rlc_present = false; // not supported. - - // no more configurable parameters for SRBs - if (pdcp_cfg.rb_type == pdcp_rb_type::srb) { - return rrc_pdcp_cfg; - } - - // drb -- Cond DRB - rrc_pdcp_cfg.drb_present = true; - - // hdr compress - rrc_pdcp_cfg.drb.hdr_compress.set_not_used(); // not supported. - - // discard timer -- Cond Setup - if (pdcp_cfg.tx.discard_timer.has_value()) { - rrc_pdcp_cfg.drb.discard_timer_present = true; - rrc_pdcp_cfg.drb.discard_timer = discard_timer_to_asn1(pdcp_cfg.tx.discard_timer.value()); - } - - // pdcp sn size ul -- Cond Setup2 - rrc_pdcp_cfg.drb.pdcp_sn_size_ul_present = true; - asn1::number_to_enum(rrc_pdcp_cfg.drb.pdcp_sn_size_ul, pdcp_sn_size_to_uint(pdcp_cfg.rx.sn_size)); - - // pdcp sn size dl -- Cond Setup2 - rrc_pdcp_cfg.drb.pdcp_sn_size_dl_present = true; - asn1::number_to_enum(rrc_pdcp_cfg.drb.pdcp_sn_size_dl, pdcp_sn_size_to_uint(pdcp_cfg.tx.sn_size)); - - // integrity protection present - rrc_pdcp_cfg.drb.integrity_protection_present = pdcp_cfg.integrity_protection_required; - - // status report required present - rrc_pdcp_cfg.drb.status_report_required_present = pdcp_cfg.tx.status_report_required; - - // out of order delivery present - rrc_pdcp_cfg.drb.out_of_order_delivery_present = pdcp_cfg.rx.out_of_order_delivery; - - return rrc_pdcp_cfg; -} - -inline asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options sdap_hdr_ul_cfg_to_rrc_asn1(sdap_hdr_ul_cfg hdr_cfg) -{ - asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options asn1_hdr_ul_opts; - - if (hdr_cfg == sdap_hdr_ul_cfg::absent) { - asn1_hdr_ul_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options::absent; - } else { - asn1_hdr_ul_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options::present; - } - - return asn1_hdr_ul_opts; -} - -inline asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options sdap_hdr_dl_cfg_to_rrc_asn1(sdap_hdr_dl_cfg hdr_cfg) -{ - asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options asn1_hdr_dl_opts; - - if (hdr_cfg == sdap_hdr_dl_cfg::absent) { - asn1_hdr_dl_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options::absent; - } else { - asn1_hdr_dl_opts = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options::present; - } +asn1::rrc_nr::pdcp_cfg_s pdcp_config_to_rrc_nr_asn1(pdcp_config pdcp_cfg); - return asn1_hdr_dl_opts; -} - -/// \brief Converts type \c sdap_config to an RRC NR ASN.1 type. -/// \param sdap_cfg sdap config object. +/// \brief Converts type \c sdap_hdr_ul_cfg to an RRC NR ASN.1 type. +/// \param[in] hdr_cfg sdap ul header config object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline asn1::rrc_nr::sdap_cfg_s sdap_config_to_rrc_asn1(sdap_config_t sdap_cfg) -{ - asn1::rrc_nr::sdap_cfg_s asn1_sdap_cfg; - - // pdu session - asn1_sdap_cfg.pdu_session = pdu_session_id_to_uint(sdap_cfg.pdu_session); - - // sdap hdr dl - asn1_sdap_cfg.sdap_hdr_dl = sdap_hdr_dl_cfg_to_rrc_asn1(sdap_cfg.sdap_hdr_dl); - - // sdap hdr ul - asn1_sdap_cfg.sdap_hdr_ul = sdap_hdr_ul_cfg_to_rrc_asn1(sdap_cfg.sdap_hdr_ul); - - // default drb - asn1_sdap_cfg.default_drb = sdap_cfg.default_drb; - - // mapped qos flow to add - for (const auto& mapped_qps_flow_to_add : sdap_cfg.mapped_qos_flows_to_add) { - asn1_sdap_cfg.mapped_qos_flows_to_add.push_back(qos_flow_id_to_uint(mapped_qps_flow_to_add)); - } - - // mapped qos flow to release - for (const auto& mapped_qps_flow_to_release : sdap_cfg.mapped_qos_flows_to_release) { - asn1_sdap_cfg.mapped_qos_flows_to_release.push_back(qos_flow_id_to_uint(mapped_qps_flow_to_release)); - } - - return asn1_sdap_cfg; -} - -inline asn1::rrc_nr::ciphering_algorithm_e -ciphering_algorithm_to_rrc_asn1(const security::ciphering_algorithm& ciphering_algo) -{ - asn1::rrc_nr::ciphering_algorithm_e asn1_ciphering_algo; - - switch (ciphering_algo) { - case srsran::security::ciphering_algorithm::nea0: - asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea0; - break; - case srsran::security::ciphering_algorithm::nea1: - asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea1; - break; - case srsran::security::ciphering_algorithm::nea2: - asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea2; - break; - case srsran::security::ciphering_algorithm::nea3: - asn1_ciphering_algo = asn1::rrc_nr::ciphering_algorithm_opts::options::nea3; - break; - default: - // error - report_fatal_error("Cannot convert ciphering algorithm {} to ASN.1 type", ciphering_algo); - } - - return asn1_ciphering_algo; -} +asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::options sdap_hdr_ul_cfg_to_rrc_asn1(sdap_hdr_ul_cfg hdr_cfg); -inline asn1::rrc_nr::integrity_prot_algorithm_e -integrity_prot_algorithm_to_rrc_asn1(const security::integrity_algorithm& integrity_prot_algo) -{ - asn1::rrc_nr::integrity_prot_algorithm_e asn1_integrity_prot_algo; - - switch (integrity_prot_algo) { - case srsran::security::integrity_algorithm::nia0: - asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia0; - break; - case srsran::security::integrity_algorithm::nia1: - asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia1; - break; - case srsran::security::integrity_algorithm::nia2: - asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia2; - break; - case srsran::security::integrity_algorithm::nia3: - asn1_integrity_prot_algo = asn1::rrc_nr::integrity_prot_algorithm_opts::options::nia3; - break; - default: - // error - report_fatal_error("Cannot convert integrity_prot algorithm {} to ASN.1 type", integrity_prot_algo); - } - - return asn1_integrity_prot_algo; -} - -inline cu_cp_five_g_s_tmsi asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<48>& asn1_five_g_s_tmsi) -{ - bounded_bitset<48> five_g_s_tmsi(48); - five_g_s_tmsi.from_uint64(asn1_five_g_s_tmsi.to_number()); - - return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; -} +/// \brief Converts type \c sdap_hdr_dl_cfg to an RRC NR ASN.1 type. +/// \param[in] hdr_cfg sdap dl header config object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::options sdap_hdr_dl_cfg_to_rrc_asn1(sdap_hdr_dl_cfg hdr_cfg); -inline cu_cp_five_g_s_tmsi asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<39>& asn1_five_g_s_tmsi_part1, - const asn1::fixed_bitstring<9>& asn1_five_g_s_tmsi_part2) -{ - bounded_bitset<48> five_g_s_tmsi(48); - five_g_s_tmsi.from_uint64((asn1_five_g_s_tmsi_part2.to_number() << 39) + asn1_five_g_s_tmsi_part1.to_number()); +/// \brief Converts type \c sdap_config_t to an RRC NR ASN.1 type. +/// \param[in] sdap_cfg sdap config object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::sdap_cfg_s sdap_config_to_rrc_asn1(const sdap_config_t& sdap_cfg); - return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; -} +/// \brief Converts type \c security::ciphering_algorithm to an RRC NR ASN.1 type. +/// \param[in] ciphering_algo ciphering algorithm object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::ciphering_algorithm_e +ciphering_algorithm_to_rrc_asn1(const security::ciphering_algorithm& ciphering_algo); -inline cu_cp_amf_identifier_t asn1_to_amf_identifier(const asn1::fixed_bitstring<24>& asn1_amf_id) -{ - cu_cp_amf_identifier_t amf_id; +/// \brief Converts type \c security::integrity_algorithm to an RRC NR ASN.1 type. +/// \param[in] integrity_prot_algo intergrity protection algorithm object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::integrity_prot_algorithm_e +integrity_prot_algorithm_to_rrc_asn1(const security::integrity_algorithm& integrity_prot_algo); - uint32_t amf_identifier = 0; - amf_identifier = (uint32_t)asn1_amf_id.to_number(); +/// \brief Converts type \c asn1::fixed_bitstring<48> to an RRC NR ASN.1 type. +/// \param[in] asn1_five_g_s_tmsi five g s tmsi object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +cu_cp_five_g_s_tmsi asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<48>& asn1_five_g_s_tmsi); - amf_id.amf_region_id = amf_identifier >> 16U; - amf_id.amf_set_id = (amf_identifier - (amf_id.amf_region_id << 16U)) >> 6U; - amf_id.amf_pointer = (amf_identifier << 26U) >> 26U; +/// \brief Converts type \c asn1::fixed_bitstring<39> and \c asn1::fixed_bitstring<9> to an RRC NR ASN.1 type. +/// \param[in] asn1_five_g_s_tmsi_part1 five g s tmsi part 1 object. +/// \param[in] asn1_five_g_s_tmsi_part2 five g s tmsi part 2 object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +cu_cp_five_g_s_tmsi asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<39>& asn1_five_g_s_tmsi_part1, + const asn1::fixed_bitstring<9>& asn1_five_g_s_tmsi_part2); - return amf_id; -} +/// \brief Converts type \c asn1::fixed_bitstring<24> to an RRC NR ASN.1 type. +/// \param[in] asn1_amf_id amf id object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +cu_cp_amf_identifier_t asn1_to_amf_identifier(const asn1::fixed_bitstring<24>& asn1_amf_id); } // namespace srs_cu_cp } // namespace srsran diff --git a/lib/rrc/ue/rrc_asn1_helpers.cpp b/lib/rrc/ue/rrc_asn1_helpers.cpp new file mode 100644 index 0000000000..0964c26461 --- /dev/null +++ b/lib/rrc/ue/rrc_asn1_helpers.cpp @@ -0,0 +1,281 @@ +/* + * + * 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 "rrc_asn1_helpers.h" +#include "rrc_asn1_converters.h" +#include "rrc_measurement_types_asn1_converters.h" + +using namespace srsran; +using namespace srs_cu_cp; + +bool srsran::srs_cu_cp::fill_asn1_rrc_setup_msg(asn1::rrc_nr::rrc_setup_s& rrc_setup, + const byte_buffer& mcg, + uint8_t rrc_transaction_id) +{ + using namespace asn1::rrc_nr; + rrc_setup_ies_s& setup_ies = rrc_setup.crit_exts.set_rrc_setup(); + rrc_setup.rrc_transaction_id = rrc_transaction_id; + + // Add SRB1 + // Note: See TS 38.331 section 5.3.5.6.3 - SRB addition/modification + auto& radio_bearer_cfg = setup_ies.radio_bearer_cfg; + radio_bearer_cfg.srb_to_add_mod_list.push_back(srb_to_add_mod_s{}); + radio_bearer_cfg.srb_to_add_mod_list.back().srb_id = 1; // SRB1 + + // Copy cell config from DU_to_CU_RRC_Container to master cell group + auto& master_cell_group = setup_ies.master_cell_group; + if (!master_cell_group.resize(mcg.length())) { + return false; + } + + std::copy(mcg.begin(), mcg.end(), master_cell_group.begin()); + return true; +} + +expected srsran::srs_cu_cp::get_transaction_id(const asn1::rrc_nr::rrc_setup_complete_s& msg) +{ + return msg.rrc_transaction_id; +} + +expected srsran::srs_cu_cp::get_transaction_id(const asn1::rrc_nr::ul_dcch_msg_s& msg) +{ + using namespace asn1::rrc_nr; + switch (msg.msg.c1().type().value) { + case ul_dcch_msg_type_c::c1_c_::types_opts::rrc_setup_complete: + return msg.msg.c1().rrc_setup_complete().rrc_transaction_id; + // TODO: Remaining cases. + default: + break; + } + return make_unexpected(default_error_t{}); +} + +void srsran::srs_cu_cp::fill_asn1_rrc_smc_msg(asn1::rrc_nr::security_mode_cmd_s& rrc_smc, + const security::integrity_algorithm& int_algo, + const security::ciphering_algorithm& ciph_algo, + uint8_t rrc_transaction_id) +{ + using namespace asn1::rrc_nr; + security_mode_cmd_ies_s& smc_ies = rrc_smc.crit_exts.set_security_mode_cmd(); + rrc_smc.rrc_transaction_id = rrc_transaction_id; + + // Set security algorithms + security_cfg_smc_s& security_cfg_smc = smc_ies.security_cfg_smc; + security_algorithm_cfg_s& security_algorithm_cfg = security_cfg_smc.security_algorithm_cfg; + + security_algorithm_cfg.integrity_prot_algorithm_present = true; + switch (int_algo) { + case security::integrity_algorithm::nia0: + security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia0; + break; + case security::integrity_algorithm::nia1: + security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia1; + break; + case security::integrity_algorithm::nia2: + security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia2; + break; + case security::integrity_algorithm::nia3: + security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia3; + break; + } + switch (ciph_algo) { + case security::ciphering_algorithm::nea0: + security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea0; + break; + case security::ciphering_algorithm::nea1: + security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea1; + break; + case security::ciphering_algorithm::nea2: + security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea2; + break; + case security::ciphering_algorithm::nea3: + security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea3; + break; + } +} + +void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recfg_s& asn1_rrc_reconf, + uint8_t rrc_transaction_id, + rrc_reconfiguration_procedure_request rrc_reconf) +{ + using namespace asn1::rrc_nr; + + asn1_rrc_reconf.rrc_transaction_id = rrc_transaction_id; + + rrc_recfg_ies_s& asn1_reconfig_ies = asn1_rrc_reconf.crit_exts.set_rrc_recfg(); + + // radio bearer cfg + if (rrc_reconf.radio_bearer_cfg.has_value()) { + asn1_reconfig_ies.radio_bearer_cfg_present = true; + auto& asn1_radio_bearer_cfg = asn1_reconfig_ies.radio_bearer_cfg; + + auto& cu_cp_radio_bearer_cfg = rrc_reconf.radio_bearer_cfg.value(); + + // srb to add mod list + for (const auto& srb_to_add : cu_cp_radio_bearer_cfg.srb_to_add_mod_list) { + srsran_assert(srb_to_add.srb_id != srb_id_t::nulltype, "Invalid SRB ID"); + + asn1::rrc_nr::srb_to_add_mod_s asn1_srb_to_add; + asn1_srb_to_add.srb_id = srb_id_to_uint(srb_to_add.srb_id); + + asn1_srb_to_add.reestablish_pdcp_present = srb_to_add.reestablish_pdcp_present; + + asn1_srb_to_add.discard_on_pdcp_present = srb_to_add.discard_on_pdcp_present; + + // PDCP config + if (srb_to_add.pdcp_cfg.has_value()) { + asn1_srb_to_add.pdcp_cfg_present = true; + asn1_srb_to_add.pdcp_cfg = pdcp_config_to_rrc_nr_asn1(srb_to_add.pdcp_cfg.value()); + } + + asn1_radio_bearer_cfg.srb_to_add_mod_list.push_back(asn1_srb_to_add); + } + + // drb to add mod list + for (const auto& drb_to_add : cu_cp_radio_bearer_cfg.drb_to_add_mod_list) { + srsran_assert(drb_to_add.drb_id != drb_id_t::invalid, "Invalid DRB ID"); + + asn1::rrc_nr::drb_to_add_mod_s asn1_drb_to_add; + asn1_drb_to_add.drb_id = drb_id_to_uint(drb_to_add.drb_id); + + asn1_drb_to_add.reestablish_pdcp_present = drb_to_add.reestablish_pdcp_present; + + // PDCP config + if (drb_to_add.pdcp_cfg.has_value()) { + asn1_drb_to_add.pdcp_cfg_present = true; + asn1_drb_to_add.pdcp_cfg = pdcp_config_to_rrc_nr_asn1(drb_to_add.pdcp_cfg.value()); + } + + // Add CN association and SDAP config + if (drb_to_add.cn_assoc.has_value()) { + asn1_drb_to_add.cn_assoc_present = true; + if (drb_to_add.cn_assoc.value().sdap_cfg.has_value()) { + asn1_drb_to_add.cn_assoc.set_sdap_cfg(); + asn1_drb_to_add.cn_assoc.sdap_cfg() = sdap_config_to_rrc_asn1(drb_to_add.cn_assoc.value().sdap_cfg.value()); + } else { + asn1_drb_to_add.cn_assoc.set_eps_bearer_id(); + asn1_drb_to_add.cn_assoc.eps_bearer_id() = drb_to_add.cn_assoc.value().eps_bearer_id.value(); + } + } + + asn1_radio_bearer_cfg.drb_to_add_mod_list.push_back(asn1_drb_to_add); + } + + // drb to release list + for (const auto& drb_to_release : cu_cp_radio_bearer_cfg.drb_to_release_list) { + srsran_assert(drb_to_release != drb_id_t::invalid, "Invalid DRB ID"); + asn1_radio_bearer_cfg.drb_to_release_list.push_back(drb_id_to_uint(drb_to_release)); + } + + // security cfg + if (cu_cp_radio_bearer_cfg.security_cfg.has_value()) { + asn1_radio_bearer_cfg.security_cfg_present = true; + + const auto& security_cfg = cu_cp_radio_bearer_cfg.security_cfg.value(); + + // security algorithm cfg + if (security_cfg.security_algorithm_cfg.has_value()) { + asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg_present = true; + + // ciphering algorithm + asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.ciphering_algorithm = + ciphering_algorithm_to_rrc_asn1(security_cfg.security_algorithm_cfg.value().ciphering_algorithm); + + // integrity prot algorithm + if (security_cfg.security_algorithm_cfg.value().integrity_prot_algorithm.has_value()) { + asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.integrity_prot_algorithm_present = true; + asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.integrity_prot_algorithm = + integrity_prot_algorithm_to_rrc_asn1( + security_cfg.security_algorithm_cfg.value().integrity_prot_algorithm.value()); + } + } + // key to use + if (security_cfg.key_to_use.has_value()) { + asn1_radio_bearer_cfg.security_cfg.key_to_use_present = true; + asn1::string_to_enum(asn1_radio_bearer_cfg.security_cfg.key_to_use, security_cfg.key_to_use.value()); + } + } + + // srb3 to release present + asn1_radio_bearer_cfg.srb3_to_release_present = cu_cp_radio_bearer_cfg.srb3_to_release_present; + } + + // secondary cell group + asn1_reconfig_ies.secondary_cell_group = rrc_reconf.secondary_cell_group.copy(); + + // meas config + if (rrc_reconf.meas_cfg.has_value()) { + asn1_reconfig_ies.meas_cfg_present = true; + asn1_reconfig_ies.meas_cfg = meas_config_to_rrc_asn1(rrc_reconf.meas_cfg.value()); + } + + // non crit ext + if (rrc_reconf.non_crit_ext.has_value()) { + asn1_reconfig_ies.non_crit_ext_present = true; + const auto& non_crit_ext = rrc_reconf.non_crit_ext.value(); + + // full cfg + asn1_reconfig_ies.non_crit_ext.full_cfg_present = non_crit_ext.full_cfg_present; + + // master cell group config + if (!non_crit_ext.master_cell_group.empty()) { + asn1_reconfig_ies.non_crit_ext.master_cell_group = non_crit_ext.master_cell_group.copy(); + } + + // ded nas msg list + for (const auto& nas_pdu : non_crit_ext.ded_nas_msg_list) { + asn1_reconfig_ies.non_crit_ext.ded_nas_msg_list.push_back(nas_pdu.copy()); + } + + // master key upd + if (non_crit_ext.master_key_upd.has_value()) { + asn1_reconfig_ies.non_crit_ext.master_key_upd_present = true; + asn1_reconfig_ies.non_crit_ext.master_key_upd.key_set_change_ind = + non_crit_ext.master_key_upd.value().key_set_change_ind; + asn1_reconfig_ies.non_crit_ext.master_key_upd.next_hop_chaining_count = + non_crit_ext.master_key_upd.value().next_hop_chaining_count; + asn1_reconfig_ies.non_crit_ext.master_key_upd.nas_container = + non_crit_ext.master_key_upd.value().nas_container.copy(); + } + + // ded sib1 delivery + if (!non_crit_ext.ded_sib1_delivery.empty()) { + asn1_reconfig_ies.non_crit_ext.ded_sib1_delivery = non_crit_ext.ded_sib1_delivery.copy(); + } + + // ded sys info delivery + if (!non_crit_ext.ded_sys_info_delivery.empty()) { + asn1_reconfig_ies.non_crit_ext.ded_sys_info_delivery = non_crit_ext.ded_sys_info_delivery.copy(); + } + + // other cfg + if (non_crit_ext.other_cfg.has_value()) { + asn1_reconfig_ies.non_crit_ext.other_cfg_present = true; + if (non_crit_ext.other_cfg.value().delay_budget_report_cfg.has_value()) { + asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg_present = true; + const auto& delay_budget_report_cfg = non_crit_ext.other_cfg.value().delay_budget_report_cfg.value(); + + if (delay_budget_report_cfg.type == "setup") { + asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.set_setup(); + asn1::string_to_enum(asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.setup() + .delay_budget_report_prohibit_timer, + delay_budget_report_cfg.delay_budget_report_prohibit_timer); + } else if (delay_budget_report_cfg.type == "release") { + asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.set_release(); + } else { + asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.set( + asn1::rrc_nr::other_cfg_s::delay_budget_report_cfg_c_::types_opts::nulltype); + } + } + } + + // TODO: add further extensions + } +} diff --git a/lib/rrc/ue/rrc_asn1_helpers.h b/lib/rrc/ue/rrc_asn1_helpers.h index bbbdc11c4e..2243bfc430 100644 --- a/lib/rrc/ue/rrc_asn1_helpers.h +++ b/lib/rrc/ue/rrc_asn1_helpers.h @@ -10,297 +10,45 @@ #pragma once -#include "rrc_asn1_converters.h" -#include "rrc_measurement_types_asn1_converters.h" #include "srsran/adt/byte_buffer.h" #include "srsran/adt/expected.h" +#include "srsran/asn1/rrc_nr/dl_dcch_msg.h" #include "srsran/asn1/rrc_nr/ul_dcch_msg.h" #include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" #include "srsran/rrc/rrc_types.h" namespace srsran { - namespace srs_cu_cp { /// \brief Fills ASN.1 RRC Setup struct. /// \param[out] rrc_setup The RRC Setup ASN.1 struct to fill. /// \param[in] init_ul_rrc_transfer_msg The Init_UL_RRC_Transfer message received by the CU. /// \return True on success, otherwise false. -inline bool -fill_asn1_rrc_setup_msg(asn1::rrc_nr::rrc_setup_s& rrc_setup, const byte_buffer& mcg, uint8_t rrc_transaction_id) -{ - using namespace asn1::rrc_nr; - rrc_setup_ies_s& setup_ies = rrc_setup.crit_exts.set_rrc_setup(); - rrc_setup.rrc_transaction_id = rrc_transaction_id; - - // Add SRB1 - // Note: See TS 38.331 section 5.3.5.6.3 - SRB addition/modification - auto& radio_bearer_cfg = setup_ies.radio_bearer_cfg; - radio_bearer_cfg.srb_to_add_mod_list.push_back(srb_to_add_mod_s{}); - radio_bearer_cfg.srb_to_add_mod_list.back().srb_id = 1; // SRB1 - - // Copy cell config from DU_to_CU_RRC_Container to master cell group - auto& master_cell_group = setup_ies.master_cell_group; - if (!master_cell_group.resize(mcg.length())) { - return false; - } - - std::copy(mcg.begin(), mcg.end(), master_cell_group.begin()); - return true; -} +bool fill_asn1_rrc_setup_msg(asn1::rrc_nr::rrc_setup_s& rrc_setup, const byte_buffer& mcg, uint8_t rrc_transaction_id); /// Extracts transaction id of RRC Setup complete message. -inline expected get_transaction_id(const asn1::rrc_nr::rrc_setup_complete_s& msg) -{ - return msg.rrc_transaction_id; -} +expected get_transaction_id(const asn1::rrc_nr::rrc_setup_complete_s& msg); /// Extracts transaction id of UL-DCCH message. -inline expected get_transaction_id(const asn1::rrc_nr::ul_dcch_msg_s& msg) -{ - using namespace asn1::rrc_nr; - switch (msg.msg.c1().type().value) { - case ul_dcch_msg_type_c::c1_c_::types_opts::rrc_setup_complete: - return msg.msg.c1().rrc_setup_complete().rrc_transaction_id; - // TODO: Remaining cases. - default: - break; - } - return make_unexpected(default_error_t{}); -} +expected get_transaction_id(const asn1::rrc_nr::ul_dcch_msg_s& msg); /// \brief Fills ASN.1 RRC Security Mode Command struct. /// \param[out] rrc_smc The RRC security mode command ASN.1 struct to fill. /// \param[in] int_algo The selected integrity protection algorithm. /// \param[in] ciph_algo The selected ciphering algorithm. /// \param[in] rrc_transaction_id The RRC transaction id. -inline void fill_asn1_rrc_smc_msg(asn1::rrc_nr::security_mode_cmd_s& rrc_smc, - const security::integrity_algorithm& int_algo, - const security::ciphering_algorithm& ciph_algo, - uint8_t rrc_transaction_id) -{ - using namespace asn1::rrc_nr; - security_mode_cmd_ies_s& smc_ies = rrc_smc.crit_exts.set_security_mode_cmd(); - rrc_smc.rrc_transaction_id = rrc_transaction_id; - - // Set security algorithms - security_cfg_smc_s& security_cfg_smc = smc_ies.security_cfg_smc; - security_algorithm_cfg_s& security_algorithm_cfg = security_cfg_smc.security_algorithm_cfg; - - security_algorithm_cfg.integrity_prot_algorithm_present = true; - switch (int_algo) { - case security::integrity_algorithm::nia0: - security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia0; - break; - case security::integrity_algorithm::nia1: - security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia1; - break; - case security::integrity_algorithm::nia2: - security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia2; - break; - case security::integrity_algorithm::nia3: - security_algorithm_cfg.integrity_prot_algorithm = integrity_prot_algorithm_e::nia3; - break; - } - switch (ciph_algo) { - case security::ciphering_algorithm::nea0: - security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea0; - break; - case security::ciphering_algorithm::nea1: - security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea1; - break; - case security::ciphering_algorithm::nea2: - security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea2; - break; - case security::ciphering_algorithm::nea3: - security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_e::nea3; - break; - } -} +void fill_asn1_rrc_smc_msg(asn1::rrc_nr::security_mode_cmd_s& rrc_smc, + const security::integrity_algorithm& int_algo, + const security::ciphering_algorithm& ciph_algo, + uint8_t rrc_transaction_id); /// \brief Fills ASN.1 RRC Setup struct. /// \param[out] asn1_rrc_reconf The RRC Reconfiguration ASN.1 struct to fill. /// \param[in] rrc_transaction_id The RRC transaction id. /// \param[in] rrc_reconf The common type struct. -inline void fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recfg_s& asn1_rrc_reconf, - uint8_t rrc_transaction_id, - rrc_reconfiguration_procedure_request rrc_reconf) -{ - using namespace asn1::rrc_nr; - - asn1_rrc_reconf.rrc_transaction_id = rrc_transaction_id; - - rrc_recfg_ies_s& asn1_reconfig_ies = asn1_rrc_reconf.crit_exts.set_rrc_recfg(); - - // radio bearer cfg - if (rrc_reconf.radio_bearer_cfg.has_value()) { - asn1_reconfig_ies.radio_bearer_cfg_present = true; - auto& asn1_radio_bearer_cfg = asn1_reconfig_ies.radio_bearer_cfg; - - auto& cu_cp_radio_bearer_cfg = rrc_reconf.radio_bearer_cfg.value(); - - // srb to add mod list - for (const auto& srb_to_add : cu_cp_radio_bearer_cfg.srb_to_add_mod_list) { - srsran_assert(srb_to_add.srb_id != srb_id_t::nulltype, "Invalid SRB ID"); - - asn1::rrc_nr::srb_to_add_mod_s asn1_srb_to_add; - asn1_srb_to_add.srb_id = srb_id_to_uint(srb_to_add.srb_id); - - asn1_srb_to_add.reestablish_pdcp_present = srb_to_add.reestablish_pdcp_present; - - asn1_srb_to_add.discard_on_pdcp_present = srb_to_add.discard_on_pdcp_present; - - // PDCP config - if (srb_to_add.pdcp_cfg.has_value()) { - asn1_srb_to_add.pdcp_cfg_present = true; - asn1_srb_to_add.pdcp_cfg = pdcp_config_to_rrc_nr_asn1(srb_to_add.pdcp_cfg.value()); - } - - asn1_radio_bearer_cfg.srb_to_add_mod_list.push_back(asn1_srb_to_add); - } - - // drb to add mod list - for (const auto& drb_to_add : cu_cp_radio_bearer_cfg.drb_to_add_mod_list) { - srsran_assert(drb_to_add.drb_id != drb_id_t::invalid, "Invalid DRB ID"); - - asn1::rrc_nr::drb_to_add_mod_s asn1_drb_to_add; - asn1_drb_to_add.drb_id = drb_id_to_uint(drb_to_add.drb_id); - - asn1_drb_to_add.reestablish_pdcp_present = drb_to_add.reestablish_pdcp_present; - - // PDCP config - if (drb_to_add.pdcp_cfg.has_value()) { - asn1_drb_to_add.pdcp_cfg_present = true; - asn1_drb_to_add.pdcp_cfg = pdcp_config_to_rrc_nr_asn1(drb_to_add.pdcp_cfg.value()); - } - - // Add CN association and SDAP config - if (drb_to_add.cn_assoc.has_value()) { - asn1_drb_to_add.cn_assoc_present = true; - if (drb_to_add.cn_assoc.value().sdap_cfg.has_value()) { - asn1_drb_to_add.cn_assoc.set_sdap_cfg(); - asn1_drb_to_add.cn_assoc.sdap_cfg() = sdap_config_to_rrc_asn1(drb_to_add.cn_assoc.value().sdap_cfg.value()); - } else { - asn1_drb_to_add.cn_assoc.set_eps_bearer_id(); - asn1_drb_to_add.cn_assoc.eps_bearer_id() = drb_to_add.cn_assoc.value().eps_bearer_id.value(); - } - } - - asn1_radio_bearer_cfg.drb_to_add_mod_list.push_back(asn1_drb_to_add); - } - - // drb to release list - for (const auto& drb_to_release : cu_cp_radio_bearer_cfg.drb_to_release_list) { - srsran_assert(drb_to_release != drb_id_t::invalid, "Invalid DRB ID"); - asn1_radio_bearer_cfg.drb_to_release_list.push_back(drb_id_to_uint(drb_to_release)); - } - - // security cfg - if (cu_cp_radio_bearer_cfg.security_cfg.has_value()) { - asn1_radio_bearer_cfg.security_cfg_present = true; - - const auto& security_cfg = cu_cp_radio_bearer_cfg.security_cfg.value(); - - // security algorithm cfg - if (security_cfg.security_algorithm_cfg.has_value()) { - asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg_present = true; - - // ciphering algorithm - asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.ciphering_algorithm = - ciphering_algorithm_to_rrc_asn1(security_cfg.security_algorithm_cfg.value().ciphering_algorithm); - - // integrity prot algorithm - if (security_cfg.security_algorithm_cfg.value().integrity_prot_algorithm.has_value()) { - asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.integrity_prot_algorithm_present = true; - asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.integrity_prot_algorithm = - integrity_prot_algorithm_to_rrc_asn1( - security_cfg.security_algorithm_cfg.value().integrity_prot_algorithm.value()); - } - } - // key to use - if (security_cfg.key_to_use.has_value()) { - asn1_radio_bearer_cfg.security_cfg.key_to_use_present = true; - asn1::string_to_enum(asn1_radio_bearer_cfg.security_cfg.key_to_use, security_cfg.key_to_use.value()); - } - } - - // srb3 to release present - asn1_radio_bearer_cfg.srb3_to_release_present = cu_cp_radio_bearer_cfg.srb3_to_release_present; - } - - // secondary cell group - asn1_reconfig_ies.secondary_cell_group = rrc_reconf.secondary_cell_group.copy(); - - // meas config - if (rrc_reconf.meas_cfg.has_value()) { - asn1_reconfig_ies.meas_cfg_present = true; - asn1_reconfig_ies.meas_cfg = meas_config_to_rrc_asn1(rrc_reconf.meas_cfg.value()); - } - - // non crit ext - if (rrc_reconf.non_crit_ext.has_value()) { - asn1_reconfig_ies.non_crit_ext_present = true; - const auto& non_crit_ext = rrc_reconf.non_crit_ext.value(); - - // full cfg - asn1_reconfig_ies.non_crit_ext.full_cfg_present = non_crit_ext.full_cfg_present; - - // master cell group config - if (!non_crit_ext.master_cell_group.empty()) { - asn1_reconfig_ies.non_crit_ext.master_cell_group = non_crit_ext.master_cell_group.copy(); - } - - // ded nas msg list - for (const auto& nas_pdu : non_crit_ext.ded_nas_msg_list) { - asn1_reconfig_ies.non_crit_ext.ded_nas_msg_list.push_back(nas_pdu.copy()); - } - - // master key upd - if (non_crit_ext.master_key_upd.has_value()) { - asn1_reconfig_ies.non_crit_ext.master_key_upd_present = true; - asn1_reconfig_ies.non_crit_ext.master_key_upd.key_set_change_ind = - non_crit_ext.master_key_upd.value().key_set_change_ind; - asn1_reconfig_ies.non_crit_ext.master_key_upd.next_hop_chaining_count = - non_crit_ext.master_key_upd.value().next_hop_chaining_count; - asn1_reconfig_ies.non_crit_ext.master_key_upd.nas_container = - non_crit_ext.master_key_upd.value().nas_container.copy(); - } - - // ded sib1 delivery - if (!non_crit_ext.ded_sib1_delivery.empty()) { - asn1_reconfig_ies.non_crit_ext.ded_sib1_delivery = non_crit_ext.ded_sib1_delivery.copy(); - } - - // ded sys info delivery - if (!non_crit_ext.ded_sys_info_delivery.empty()) { - asn1_reconfig_ies.non_crit_ext.ded_sys_info_delivery = non_crit_ext.ded_sys_info_delivery.copy(); - } - - // other cfg - if (non_crit_ext.other_cfg.has_value()) { - asn1_reconfig_ies.non_crit_ext.other_cfg_present = true; - if (non_crit_ext.other_cfg.value().delay_budget_report_cfg.has_value()) { - asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg_present = true; - const auto& delay_budget_report_cfg = non_crit_ext.other_cfg.value().delay_budget_report_cfg.value(); - - if (delay_budget_report_cfg.type == "setup") { - asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.set_setup(); - asn1::string_to_enum(asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.setup() - .delay_budget_report_prohibit_timer, - delay_budget_report_cfg.delay_budget_report_prohibit_timer); - } else if (delay_budget_report_cfg.type == "release") { - asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.set_release(); - } else { - asn1_reconfig_ies.non_crit_ext.other_cfg.delay_budget_report_cfg.set( - asn1::rrc_nr::other_cfg_s::delay_budget_report_cfg_c_::types_opts::nulltype); - } - } - } - - // TODO: add further extensions - } -} +void fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recfg_s& asn1_rrc_reconf, + uint8_t rrc_transaction_id, + rrc_reconfiguration_procedure_request rrc_reconf); } // namespace srs_cu_cp - } // namespace srsran diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp b/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp new file mode 100644 index 0000000000..9e939cb6c6 --- /dev/null +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp @@ -0,0 +1,1256 @@ +/* + * + * 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 "rrc_measurement_types_asn1_converters.h" +#include "srsran/srslog/srslog.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; +using namespace srs_cu_cp; + +rrc_ssb_mtc srsran::srs_cu_cp::asn1_to_ssb_mtc(const asn1::rrc_nr::ssb_mtc_s& asn1_ssb_mtc) +{ + rrc_ssb_mtc ssb_mtc; + + // periodicity and offset + switch (asn1_ssb_mtc.periodicity_and_offset.type()) { + case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf5: + ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf5; + ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf5(); + break; + case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf10: + ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf10; + ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf10(); + break; + case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf20: + ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf20; + ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf20(); + break; + case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf40: + ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf40; + ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf40(); + break; + case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf80: + ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf80; + ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf80(); + break; + case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf160: + ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf160; + ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf160(); + break; + default: + srslog::fetch_basic_logger("RRC").error("Invalid SSB MTC configuration."); + } + + // dur + ssb_mtc.dur = asn1_ssb_mtc.dur.to_number(); + + return ssb_mtc; +} + +subcarrier_spacing +srsran::srs_cu_cp::rrc_asn1_to_subcarrier_spacing(const asn1::rrc_nr::subcarrier_spacing_e asn1_sc_spacing) +{ + subcarrier_spacing sc_spacing; + + switch (asn1_sc_spacing) { + case asn1::rrc_nr::subcarrier_spacing_opts::options::khz15: + sc_spacing = srsran::subcarrier_spacing::kHz15; + break; + case asn1::rrc_nr::subcarrier_spacing_opts::options::khz30: + sc_spacing = srsran::subcarrier_spacing::kHz30; + break; + case asn1::rrc_nr::subcarrier_spacing_opts::options::khz60: + sc_spacing = srsran::subcarrier_spacing::kHz60; + break; + case asn1::rrc_nr::subcarrier_spacing_opts::options::khz120: + sc_spacing = srsran::subcarrier_spacing::kHz120; + break; + case asn1::rrc_nr::subcarrier_spacing_opts::options::khz240: + sc_spacing = srsran::subcarrier_spacing::kHz240; + break; + default: + sc_spacing = srsran::subcarrier_spacing::invalid; + } + + return sc_spacing; +} + +rrc_meas_timing srsran::srs_cu_cp::asn1_to_meas_timing(const asn1::rrc_nr::meas_timing_s& asn1_meas_timing) +{ + rrc_meas_timing meas_timing; + + // freq and timing + if (asn1_meas_timing.freq_and_timing_present) { + rrc_meas_timing::rrc_freq_and_timing_ freq_and_timing; + + // carrier freq + freq_and_timing.carrier_freq = asn1_meas_timing.freq_and_timing.carrier_freq; + + // subcarrier spacing + freq_and_timing.ssb_subcarrier_spacing = + rrc_asn1_to_subcarrier_spacing(asn1_meas_timing.freq_and_timing.ssb_subcarrier_spacing); + + // ssb mtc + freq_and_timing.ssb_meas_timing_cfg = asn1_to_ssb_mtc(asn1_meas_timing.freq_and_timing.ssb_meas_timing_cfg); + + // ss rssi meas + if (asn1_meas_timing.freq_and_timing.ss_rssi_meas_present) { + rrc_ss_rssi_meas ss_rssi_meas; + + // meas slots + ss_rssi_meas.meas_slots = asn1_meas_timing.freq_and_timing.ss_rssi_meas.meas_slots.to_number(); + // end symbol + ss_rssi_meas.end_symbol = asn1_meas_timing.freq_and_timing.ss_rssi_meas.end_symbol; + + freq_and_timing.ss_rssi_meas = ss_rssi_meas; + } + + meas_timing.freq_and_timing = freq_and_timing; + } + + return meas_timing; +} + +asn1::rrc_nr::subcarrier_spacing_e srsran::srs_cu_cp::subcarrier_spacing_to_rrc_asn1(subcarrier_spacing sc_spacing) +{ + asn1::rrc_nr::subcarrier_spacing_e asn1_sc_spacing; + + switch (sc_spacing) { + case srsran::subcarrier_spacing::kHz15: + asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz15; + break; + case srsran::subcarrier_spacing::kHz30: + asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz30; + break; + case srsran::subcarrier_spacing::kHz60: + asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz60; + break; + case srsran::subcarrier_spacing::kHz120: + asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz120; + break; + case srsran::subcarrier_spacing::kHz240: + asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz240; + break; + default: + asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::nulltype; + } + + return asn1_sc_spacing; +} + +asn1::rrc_nr::ssb_mtc_s srsran::srs_cu_cp::ssb_mtc_to_rrc_asn1(rrc_ssb_mtc ssb_mtc) +{ + asn1::rrc_nr::ssb_mtc_s asn1_ssb_mtc; + + switch ((uint8_t)ssb_mtc.periodicity_and_offset.periodicity) { + case 5: + asn1_ssb_mtc.periodicity_and_offset.set_sf5(); + asn1_ssb_mtc.periodicity_and_offset.sf5() = ssb_mtc.periodicity_and_offset.offset; + break; + case 10: + asn1_ssb_mtc.periodicity_and_offset.set_sf10(); + asn1_ssb_mtc.periodicity_and_offset.sf10() = ssb_mtc.periodicity_and_offset.offset; + break; + case 20: + asn1_ssb_mtc.periodicity_and_offset.set_sf20(); + asn1_ssb_mtc.periodicity_and_offset.sf20() = ssb_mtc.periodicity_and_offset.offset; + break; + case 40: + asn1_ssb_mtc.periodicity_and_offset.set_sf40(); + asn1_ssb_mtc.periodicity_and_offset.sf40() = ssb_mtc.periodicity_and_offset.offset; + break; + case 80: + asn1_ssb_mtc.periodicity_and_offset.set_sf80(); + asn1_ssb_mtc.periodicity_and_offset.sf80() = ssb_mtc.periodicity_and_offset.offset; + break; + case 160: + asn1_ssb_mtc.periodicity_and_offset.set_sf160(); + asn1_ssb_mtc.periodicity_and_offset.sf160() = ssb_mtc.periodicity_and_offset.offset; + break; + default: + report_fatal_error("Cannot convert SSB MTC to ASN.1 type"); + } + + asn1::number_to_enum(asn1_ssb_mtc.dur, ssb_mtc.dur); + + return asn1_ssb_mtc; +} + +asn1::rrc_nr::ssb_cfg_mob_s srsran::srs_cu_cp::ssb_cfg_mob_to_rrc_asn1(const rrc_ssb_cfg_mob& ssb_cfg_mob) +{ + asn1::rrc_nr::ssb_cfg_mob_s asn1_ssb_cfg_mob; + + // ssb to measure + if (ssb_cfg_mob.ssb_to_measure.has_value()) { + const auto& ssb_to_measure = ssb_cfg_mob.ssb_to_measure.value(); + asn1_ssb_cfg_mob.ssb_to_measure_present = true; + // release + if (ssb_to_measure.is_release) { + asn1_ssb_cfg_mob.ssb_to_measure.set_release(); + } else if (ssb_to_measure.setup.has_value()) { + // setup + asn1_ssb_cfg_mob.ssb_to_measure.set_setup(); + // short bitmap + if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::short_bitmap) { + asn1_ssb_cfg_mob.ssb_to_measure.setup().set_short_bitmap(); + asn1_ssb_cfg_mob.ssb_to_measure.setup().short_bitmap().from_number( + static_cast(ssb_to_measure.setup.value().bitmap)); + } + // medium bitmap + if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::medium_bitmap) { + asn1_ssb_cfg_mob.ssb_to_measure.setup().set_medium_bitmap(); + asn1_ssb_cfg_mob.ssb_to_measure.setup().medium_bitmap().from_number( + static_cast(ssb_to_measure.setup.value().bitmap)); + } + // long bitmap + if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::long_bitmap) { + asn1_ssb_cfg_mob.ssb_to_measure.setup().set_long_bitmap(); + asn1_ssb_cfg_mob.ssb_to_measure.setup().long_bitmap().from_number(ssb_to_measure.setup.value().bitmap); + } + } + } + + // derive ssb idx from cell + asn1_ssb_cfg_mob.derive_ssb_idx_from_cell = ssb_cfg_mob.derive_ssb_idx_from_cell; + + // ss rssi meas + if (ssb_cfg_mob.ss_rssi_meas.has_value()) { + const auto& ss_rssi_meas = ssb_cfg_mob.ss_rssi_meas.value(); + asn1_ssb_cfg_mob.ss_rssi_meas_present = true; + asn1_ssb_cfg_mob.ss_rssi_meas.meas_slots.from_number(ss_rssi_meas.meas_slots); + asn1_ssb_cfg_mob.ss_rssi_meas.end_symbol = ss_rssi_meas.end_symbol; + } + + return asn1_ssb_cfg_mob; +} + +asn1::setup_release_c +srsran::srs_cu_cp::csi_res_cfg_mob_to_rrc_asn1(const rrc_csi_rs_res_cfg_mob_setup_release& csi_rs_res_cfg_mob) +{ + asn1::setup_release_c asn1_csi_rs_res_cfg_mob; + + if (csi_rs_res_cfg_mob.is_release) { + asn1_csi_rs_res_cfg_mob.set_release(); + } else if (csi_rs_res_cfg_mob.setup.has_value()) { + asn1_csi_rs_res_cfg_mob.set_setup(); + // subcarrier spacing + asn1_csi_rs_res_cfg_mob.setup().subcarrier_spacing = + subcarrier_spacing_to_rrc_asn1(csi_rs_res_cfg_mob.setup.value().sc_spacing); + // csi rs cell list mob + for (const auto& csi_rs_cell_mob : csi_rs_res_cfg_mob.setup.value().csi_rs_cell_list_mob) { + asn1::rrc_nr::csi_rs_cell_mob_s asn1_csi_rs_cell_mob; + + // cell id + asn1_csi_rs_cell_mob.cell_id = csi_rs_cell_mob.cell_id; + // csi rs meas bw + asn1::number_to_enum(asn1_csi_rs_cell_mob.csi_rs_meas_bw.nrof_prbs, csi_rs_cell_mob.csi_rs_meas_bw.nrof_prbs); + asn1_csi_rs_cell_mob.csi_rs_meas_bw.start_prb = csi_rs_cell_mob.csi_rs_meas_bw.start_prb; + // density + if (csi_rs_cell_mob.density.has_value()) { + asn1_csi_rs_cell_mob.density_present = true; + asn1::number_to_enum(asn1_csi_rs_cell_mob.density, csi_rs_cell_mob.density.value()); + } + // csi rs res list mob + for (const auto& csi_rs_res_mob : csi_rs_cell_mob.csi_rs_res_list_mob) { + asn1::rrc_nr::csi_rs_res_mob_s asn1_csi_rs_res_mob; + + // csi rs idx + asn1_csi_rs_res_mob.csi_rs_idx = csi_rs_res_mob.csi_rs_idx; + // slot cfg + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms4) { + asn1_csi_rs_res_mob.slot_cfg.set_ms4() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms5) { + asn1_csi_rs_res_mob.slot_cfg.set_ms5() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms10) { + asn1_csi_rs_res_mob.slot_cfg.set_ms10() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms20) { + asn1_csi_rs_res_mob.slot_cfg.set_ms20() = static_cast(csi_rs_res_mob.slot_cfg.offset); + } + if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms40) { + asn1_csi_rs_res_mob.slot_cfg.set_ms40() = csi_rs_res_mob.slot_cfg.offset; + } + // associated ssb + if (csi_rs_res_mob.associated_ssb.has_value()) { + asn1_csi_rs_res_mob.associated_ssb_present = true; + asn1_csi_rs_res_mob.associated_ssb.ssb_idx = csi_rs_res_mob.associated_ssb.value().ssb_idx; + asn1_csi_rs_res_mob.associated_ssb.is_quasi_colocated = + csi_rs_res_mob.associated_ssb.value().is_quasi_colocated; + } + // freq domain alloc + if (std::holds_alternative(csi_rs_res_mob.freq_domain_alloc)) { + asn1_csi_rs_res_mob.freq_domain_alloc.set_row1(); + asn1_csi_rs_res_mob.freq_domain_alloc.row1().from_number( + std::get(csi_rs_res_mob.freq_domain_alloc)); + } + if (std::holds_alternative(csi_rs_res_mob.freq_domain_alloc)) { + asn1_csi_rs_res_mob.freq_domain_alloc.set_row2(); + asn1_csi_rs_res_mob.freq_domain_alloc.row2().from_number( + std::get(csi_rs_res_mob.freq_domain_alloc)); + } + // first ofdm symbol in time domain + asn1_csi_rs_res_mob.first_ofdm_symbol_in_time_domain = csi_rs_res_mob.first_ofdm_symbol_in_time_domain; + // seq generation cfg + asn1_csi_rs_res_mob.seq_generation_cfg = csi_rs_res_mob.seq_generation_cfg; + + asn1_csi_rs_cell_mob.csi_rs_res_list_mob.push_back(asn1_csi_rs_res_mob); + } + + asn1_csi_rs_res_cfg_mob.setup().csi_rs_cell_list_mob.push_back(asn1_csi_rs_cell_mob); + } + } else { + // error + report_fatal_error("Cannot convert CSI RS res cfg mob to ASN.1 type"); + } + + return asn1_csi_rs_res_cfg_mob; +} + +asn1::rrc_nr::thres_nr_s srsran::srs_cu_cp::thres_nr_to_rrc_asn1(const rrc_thres_nr& thres_nr) +{ + asn1::rrc_nr::thres_nr_s asn1_thres_nr; + + // thres rsrp + if (thres_nr.thres_rsrp.has_value()) { + asn1_thres_nr.thres_rsrp_present = true; + asn1_thres_nr.thres_rsrp = thres_nr.thres_rsrp.value(); + } + + // thres rsrq + if (thres_nr.thres_rsrq.has_value()) { + asn1_thres_nr.thres_rsrq_present = true; + asn1_thres_nr.thres_rsrq = thres_nr.thres_rsrq.value(); + } + + // thres sinr + if (thres_nr.thres_sinr.has_value()) { + asn1_thres_nr.thres_sinr_present = true; + asn1_thres_nr.thres_sinr = thres_nr.thres_sinr.value(); + } + + return asn1_thres_nr; +} + +asn1::rrc_nr::q_offset_range_list_s +srsran::srs_cu_cp::q_offset_range_list_to_rrc_asn1(const rrc_q_offset_range_list& q_offset_range_list) +{ + asn1::rrc_nr::q_offset_range_list_s asn1_q_offset_range_list; + + // rsrp offset ssb + if (q_offset_range_list.rsrp_offset_ssb.has_value()) { + asn1_q_offset_range_list.rsrp_offset_ssb_present = true; + asn1::number_to_enum(asn1_q_offset_range_list.rsrp_offset_ssb, q_offset_range_list.rsrp_offset_ssb.value()); + } + // rsrq offset ssb + if (q_offset_range_list.rsrq_offset_ssb.has_value()) { + asn1_q_offset_range_list.rsrq_offset_ssb_present = true; + asn1::number_to_enum(asn1_q_offset_range_list.rsrq_offset_ssb, q_offset_range_list.rsrq_offset_ssb.value()); + } + // sinr offset ssb + if (q_offset_range_list.sinr_offset_ssb.has_value()) { + asn1_q_offset_range_list.sinr_offset_ssb_present = true; + asn1::number_to_enum(asn1_q_offset_range_list.sinr_offset_ssb, q_offset_range_list.sinr_offset_ssb.value()); + } + // rsrp offset csi_rs + if (q_offset_range_list.rsrp_offset_csi_rs.has_value()) { + asn1_q_offset_range_list.rsrp_offset_csi_rs_present = true; + asn1::number_to_enum(asn1_q_offset_range_list.rsrp_offset_csi_rs, q_offset_range_list.rsrp_offset_csi_rs.value()); + } + // rsrq offset csi_rs + if (q_offset_range_list.rsrq_offset_csi_rs.has_value()) { + asn1_q_offset_range_list.rsrq_offset_csi_rs_present = true; + asn1::number_to_enum(asn1_q_offset_range_list.rsrq_offset_csi_rs, q_offset_range_list.rsrq_offset_csi_rs.value()); + } + // sinr offset csi_rs + if (q_offset_range_list.sinr_offset_csi_rs.has_value()) { + asn1_q_offset_range_list.sinr_offset_csi_rs_present = true; + asn1::number_to_enum(asn1_q_offset_range_list.sinr_offset_csi_rs, q_offset_range_list.sinr_offset_csi_rs.value()); + } + + return asn1_q_offset_range_list; +} + +asn1::rrc_nr::meas_obj_nr_s srsran::srs_cu_cp::meas_obj_nr_to_rrc_asn1(const rrc_meas_obj_nr& meas_obj_nr) +{ + asn1::rrc_nr::meas_obj_nr_s asn1_meas_obj_nr; + + // ssb freq + if (meas_obj_nr.ssb_freq.has_value()) { + asn1_meas_obj_nr.ssb_freq_present = true; + asn1_meas_obj_nr.ssb_freq = meas_obj_nr.ssb_freq.value(); + } + + // ssb subcarrier spacing + if (meas_obj_nr.ssb_subcarrier_spacing.has_value()) { + asn1_meas_obj_nr.ssb_subcarrier_spacing_present = true; + asn1_meas_obj_nr.ssb_subcarrier_spacing = + subcarrier_spacing_to_rrc_asn1(meas_obj_nr.ssb_subcarrier_spacing.value()); + } + + // smtc1 + if (meas_obj_nr.smtc1.has_value()) { + asn1_meas_obj_nr.smtc1_present = true; + asn1_meas_obj_nr.smtc1 = ssb_mtc_to_rrc_asn1(meas_obj_nr.smtc1.value()); + } + + // smtc2 + if (meas_obj_nr.smtc2.has_value()) { + asn1_meas_obj_nr.smtc2_present = true; + // pci list + for (const auto& pci : meas_obj_nr.smtc2.value().pci_list) { + asn1_meas_obj_nr.smtc2.pci_list.push_back(pci); + } + // periodicity + asn1::number_to_enum(asn1_meas_obj_nr.smtc2.periodicity, meas_obj_nr.smtc2.value().periodicity); + } + + // ref freq csi rs + if (meas_obj_nr.ref_freq_csi_rs.has_value()) { + asn1_meas_obj_nr.ref_freq_csi_rs_present = true; + asn1_meas_obj_nr.ref_freq_csi_rs = meas_obj_nr.ref_freq_csi_rs.value(); + } + + // ref sig cfg + // ssb cfg mob + if (meas_obj_nr.ref_sig_cfg.ssb_cfg_mob.has_value()) { + asn1_meas_obj_nr.ref_sig_cfg.ssb_cfg_mob_present = true; + asn1_meas_obj_nr.ref_sig_cfg.ssb_cfg_mob = ssb_cfg_mob_to_rrc_asn1(meas_obj_nr.ref_sig_cfg.ssb_cfg_mob.value()); + } + // csi rs res cfg mob + if (meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob.has_value()) { + asn1_meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob_present = true; + asn1_meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob = + csi_res_cfg_mob_to_rrc_asn1(meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob.value()); + } + + // abs thresh ss blocks consolidation + if (meas_obj_nr.abs_thresh_ss_blocks_consolidation.has_value()) { + asn1_meas_obj_nr.abs_thresh_ss_blocks_consolidation_present = true; + asn1_meas_obj_nr.abs_thresh_ss_blocks_consolidation = + thres_nr_to_rrc_asn1(meas_obj_nr.abs_thresh_ss_blocks_consolidation.value()); + } + + // abs thresh csi rs consolidation + if (meas_obj_nr.abs_thresh_csi_rs_consolidation.has_value()) { + asn1_meas_obj_nr.abs_thresh_csi_rs_consolidation_present = true; + asn1_meas_obj_nr.abs_thresh_csi_rs_consolidation = + thres_nr_to_rrc_asn1(meas_obj_nr.abs_thresh_csi_rs_consolidation.value()); + } + + // nrof ss blocks to average + if (meas_obj_nr.nrof_ss_blocks_to_average.has_value()) { + asn1_meas_obj_nr.nrof_ss_blocks_to_average_present = true; + asn1_meas_obj_nr.nrof_ss_blocks_to_average = meas_obj_nr.nrof_ss_blocks_to_average.value(); + } + + // nrof csi rs res to average + if (meas_obj_nr.nrof_csi_rs_res_to_average.has_value()) { + asn1_meas_obj_nr.nrof_csi_rs_res_to_average_present = true; + asn1_meas_obj_nr.nrof_csi_rs_res_to_average = meas_obj_nr.nrof_csi_rs_res_to_average.value(); + } + + // quant cfg idx + asn1_meas_obj_nr.quant_cfg_idx = meas_obj_nr.quant_cfg_idx; + + // offset mo + asn1_meas_obj_nr.offset_mo = q_offset_range_list_to_rrc_asn1(meas_obj_nr.offset_mo); + + // cells to rem list + srsran_assert(meas_obj_nr.cells_to_rem_list.size() <= 32, + "Too many cells to remove ({}>{}).", + meas_obj_nr.cells_to_rem_list.size(), + 32); + for (const auto& cell_to_rem : meas_obj_nr.cells_to_rem_list) { + asn1_meas_obj_nr.cells_to_rem_list.push_back(cell_to_rem); + } + + // cells to add mod list + for (const auto& cell_to_add_mod : meas_obj_nr.cells_to_add_mod_list) { + asn1::rrc_nr::cells_to_add_mod_s asn1_cells_to_add_mod; + + asn1_cells_to_add_mod.pci = cell_to_add_mod.pci; + asn1_cells_to_add_mod.cell_individual_offset = + q_offset_range_list_to_rrc_asn1(cell_to_add_mod.cell_individual_offset); + + asn1_meas_obj_nr.cells_to_add_mod_list.push_back(asn1_cells_to_add_mod); + } + + // excluded cells to rem list + srsran_assert(meas_obj_nr.excluded_cells_to_rem_list.size() <= 8, + "Too many excluded cells to remove ({}>{}).", + meas_obj_nr.excluded_cells_to_rem_list.size(), + 8); + for (const auto& excluded_cell : meas_obj_nr.excluded_cells_to_rem_list) { + asn1_meas_obj_nr.excluded_cells_to_rem_list.push_back(excluded_cell); + } + + // excluded cells to add mod list + for (const auto& excluded_cell : meas_obj_nr.excluded_cells_to_add_mod_list) { + asn1::rrc_nr::pci_range_elem_s asn1_pci_range_elem; + asn1_pci_range_elem.pci_range_idx = excluded_cell.pci_range_idx; + + asn1_pci_range_elem.pci_range.start = excluded_cell.pci_range.start; + if (excluded_cell.pci_range.range.has_value()) { + asn1_pci_range_elem.pci_range.range_present = true; + asn1::number_to_enum(asn1_pci_range_elem.pci_range.range, excluded_cell.pci_range.range.value()); + } + asn1_meas_obj_nr.excluded_cells_to_add_mod_list.push_back(asn1_pci_range_elem); + } + + // allowed cells to rem list + srsran_assert(meas_obj_nr.allowed_cells_to_rem_list.size() <= 8, + "Too many allowed cells to remove ({}>{}).", + meas_obj_nr.allowed_cells_to_rem_list.size(), + 8); + for (const auto& allowed_cell : meas_obj_nr.allowed_cells_to_rem_list) { + asn1_meas_obj_nr.allowed_cells_to_rem_list.push_back(allowed_cell); + } + + // allowed cells to add mod list + for (const auto& allowed_cell : meas_obj_nr.allowed_cells_to_add_mod_list) { + asn1::rrc_nr::pci_range_elem_s asn1_pci_range_elem; + asn1_pci_range_elem.pci_range_idx = allowed_cell.pci_range_idx; + + asn1_pci_range_elem.pci_range.start = allowed_cell.pci_range.start; + if (allowed_cell.pci_range.range.has_value()) { + asn1_pci_range_elem.pci_range.range_present = true; + asn1::number_to_enum(asn1_pci_range_elem.pci_range.range, allowed_cell.pci_range.range.value()); + } + asn1_meas_obj_nr.allowed_cells_to_add_mod_list.push_back(asn1_pci_range_elem); + } + + // group 0 + // freq band ind nr + if (meas_obj_nr.freq_band_ind_nr.has_value()) { + asn1_meas_obj_nr.ext = true; + asn1_meas_obj_nr.freq_band_ind_nr_present = true; + asn1_meas_obj_nr.freq_band_ind_nr = meas_obj_nr.freq_band_ind_nr.value(); + } + // meas cycle scell + if (meas_obj_nr.meas_cycle_scell.has_value()) { + asn1_meas_obj_nr.ext = true; + asn1_meas_obj_nr.meas_cycle_scell_present = true; + asn1::number_to_enum(asn1_meas_obj_nr.meas_cycle_scell, meas_obj_nr.meas_cycle_scell.value()); + } + + return asn1_meas_obj_nr; +} + +template +void srsran::srs_cu_cp::srs_periodicity_and_offset_to_rrc_asn1( + asn1_srs_periodicity_and_offset& asn1_srs_period_and_offset, + const rrc_srs_periodicity_and_offset& srs_period_and_offset) +{ + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms1) { + asn1_srs_period_and_offset.set_sl1(); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms2) { + asn1_srs_period_and_offset.set_sl2() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms4) { + asn1_srs_period_and_offset.set_sl4() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms5) { + asn1_srs_period_and_offset.set_sl5() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms8) { + asn1_srs_period_and_offset.set_sl8() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms10) { + asn1_srs_period_and_offset.set_sl10() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms16) { + asn1_srs_period_and_offset.set_sl16() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms20) { + asn1_srs_period_and_offset.set_sl20() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms32) { + asn1_srs_period_and_offset.set_sl32() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms40) { + asn1_srs_period_and_offset.set_sl40() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms64) { + asn1_srs_period_and_offset.set_sl64() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms80) { + asn1_srs_period_and_offset.set_sl80() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms160) { + asn1_srs_period_and_offset.set_sl160() = static_cast(srs_period_and_offset.offset); + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms320) { + asn1_srs_period_and_offset.set_sl320() = srs_period_and_offset.offset; + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms640) { + asn1_srs_period_and_offset.set_sl640() = srs_period_and_offset.offset; + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms1280) { + asn1_srs_period_and_offset.set_sl1280() = srs_period_and_offset.offset; + } + if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms2560) { + asn1_srs_period_and_offset.set_sl2560() = srs_period_and_offset.offset; + } +}; + +asn1::rrc_nr::srs_res_s srsran::srs_cu_cp::srs_res_to_rrc_asn1(const rrc_srs_res& srs_res) +{ + asn1::rrc_nr::srs_res_s asn1_srs_res; + + // srs res id + asn1_srs_res.srs_res_id = srs_res.srs_res_id; + + // nrof srs ports + asn1::number_to_enum(asn1_srs_res.nrof_srs_ports, srs_res.nrof_srs_ports); + + // ptrs port idx + if (srs_res.ptrs_port_idx.has_value()) { + asn1_srs_res.ptrs_port_idx_present = true; + asn1::number_to_enum(asn1_srs_res.ptrs_port_idx, srs_res.ptrs_port_idx.value()); + } + + // tx comb + if (const auto* n2 = std::get_if(&srs_res.tx_comb); n2 != nullptr) { + asn1_srs_res.tx_comb.set_n2(); + asn1_srs_res.tx_comb.n2().comb_offset_n2 = n2->comb_offset_n2; + asn1_srs_res.tx_comb.n2().cyclic_shift_n2 = n2->cyclic_shift_n2; + } + + if (const auto* n4 = std::get_if(&srs_res.tx_comb); n4 != nullptr) { + asn1_srs_res.tx_comb.set_n4(); + asn1_srs_res.tx_comb.n4().comb_offset_n4 = n4->comb_offset_n4; + asn1_srs_res.tx_comb.n4().cyclic_shift_n4 = n4->cyclic_shift_n4; + } + + // res map + asn1_srs_res.res_map.start_position = srs_res.res_map.start_position; + asn1::number_to_enum(asn1_srs_res.res_map.nrof_symbols, srs_res.res_map.nrof_symbols); + asn1::number_to_enum(asn1_srs_res.res_map.repeat_factor, srs_res.res_map.repeat_factor); + + // freq domain position + asn1_srs_res.freq_domain_position = srs_res.freq_domain_position; + + // freq domain shift + asn1_srs_res.freq_domain_shift = srs_res.freq_domain_shift; + + // freq hop + asn1_srs_res.freq_hop.c_srs = srs_res.freq_hop.c_srs; + asn1_srs_res.freq_hop.b_srs = srs_res.freq_hop.b_srs; + asn1_srs_res.freq_hop.b_hop = srs_res.freq_hop.b_hop; + + // group or seq hop + asn1::string_to_enum(asn1_srs_res.group_or_seq_hop, srs_res.group_or_seq_hop); + + // res type + if (std::holds_alternative(srs_res.res_type)) { + asn1_srs_res.res_type.set_aperiodic(); + } + if (std::holds_alternative(srs_res.res_type)) { + asn1_srs_res.res_type.set_semi_persistent(); + srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_res.res_type.semi_persistent().periodicity_and_offset_sp, + std::get(srs_res.res_type).periodicity_and_offset_sp_p); + } + if (std::holds_alternative(srs_res.res_type)) { + asn1_srs_res.res_type.set_periodic(); + srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_res.res_type.periodic().periodicity_and_offset_p, + std::get(srs_res.res_type).periodicity_and_offset_sp_p); + } + // seq id + asn1_srs_res.seq_id = srs_res.seq_id; + + // spatial relation info + if (srs_res.spatial_relation_info.has_value()) { + // serving cell id + if (srs_res.spatial_relation_info.value().serving_cell_id.has_value()) { + asn1_srs_res.spatial_relation_info.serving_cell_id_present = true; + asn1_srs_res.spatial_relation_info.serving_cell_id = + srs_res.spatial_relation_info.value().serving_cell_id.value(); + } + // ref sig + if (std::holds_alternative( + srs_res.spatial_relation_info.value().ref_sig)) { + asn1_srs_res.spatial_relation_info.ref_sig.set_ssb_idx() = static_cast( + std::get(srs_res.spatial_relation_info.value().ref_sig)); + } + if (std::holds_alternative( + srs_res.spatial_relation_info.value().ref_sig)) { + asn1_srs_res.spatial_relation_info.ref_sig.set_csi_rs_idx() = static_cast( + std::get(srs_res.spatial_relation_info.value().ref_sig)); + } + if (std::holds_alternative(srs_res.spatial_relation_info.value().ref_sig)) { + asn1_srs_res.spatial_relation_info.ref_sig.set_srs(); + asn1_srs_res.spatial_relation_info.ref_sig.srs().res_id = + std::get(srs_res.spatial_relation_info.value().ref_sig).res_id; + asn1_srs_res.spatial_relation_info.ref_sig.srs().ul_bwp = + std::get(srs_res.spatial_relation_info.value().ref_sig).ul_bwp; + } + } + + return asn1_srs_res; +} + +asn1::rrc_nr::meas_obj_to_add_mod_s +srsran::srs_cu_cp::meas_obj_to_add_mod_to_rrc_asn1(const rrc_meas_obj_to_add_mod& meas_obj_to_add_mod) +{ + asn1::rrc_nr::meas_obj_to_add_mod_s asn1_meas_obj_to_add_mod; + + // meas obj id + asn1_meas_obj_to_add_mod.meas_obj_id = meas_obj_id_to_uint(meas_obj_to_add_mod.meas_obj_id); + + // meas obj + if (meas_obj_to_add_mod.meas_obj_nr.has_value()) { + // meas obj nr + asn1_meas_obj_to_add_mod.meas_obj.set_meas_obj_nr(); + asn1_meas_obj_to_add_mod.meas_obj.meas_obj_nr() = meas_obj_nr_to_rrc_asn1(meas_obj_to_add_mod.meas_obj_nr.value()); + } + + return asn1_meas_obj_to_add_mod; +} + +asn1::rrc_nr::meas_report_quant_s +srsran::srs_cu_cp::meas_report_quant_to_rrc_asn1(const rrc_meas_report_quant& meas_report_quant) +{ + asn1::rrc_nr::meas_report_quant_s asn1_meas_report_quant; + + asn1_meas_report_quant.rsrp = meas_report_quant.rsrp; + asn1_meas_report_quant.rsrq = meas_report_quant.rsrq; + asn1_meas_report_quant.sinr = meas_report_quant.sinr; + + return asn1_meas_report_quant; +} + +asn1::rrc_nr::nr_rs_type_e srsran::srs_cu_cp::rrc_nr_rs_type_to_asn1(const rrc_nr_rs_type& rs_type) +{ + asn1::rrc_nr::nr_rs_type_e asn1_rs_type; + + switch (rs_type) { + case rrc_nr_rs_type::ssb: + asn1_rs_type = asn1::rrc_nr::nr_rs_type_opts::options::ssb; + break; + case rrc_nr_rs_type::csi_rs: + asn1_rs_type = asn1::rrc_nr::nr_rs_type_opts::options::csi_rs; + break; + } + + return asn1_rs_type; +} + +asn1::rrc_nr::report_interv_e srsran::srs_cu_cp::report_interval_to_asn1(uint32_t report_interval) +{ + asn1::rrc_nr::report_interv_e asn1_report_interval; + + return asn1_report_interval; +} + +asn1::rrc_nr::periodical_report_cfg_s +srsran::srs_cu_cp::periodical_report_cfg_to_rrc_asn1(const rrc_periodical_report_cfg& periodical_report_cfg) +{ + asn1::rrc_nr::periodical_report_cfg_s asn1_periodical_report_cfg; + + // rs type + asn1_periodical_report_cfg.rs_type = rrc_nr_rs_type_to_asn1(periodical_report_cfg.rs_type); + // report interv. This struct mixes ms and minutes so we need to convert the value before conversion + if (periodical_report_cfg.report_interv < 60000) { + asn1::number_to_enum(asn1_periodical_report_cfg.report_interv, periodical_report_cfg.report_interv); + } else { + asn1::number_to_enum(asn1_periodical_report_cfg.report_interv, periodical_report_cfg.report_interv / 60000); + } + + // report amount + asn1::number_to_enum(asn1_periodical_report_cfg.report_amount, periodical_report_cfg.report_amount); + // report quant cell + asn1_periodical_report_cfg.report_quant_cell = meas_report_quant_to_rrc_asn1(periodical_report_cfg.report_quant_cell); + // max report cells + asn1_periodical_report_cfg.max_report_cells = periodical_report_cfg.max_report_cells; + // report quant rx idxes + if (periodical_report_cfg.report_quant_rs_idxes.has_value()) { + asn1_periodical_report_cfg.report_quant_rs_idxes_present = true; + asn1_periodical_report_cfg.report_quant_rs_idxes = + meas_report_quant_to_rrc_asn1(periodical_report_cfg.report_quant_rs_idxes.value()); + } + // max nrof rs idxes to report + if (periodical_report_cfg.max_nrof_rs_idxes_to_report.has_value()) { + asn1_periodical_report_cfg.max_nrof_rs_idxes_to_report_present = true; + asn1_periodical_report_cfg.max_nrof_rs_idxes_to_report = periodical_report_cfg.max_nrof_rs_idxes_to_report.value(); + } + // include beam meass + asn1_periodical_report_cfg.include_beam_meass = periodical_report_cfg.include_beam_meass; + // use allowed cell list + asn1_periodical_report_cfg.use_allowed_cell_list = periodical_report_cfg.use_allowed_cell_list; + + return asn1_periodical_report_cfg; +} + +template +void srsran::srs_cu_cp::meas_trigger_quant_to_rrc_asn1( + asn1_meas_trigger_quant_quant_offset& asn1_meas_trigger_quant_offset, + const rrc_meas_trigger_quant& meas_trigger_quant) +{ + if (meas_trigger_quant.rsrp.has_value()) { + asn1_meas_trigger_quant_offset.set_rsrp() = meas_trigger_quant.rsrp.value(); + } else if (meas_trigger_quant.rsrq.has_value()) { + asn1_meas_trigger_quant_offset.set_rsrq() = meas_trigger_quant.rsrq.value(); + } else if (meas_trigger_quant.sinr.has_value()) { + asn1_meas_trigger_quant_offset.set_sinr() = meas_trigger_quant.sinr.value(); + } else { + // error + report_fatal_error("Cannot convert meas trigger quant to ASN.1 type"); + } +} + +asn1::rrc_nr::event_trigger_cfg_s +srsran::srs_cu_cp::event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigger_cfg& event_trigger_cfg) +{ + asn1::rrc_nr::event_trigger_cfg_s asn1_event_trigger_cfg = {}; + + // report add neigh meas present + asn1_event_trigger_cfg.report_add_neigh_meas_present = event_trigger_cfg.report_add_neigh_meas_present; + + const auto& event_id = event_trigger_cfg.event_id; + + // event a1 + if (event_id.id == rrc_event_id::event_id_t::a1) { + auto& asn1_event_a1 = asn1_event_trigger_cfg.event_id.set_event_a1(); + meas_trigger_quant_to_rrc_asn1(asn1_event_a1.a1_thres, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a1.report_on_leave = event_id.report_on_leave; + asn1_event_a1.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a1.time_to_trigger, event_id.time_to_trigger); + } + + // event a2 + if (event_id.id == rrc_event_id::event_id_t::a2) { + auto& asn1_event_a2 = asn1_event_trigger_cfg.event_id.set_event_a2(); + meas_trigger_quant_to_rrc_asn1(asn1_event_a2.a2_thres, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a2.report_on_leave = event_id.report_on_leave; + asn1_event_a2.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a2.time_to_trigger, event_id.time_to_trigger); + } + + // event a3 + if (event_id.id == rrc_event_id::event_id_t::a3) { + auto& asn1_event_a3 = asn1_event_trigger_cfg.event_id.set_event_a3(); + meas_trigger_quant_to_rrc_asn1(asn1_event_a3.a3_offset, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a3.report_on_leave = event_id.report_on_leave; + asn1_event_a3.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a3.time_to_trigger, event_id.time_to_trigger); + asn1_event_a3.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // event a4 + if (event_id.id == rrc_event_id::event_id_t::a4) { + auto& asn1_event_a4 = asn1_event_trigger_cfg.event_id.set_event_a4(); + meas_trigger_quant_to_rrc_asn1(asn1_event_a4.a4_thres, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a4.report_on_leave = event_id.report_on_leave; + asn1_event_a4.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a4.time_to_trigger, event_id.time_to_trigger); + asn1_event_a4.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // event a5 + if (event_id.id == rrc_event_id::event_id_t::a5) { + auto& asn1_event_a5 = asn1_event_trigger_cfg.event_id.set_event_a5(); + meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres1, event_id.meas_trigger_quant_thres_or_offset.value()); + meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres2, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a5.report_on_leave = event_id.report_on_leave; + asn1_event_a5.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a5.time_to_trigger, event_id.time_to_trigger); + asn1_event_a5.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // event a6 + if (event_id.id == rrc_event_id::event_id_t::a6) { + auto& asn1_event_a6 = asn1_event_trigger_cfg.event_id.set_event_a6(); + meas_trigger_quant_to_rrc_asn1(asn1_event_a6.a6_offset, event_id.meas_trigger_quant_thres_or_offset.value()); + asn1_event_a6.report_on_leave = event_id.report_on_leave; + asn1_event_a6.hysteresis = event_id.hysteresis; + asn1::number_to_enum(asn1_event_a6.time_to_trigger, event_id.time_to_trigger); + asn1_event_a6.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } + + // rs type + asn1_event_trigger_cfg.rs_type = rrc_nr_rs_type_to_asn1(event_trigger_cfg.rs_type); + + // report interv + // report interv. This struct mixes ms and minutes so we need to convert the value before conversion + if (event_trigger_cfg.report_interv < 60000) { + asn1::number_to_enum(asn1_event_trigger_cfg.report_interv, event_trigger_cfg.report_interv); + } else { + asn1::number_to_enum(asn1_event_trigger_cfg.report_interv, event_trigger_cfg.report_interv / 60000); + } + + // report amount + asn1::number_to_enum(asn1_event_trigger_cfg.report_amount, event_trigger_cfg.report_amount); + + // report quant cell + asn1_event_trigger_cfg.report_quant_cell = meas_report_quant_to_rrc_asn1(event_trigger_cfg.report_quant_cell); + + // max report cells + asn1_event_trigger_cfg.max_report_cells = event_trigger_cfg.max_report_cells; + + // report quant rx idxes + if (event_trigger_cfg.report_quant_rs_idxes.has_value()) { + asn1_event_trigger_cfg.report_quant_rs_idxes_present = true; + asn1_event_trigger_cfg.report_quant_rs_idxes = + meas_report_quant_to_rrc_asn1(event_trigger_cfg.report_quant_rs_idxes.value()); + } + + // max nrof rs idxes to report + if (event_trigger_cfg.max_nrof_rs_idxes_to_report.has_value()) { + asn1_event_trigger_cfg.max_nrof_rs_idxes_to_report_present = true; + asn1_event_trigger_cfg.max_nrof_rs_idxes_to_report = event_trigger_cfg.max_nrof_rs_idxes_to_report.value(); + } + + // include beam meass + asn1_event_trigger_cfg.include_beam_meass = event_trigger_cfg.include_beam_meass; + + return asn1_event_trigger_cfg; +} + +asn1::rrc_nr::report_cfg_nr_s srsran::srs_cu_cp::report_cfg_nr_to_rrc_asn1(const rrc_report_cfg_nr& report_cfg_nr) +{ + asn1::rrc_nr::report_cfg_nr_s asn1_report_cfg_nr; + + if (const auto* periodical = std::get_if(&report_cfg_nr); periodical != nullptr) { + // periodical + asn1_report_cfg_nr.report_type.set_periodical() = periodical_report_cfg_to_rrc_asn1(*periodical); + } + + if (const auto* event_triggered = std::get_if(&report_cfg_nr); event_triggered != nullptr) { + // event triggered + asn1_report_cfg_nr.report_type.set_event_triggered() = event_triggered_report_cfg_to_rrc_asn1(*event_triggered); + } + + if (const auto* report_cgi = std::get_if(&report_cfg_nr); report_cgi != nullptr) { + // report cgi + asn1_report_cfg_nr.report_type.set_report_cgi(); + asn1_report_cfg_nr.report_type.report_cgi().cell_for_which_to_report_cgi = report_cgi->cell_for_which_to_report_cgi; + } + + if (const auto* report_sftd = std::get_if(&report_cfg_nr); report_sftd != nullptr) { + // report sftd + asn1_report_cfg_nr.report_type.set_report_sftd(); + asn1_report_cfg_nr.report_type.report_sftd().report_sftd_meas = report_sftd->report_sftd_meas; + asn1_report_cfg_nr.report_type.report_sftd().report_rsrp = report_sftd->report_rsrp; + } + + return asn1_report_cfg_nr; +} + +asn1::rrc_nr::report_cfg_to_add_mod_s +srsran::srs_cu_cp::report_cfg_to_add_mod_to_rrc_asn1(const rrc_report_cfg_to_add_mod& report_cfg_to_add_mod) +{ + asn1::rrc_nr::report_cfg_to_add_mod_s asn1_report_cfg_to_add_mod; + + // report cfg id + asn1_report_cfg_to_add_mod.report_cfg_id = report_cfg_id_to_uint(report_cfg_to_add_mod.report_cfg_id); + + // report cfg + asn1_report_cfg_to_add_mod.report_cfg.set_report_cfg_nr() = + report_cfg_nr_to_rrc_asn1(report_cfg_to_add_mod.report_cfg); + + return asn1_report_cfg_to_add_mod; +} + +asn1::rrc_nr::meas_id_to_add_mod_s +srsran::srs_cu_cp::meas_id_to_add_mod_to_rrc_asn1(const rrc_meas_id_to_add_mod& meas_id_to_add_mod) +{ + asn1::rrc_nr::meas_id_to_add_mod_s asn1_meas_id_to_add_mod; + + // meas id + asn1_meas_id_to_add_mod.meas_id = meas_id_to_uint(meas_id_to_add_mod.meas_id); + // meas obj id + asn1_meas_id_to_add_mod.meas_obj_id = meas_obj_id_to_uint(meas_id_to_add_mod.meas_obj_id); + // report cfg ind + asn1_meas_id_to_add_mod.report_cfg_id = report_cfg_id_to_uint(meas_id_to_add_mod.report_cfg_id); + + return asn1_meas_id_to_add_mod; +} + +asn1::rrc_nr::filt_cfg_s srsran::srs_cu_cp::filt_cfg_to_rrc_asn1(const rrc_filt_cfg& filt_cfg) +{ + asn1::rrc_nr::filt_cfg_s asn1_filt_cfg; + + // filt coef rsrp + if (filt_cfg.filt_coef_rsrp.has_value()) { + asn1_filt_cfg.filt_coef_rsrp_present = true; + asn1::number_to_enum(asn1_filt_cfg.filt_coef_rsrp, filt_cfg.filt_coef_rsrp.value()); + } + + // filt coef rsrq + if (filt_cfg.filt_coef_rsrq.has_value()) { + asn1_filt_cfg.filt_coef_rsrq_present = true; + asn1::number_to_enum(asn1_filt_cfg.filt_coef_rsrq, filt_cfg.filt_coef_rsrq.value()); + } + + // filt coef rs sinr + if (filt_cfg.filt_coef_rs_sinr.has_value()) { + asn1_filt_cfg.filt_coef_rs_sinr_present = true; + asn1::number_to_enum(asn1_filt_cfg.filt_coef_rs_sinr, filt_cfg.filt_coef_rs_sinr.value()); + } + + return asn1_filt_cfg; +} + +asn1::rrc_nr::quant_cfg_rs_s srsran::srs_cu_cp::quant_cfg_rs_to_rrc_asn1(const rrc_quant_cfg_rs& quant_cfg_rs) +{ + asn1::rrc_nr::quant_cfg_rs_s asn1_quant_cfg_rs; + + // ssb filt cfg + asn1_quant_cfg_rs.ssb_filt_cfg = filt_cfg_to_rrc_asn1(quant_cfg_rs.ssb_filt_cfg); + // csi rs filt cfg + asn1_quant_cfg_rs.csi_rs_filt_cfg = filt_cfg_to_rrc_asn1(quant_cfg_rs.csi_rs_filt_cfg); + + return asn1_quant_cfg_rs; +} + +asn1::rrc_nr::meas_cfg_s srsran::srs_cu_cp::meas_config_to_rrc_asn1(const rrc_meas_cfg& meas_cfg) +{ + asn1::rrc_nr::meas_cfg_s asn1_meas_cfg; + + // meas obj to rem list + for (const auto& meas_obj_to_rem : meas_cfg.meas_obj_to_rem_list) { + asn1_meas_cfg.meas_obj_to_rem_list.push_back(meas_obj_id_to_uint(meas_obj_to_rem)); + } + + // meas obj to add mod list + for (const auto& meas_obj_to_add_mod : meas_cfg.meas_obj_to_add_mod_list) { + asn1::rrc_nr::meas_obj_to_add_mod_s asn1_meas_obj_to_add_mod = meas_obj_to_add_mod_to_rrc_asn1(meas_obj_to_add_mod); + asn1_meas_cfg.meas_obj_to_add_mod_list.push_back(asn1_meas_obj_to_add_mod); + } + + // report cfg to rem list + for (const auto& report_cfg_to_rem : meas_cfg.report_cfg_to_rem_list) { + asn1_meas_cfg.report_cfg_to_rem_list.push_back(report_cfg_id_to_uint(report_cfg_to_rem)); + } + + // report cfg to add mod list + for (const auto& report_cfg_to_add_mod : meas_cfg.report_cfg_to_add_mod_list) { + asn1::rrc_nr::report_cfg_to_add_mod_s asn1_report_cfg_to_add_mod = + report_cfg_to_add_mod_to_rrc_asn1(report_cfg_to_add_mod); + asn1_meas_cfg.report_cfg_to_add_mod_list.push_back(asn1_report_cfg_to_add_mod); + } + + // meas id to rem list + for (const auto& meas_id_to_rem : meas_cfg.meas_id_to_rem_list) { + asn1_meas_cfg.meas_id_to_rem_list.push_back(meas_id_to_uint(meas_id_to_rem)); + } + + // meas id to add mod list + for (const auto& meas_id_to_add_mod : meas_cfg.meas_id_to_add_mod_list) { + asn1::rrc_nr::meas_id_to_add_mod_s asn1_meas_id_to_add_mod = meas_id_to_add_mod_to_rrc_asn1(meas_id_to_add_mod); + asn1_meas_cfg.meas_id_to_add_mod_list.push_back(asn1_meas_id_to_add_mod); + } + + // s measure cfg + if (meas_cfg.s_measure_cfg.has_value()) { + asn1_meas_cfg.s_measure_cfg_present = true; + if (meas_cfg.s_measure_cfg.value().type == rrc_s_measure_cfg::measure_type_t::ssb_rsrp) { + asn1_meas_cfg.s_measure_cfg.set_ssb_rsrp() = meas_cfg.s_measure_cfg.value().measure_config; + } + + if (meas_cfg.s_measure_cfg.value().type == rrc_s_measure_cfg::measure_type_t::csi_rsrp) { + asn1_meas_cfg.s_measure_cfg.set_csi_rsrp() = meas_cfg.s_measure_cfg.value().measure_config; + } + } + + // quant cfg + if (meas_cfg.quant_cfg.has_value()) { + asn1_meas_cfg.quant_cfg_present = true; + for (const auto& quant_cfg_nr : meas_cfg.quant_cfg.value().quant_cfg_nr_list) { + asn1::rrc_nr::quant_cfg_nr_s asn1_quant_cfg_nr; + + // quant cfg cell + asn1_quant_cfg_nr.quant_cfg_cell = quant_cfg_rs_to_rrc_asn1(quant_cfg_nr.quant_cfg_cell); + + // quant cfg rs idx + if (quant_cfg_nr.quant_cfg_rs_idx.has_value()) { + asn1_quant_cfg_nr.quant_cfg_rs_idx_present = true; + asn1_quant_cfg_nr.quant_cfg_rs_idx = quant_cfg_rs_to_rrc_asn1(quant_cfg_nr.quant_cfg_rs_idx.value()); + } + + asn1_meas_cfg.quant_cfg.quant_cfg_nr_list.push_back(asn1_quant_cfg_nr); + } + } + + // meas gap cfg + if (meas_cfg.meas_gap_cfg.has_value()) { + asn1_meas_cfg.meas_gap_cfg_present = true; + if (meas_cfg.meas_gap_cfg.value().gap_fr2.has_value()) { + asn1_meas_cfg.meas_gap_cfg.gap_fr2_present = true; + if (meas_cfg.meas_gap_cfg.value().gap_fr2.value().is_release) { + asn1_meas_cfg.meas_gap_cfg.gap_fr2.set_release(); + } else if (meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.has_value()) { + asn1_meas_cfg.meas_gap_cfg.gap_fr2.set_setup(); + // gap offset + asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().gap_offset = + meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().gap_offset; + // mgl + asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgl, + meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgl); + // mgrp + asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgrp, + meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgrp); + // mgta + asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgta, + meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgta); + } else { + // error + report_fatal_error("Cannot convert gap fr2 to ASN.1 type"); + } + } + } + + // meas gap sharing cfg + if (meas_cfg.meas_gap_sharing_cfg.has_value()) { + asn1_meas_cfg.meas_gap_sharing_cfg_present = true; + if (meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.has_value()) { + asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2_present = true; + if (meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().is_release) { + asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.set_release(); + } else if (!meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().setup.value().empty()) { + asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.set_setup(); + asn1::string_to_enum(asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.setup(), + meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().setup.value()); + } else { + // error + report_fatal_error("Cannot convert gap sharing fr2 to ASN.1 type"); + } + } + } + + return asn1_meas_cfg; +} + +rrc_meas_quant_results +srsran::srs_cu_cp::asn1_to_meas_quant_results(const asn1::rrc_nr::meas_quant_results_s& asn1_meas_quant_results) +{ + rrc_meas_quant_results meas_quant_results; + + // rsrp + if (asn1_meas_quant_results.rsrp_present) { + meas_quant_results.rsrp = asn1_meas_quant_results.rsrp; + } + + // rsrq + if (asn1_meas_quant_results.rsrq_present) { + meas_quant_results.rsrq = asn1_meas_quant_results.rsrq; + } + + // sinr + if (asn1_meas_quant_results.sinr_present) { + meas_quant_results.sinr = asn1_meas_quant_results.sinr; + } + + return meas_quant_results; +}; + +rrc_meas_result_nr srsran::srs_cu_cp::asn1_to_meas_result_nr(const asn1::rrc_nr::meas_result_nr_s& asn1_meas_result_nr) +{ + rrc_meas_result_nr meas_result_nr; + + // pci + if (asn1_meas_result_nr.pci_present) { + meas_result_nr.pci = asn1_meas_result_nr.pci; + } + + // cell results + // results ssb cell + if (asn1_meas_result_nr.meas_result.cell_results.results_ssb_cell_present) { + meas_result_nr.cell_results.results_ssb_cell = + asn1_to_meas_quant_results(asn1_meas_result_nr.meas_result.cell_results.results_ssb_cell); + } + // results csi rs cell + if (asn1_meas_result_nr.meas_result.cell_results.results_csi_rs_cell_present) { + meas_result_nr.cell_results.results_csi_rs_cell = + asn1_to_meas_quant_results(asn1_meas_result_nr.meas_result.cell_results.results_csi_rs_cell); + } + + // rs idx results + if (asn1_meas_result_nr.meas_result.rs_idx_results_present) { + rrc_meas_result_nr::rs_idx_results_ rs_idx_result; + + // results ssb idxes + for (const auto& asn1_ssb_result : asn1_meas_result_nr.meas_result.rs_idx_results.results_ssb_idxes) { + rrc_results_per_ssb_idx ssb_result; + + ssb_result.ssb_idx = asn1_ssb_result.ssb_idx; + + if (asn1_ssb_result.ssb_results_present) { + ssb_result.ssb_results = asn1_to_meas_quant_results(asn1_ssb_result.ssb_results); + } + rs_idx_result.results_ssb_idxes.emplace(asn1_ssb_result.ssb_idx, ssb_result); + } + + // results csi_rs idxes + for (const auto& asn1_csi_rs_result : asn1_meas_result_nr.meas_result.rs_idx_results.results_csi_rs_idxes) { + rrc_results_per_csi_rs_idx csi_rs_result; + if (asn1_csi_rs_result.csi_rs_results_present) { + csi_rs_result.csi_rs_results = asn1_to_meas_quant_results(asn1_csi_rs_result.csi_rs_results); + } + rs_idx_result.results_csi_rs_idxes.emplace(asn1_csi_rs_result.csi_rs_idx, csi_rs_result); + } + + meas_result_nr.rs_idx_results = rs_idx_result; + } + + return meas_result_nr; +}; + +rrc_meas_results srsran::srs_cu_cp::asn1_to_measurement_results(const asn1::rrc_nr::meas_results_s& asn1_meas_results, + srslog::basic_logger& logger) +{ + rrc_meas_results meas_results; + + // meas id + meas_results.meas_id = uint_to_meas_id(asn1_meas_results.meas_id); + + // meas result serving mo list + for (const auto& asn1_meas_result_serv_mo : asn1_meas_results.meas_result_serving_mo_list) { + rrc_meas_result_serv_mo meas_result_serv_mo; + + // serv cell id + meas_result_serv_mo.serv_cell_id = asn1_meas_result_serv_mo.serv_cell_id; + // meas result serving cell + meas_result_serv_mo.meas_result_serving_cell = + asn1_to_meas_result_nr(asn1_meas_result_serv_mo.meas_result_serving_cell); + // meas result best neigh cell + if (asn1_meas_result_serv_mo.meas_result_best_neigh_cell_present) { + meas_result_serv_mo.meas_result_best_neigh_cell = + asn1_to_meas_result_nr(asn1_meas_result_serv_mo.meas_result_best_neigh_cell); + } + + meas_results.meas_result_serving_mo_list.emplace(asn1_meas_result_serv_mo.serv_cell_id, meas_result_serv_mo); + } + + // meas result neigh cells + if (asn1_meas_results.meas_result_neigh_cells_present) { + rrc_meas_result_neigh_cells meas_result_neigh_cell; + + if (asn1_meas_results.meas_result_neigh_cells.type() == + asn1::rrc_nr::meas_results_s::meas_result_neigh_cells_c_::types_opts::options::meas_result_list_nr) { + // meas result list nr + for (const auto& asn1_meas_result_nr : asn1_meas_results.meas_result_neigh_cells.meas_result_list_nr()) { + meas_result_neigh_cell.meas_result_list_nr.push_back(asn1_to_meas_result_nr(asn1_meas_result_nr)); + } + } else { + // error + logger.error("Ignoring neighbor cell measurement. Cause: Unsupported cell type {}", + asn1_meas_results.meas_result_neigh_cells.type().to_string()); + } + + meas_results.meas_result_neigh_cells = meas_result_neigh_cell; + } + + return meas_results; +} diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h index 9c26edff17..6f72005ddb 100644 --- a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h @@ -17,1261 +17,154 @@ #include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" #include "srsran/ran/subcarrier_spacing.h" #include "srsran/rrc/meas_types.h" -#include "srsran/srslog/srslog.h" -#include "srsran/support/error_handling.h" + #include #include namespace srsran { namespace srs_cu_cp { -inline rrc_ssb_mtc asn1_to_ssb_mtc(const asn1::rrc_nr::ssb_mtc_s& asn1_ssb_mtc) -{ - rrc_ssb_mtc ssb_mtc; - - // periodicity and offset - switch (asn1_ssb_mtc.periodicity_and_offset.type()) { - case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf5: - ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf5; - ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf5(); - break; - case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf10: - ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf10; - ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf10(); - break; - case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf20: - ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf20; - ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf20(); - break; - case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf40: - ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf40; - ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf40(); - break; - case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf80: - ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf80; - ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf80(); - break; - case asn1::rrc_nr::ssb_mtc_s::periodicity_and_offset_c_::types_opts::options::sf160: - ssb_mtc.periodicity_and_offset.periodicity = rrc_periodicity_and_offset::periodicity_t::sf160; - ssb_mtc.periodicity_and_offset.offset = asn1_ssb_mtc.periodicity_and_offset.sf160(); - break; - default: - srslog::fetch_basic_logger("RRC").error("Invalid SSB MTC configuration."); - } - - // dur - ssb_mtc.dur = asn1_ssb_mtc.dur.to_number(); - - return ssb_mtc; -} +rrc_ssb_mtc asn1_to_ssb_mtc(const asn1::rrc_nr::ssb_mtc_s& asn1_ssb_mtc); /// \brief Converts type \c subcarrier_spacing to an RRC NR ASN.1 type. -/// \param sc_spacing subcarrier spacing object. +/// \param[in] sc_spacing subcarrier spacing object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline subcarrier_spacing rrc_asn1_to_subcarrier_spacing(const asn1::rrc_nr::subcarrier_spacing_e asn1_sc_spacing) -{ - subcarrier_spacing sc_spacing; - - switch (asn1_sc_spacing) { - case asn1::rrc_nr::subcarrier_spacing_opts::options::khz15: - sc_spacing = srsran::subcarrier_spacing::kHz15; - break; - case asn1::rrc_nr::subcarrier_spacing_opts::options::khz30: - sc_spacing = srsran::subcarrier_spacing::kHz30; - break; - case asn1::rrc_nr::subcarrier_spacing_opts::options::khz60: - sc_spacing = srsran::subcarrier_spacing::kHz60; - break; - case asn1::rrc_nr::subcarrier_spacing_opts::options::khz120: - sc_spacing = srsran::subcarrier_spacing::kHz120; - break; - case asn1::rrc_nr::subcarrier_spacing_opts::options::khz240: - sc_spacing = srsran::subcarrier_spacing::kHz240; - break; - default: - sc_spacing = srsran::subcarrier_spacing::invalid; - } - - return sc_spacing; -} - -inline rrc_meas_timing asn1_to_meas_timing(const asn1::rrc_nr::meas_timing_s& asn1_meas_timing) -{ - rrc_meas_timing meas_timing; - - // freq and timing - if (asn1_meas_timing.freq_and_timing_present) { - rrc_meas_timing::rrc_freq_and_timing_ freq_and_timing; - - // carrier freq - freq_and_timing.carrier_freq = asn1_meas_timing.freq_and_timing.carrier_freq; - - // subcarrier spacing - freq_and_timing.ssb_subcarrier_spacing = - rrc_asn1_to_subcarrier_spacing(asn1_meas_timing.freq_and_timing.ssb_subcarrier_spacing); - - // ssb mtc - freq_and_timing.ssb_meas_timing_cfg = asn1_to_ssb_mtc(asn1_meas_timing.freq_and_timing.ssb_meas_timing_cfg); +subcarrier_spacing rrc_asn1_to_subcarrier_spacing(asn1::rrc_nr::subcarrier_spacing_e asn1_sc_spacing); - // ss rssi meas - if (asn1_meas_timing.freq_and_timing.ss_rssi_meas_present) { - rrc_ss_rssi_meas ss_rssi_meas; - - // meas slots - ss_rssi_meas.meas_slots = asn1_meas_timing.freq_and_timing.ss_rssi_meas.meas_slots.to_number(); - // end symbol - ss_rssi_meas.end_symbol = asn1_meas_timing.freq_and_timing.ss_rssi_meas.end_symbol; - - freq_and_timing.ss_rssi_meas = ss_rssi_meas; - } - - meas_timing.freq_and_timing = freq_and_timing; - } - - return meas_timing; -} +/// \brief Converts type \c asn1::rrc_nr::meas_timing_s to common type. +/// \param[in] asn1_meas_timing asn1 meas timing object. +/// \return The common object where the result of the conversion is stored. +rrc_meas_timing asn1_to_meas_timing(const asn1::rrc_nr::meas_timing_s& asn1_meas_timing); /// \brief Converts type \c subcarrier_spacing to an RRC NR ASN.1 type. -/// \param sc_spacing subcarrier spacing object. +/// \param[in] sc_spacing subcarrier spacing object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline asn1::rrc_nr::subcarrier_spacing_e subcarrier_spacing_to_rrc_asn1(subcarrier_spacing sc_spacing) -{ - asn1::rrc_nr::subcarrier_spacing_e asn1_sc_spacing; - - switch (sc_spacing) { - case srsran::subcarrier_spacing::kHz15: - asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz15; - break; - case srsran::subcarrier_spacing::kHz30: - asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz30; - break; - case srsran::subcarrier_spacing::kHz60: - asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz60; - break; - case srsran::subcarrier_spacing::kHz120: - asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz120; - break; - case srsran::subcarrier_spacing::kHz240: - asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::khz240; - break; - default: - asn1_sc_spacing = asn1::rrc_nr::subcarrier_spacing_opts::options::nulltype; - } - - return asn1_sc_spacing; -} +asn1::rrc_nr::subcarrier_spacing_e subcarrier_spacing_to_rrc_asn1(subcarrier_spacing sc_spacing); -/// \brief Converts type \c ssb_mtc to an RRC NR ASN.1 type. -/// \param ssb_mtc ssb mtc object. +/// \brief Converts type \c rrc_ssb_mtc to an RRC NR ASN.1 type. +/// \param[in] ssb_mtc ssb mtc object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline asn1::rrc_nr::ssb_mtc_s ssb_mtc_to_rrc_asn1(rrc_ssb_mtc ssb_mtc) -{ - asn1::rrc_nr::ssb_mtc_s asn1_ssb_mtc; - - switch ((uint8_t)ssb_mtc.periodicity_and_offset.periodicity) { - case 5: - asn1_ssb_mtc.periodicity_and_offset.set_sf5(); - asn1_ssb_mtc.periodicity_and_offset.sf5() = ssb_mtc.periodicity_and_offset.offset; - break; - case 10: - asn1_ssb_mtc.periodicity_and_offset.set_sf10(); - asn1_ssb_mtc.periodicity_and_offset.sf10() = ssb_mtc.periodicity_and_offset.offset; - break; - case 20: - asn1_ssb_mtc.periodicity_and_offset.set_sf20(); - asn1_ssb_mtc.periodicity_and_offset.sf20() = ssb_mtc.periodicity_and_offset.offset; - break; - case 40: - asn1_ssb_mtc.periodicity_and_offset.set_sf40(); - asn1_ssb_mtc.periodicity_and_offset.sf40() = ssb_mtc.periodicity_and_offset.offset; - break; - case 80: - asn1_ssb_mtc.periodicity_and_offset.set_sf80(); - asn1_ssb_mtc.periodicity_and_offset.sf80() = ssb_mtc.periodicity_and_offset.offset; - break; - case 160: - asn1_ssb_mtc.periodicity_and_offset.set_sf160(); - asn1_ssb_mtc.periodicity_and_offset.sf160() = ssb_mtc.periodicity_and_offset.offset; - break; - default: - report_fatal_error("Cannot convert SSB MTC to ASN.1 type"); - } - - asn1::number_to_enum(asn1_ssb_mtc.dur, ssb_mtc.dur); - - return asn1_ssb_mtc; -} - -inline asn1::rrc_nr::ssb_cfg_mob_s ssb_cfg_mob_to_rrc_asn1(const rrc_ssb_cfg_mob& ssb_cfg_mob) -{ - asn1::rrc_nr::ssb_cfg_mob_s asn1_ssb_cfg_mob; - - // ssb to measure - if (ssb_cfg_mob.ssb_to_measure.has_value()) { - const auto& ssb_to_measure = ssb_cfg_mob.ssb_to_measure.value(); - asn1_ssb_cfg_mob.ssb_to_measure_present = true; - // release - if (ssb_to_measure.is_release) { - asn1_ssb_cfg_mob.ssb_to_measure.set_release(); - } else if (ssb_to_measure.setup.has_value()) { - // setup - asn1_ssb_cfg_mob.ssb_to_measure.set_setup(); - // short bitmap - if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::short_bitmap) { - asn1_ssb_cfg_mob.ssb_to_measure.setup().set_short_bitmap(); - asn1_ssb_cfg_mob.ssb_to_measure.setup().short_bitmap().from_number( - static_cast(ssb_to_measure.setup.value().bitmap)); - } - // medium bitmap - if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::medium_bitmap) { - asn1_ssb_cfg_mob.ssb_to_measure.setup().set_medium_bitmap(); - asn1_ssb_cfg_mob.ssb_to_measure.setup().medium_bitmap().from_number( - static_cast(ssb_to_measure.setup.value().bitmap)); - } - // long bitmap - if (ssb_to_measure.setup.value().type == rrc_ssb_to_measure::bitmap_type_t::long_bitmap) { - asn1_ssb_cfg_mob.ssb_to_measure.setup().set_long_bitmap(); - asn1_ssb_cfg_mob.ssb_to_measure.setup().long_bitmap().from_number(ssb_to_measure.setup.value().bitmap); - } - } - } - - // derive ssb idx from cell - asn1_ssb_cfg_mob.derive_ssb_idx_from_cell = ssb_cfg_mob.derive_ssb_idx_from_cell; - - // ss rssi meas - if (ssb_cfg_mob.ss_rssi_meas.has_value()) { - const auto& ss_rssi_meas = ssb_cfg_mob.ss_rssi_meas.value(); - asn1_ssb_cfg_mob.ss_rssi_meas_present = true; - asn1_ssb_cfg_mob.ss_rssi_meas.meas_slots.from_number(ss_rssi_meas.meas_slots); - asn1_ssb_cfg_mob.ss_rssi_meas.end_symbol = ss_rssi_meas.end_symbol; - } - - return asn1_ssb_cfg_mob; -} - -inline asn1::setup_release_c -csi_res_cfg_mob_to_rrc_asn1(const rrc_csi_rs_res_cfg_mob_setup_release& csi_rs_res_cfg_mob) -{ - asn1::setup_release_c asn1_csi_rs_res_cfg_mob; - - if (csi_rs_res_cfg_mob.is_release) { - asn1_csi_rs_res_cfg_mob.set_release(); - } else if (csi_rs_res_cfg_mob.setup.has_value()) { - asn1_csi_rs_res_cfg_mob.set_setup(); - // subcarrier spacing - asn1_csi_rs_res_cfg_mob.setup().subcarrier_spacing = - subcarrier_spacing_to_rrc_asn1(csi_rs_res_cfg_mob.setup.value().sc_spacing); - // csi rs cell list mob - for (const auto& csi_rs_cell_mob : csi_rs_res_cfg_mob.setup.value().csi_rs_cell_list_mob) { - asn1::rrc_nr::csi_rs_cell_mob_s asn1_csi_rs_cell_mob; - - // cell id - asn1_csi_rs_cell_mob.cell_id = csi_rs_cell_mob.cell_id; - // csi rs meas bw - asn1::number_to_enum(asn1_csi_rs_cell_mob.csi_rs_meas_bw.nrof_prbs, csi_rs_cell_mob.csi_rs_meas_bw.nrof_prbs); - asn1_csi_rs_cell_mob.csi_rs_meas_bw.start_prb = csi_rs_cell_mob.csi_rs_meas_bw.start_prb; - // density - if (csi_rs_cell_mob.density.has_value()) { - asn1_csi_rs_cell_mob.density_present = true; - asn1::number_to_enum(asn1_csi_rs_cell_mob.density, csi_rs_cell_mob.density.value()); - } - // csi rs res list mob - for (const auto& csi_rs_res_mob : csi_rs_cell_mob.csi_rs_res_list_mob) { - asn1::rrc_nr::csi_rs_res_mob_s asn1_csi_rs_res_mob; - - // csi rs idx - asn1_csi_rs_res_mob.csi_rs_idx = csi_rs_res_mob.csi_rs_idx; - // slot cfg - if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms4) { - asn1_csi_rs_res_mob.slot_cfg.set_ms4() = static_cast(csi_rs_res_mob.slot_cfg.offset); - } - if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms5) { - asn1_csi_rs_res_mob.slot_cfg.set_ms5() = static_cast(csi_rs_res_mob.slot_cfg.offset); - } - if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms10) { - asn1_csi_rs_res_mob.slot_cfg.set_ms10() = static_cast(csi_rs_res_mob.slot_cfg.offset); - } - if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms20) { - asn1_csi_rs_res_mob.slot_cfg.set_ms20() = static_cast(csi_rs_res_mob.slot_cfg.offset); - } - if (csi_rs_res_mob.slot_cfg.period == rrc_slot_cfg::period_t::ms40) { - asn1_csi_rs_res_mob.slot_cfg.set_ms40() = csi_rs_res_mob.slot_cfg.offset; - } - // associated ssb - if (csi_rs_res_mob.associated_ssb.has_value()) { - asn1_csi_rs_res_mob.associated_ssb_present = true; - asn1_csi_rs_res_mob.associated_ssb.ssb_idx = csi_rs_res_mob.associated_ssb.value().ssb_idx; - asn1_csi_rs_res_mob.associated_ssb.is_quasi_colocated = - csi_rs_res_mob.associated_ssb.value().is_quasi_colocated; - } - // freq domain alloc - if (std::holds_alternative(csi_rs_res_mob.freq_domain_alloc)) { - asn1_csi_rs_res_mob.freq_domain_alloc.set_row1(); - asn1_csi_rs_res_mob.freq_domain_alloc.row1().from_number( - std::get(csi_rs_res_mob.freq_domain_alloc)); - } - if (std::holds_alternative(csi_rs_res_mob.freq_domain_alloc)) { - asn1_csi_rs_res_mob.freq_domain_alloc.set_row2(); - asn1_csi_rs_res_mob.freq_domain_alloc.row2().from_number( - std::get(csi_rs_res_mob.freq_domain_alloc)); - } - // first ofdm symbol in time domain - asn1_csi_rs_res_mob.first_ofdm_symbol_in_time_domain = csi_rs_res_mob.first_ofdm_symbol_in_time_domain; - // seq generation cfg - asn1_csi_rs_res_mob.seq_generation_cfg = csi_rs_res_mob.seq_generation_cfg; - - asn1_csi_rs_cell_mob.csi_rs_res_list_mob.push_back(asn1_csi_rs_res_mob); - } - - asn1_csi_rs_res_cfg_mob.setup().csi_rs_cell_list_mob.push_back(asn1_csi_rs_cell_mob); - } - } else { - // error - report_fatal_error("Cannot convert CSI RS res cfg mob to ASN.1 type"); - } - - return asn1_csi_rs_res_cfg_mob; -} - -inline asn1::rrc_nr::thres_nr_s thres_nr_to_rrc_asn1(const rrc_thres_nr& thres_nr) -{ - asn1::rrc_nr::thres_nr_s asn1_thres_nr; - - // thres rsrp - if (thres_nr.thres_rsrp.has_value()) { - asn1_thres_nr.thres_rsrp_present = true; - asn1_thres_nr.thres_rsrp = thres_nr.thres_rsrp.value(); - } - - // thres rsrq - if (thres_nr.thres_rsrq.has_value()) { - asn1_thres_nr.thres_rsrq_present = true; - asn1_thres_nr.thres_rsrq = thres_nr.thres_rsrq.value(); - } - - // thres sinr - if (thres_nr.thres_sinr.has_value()) { - asn1_thres_nr.thres_sinr_present = true; - asn1_thres_nr.thres_sinr = thres_nr.thres_sinr.value(); - } - - return asn1_thres_nr; -} - -inline asn1::rrc_nr::q_offset_range_list_s -q_offset_range_list_to_rrc_asn1(const rrc_q_offset_range_list& q_offset_range_list) -{ - asn1::rrc_nr::q_offset_range_list_s asn1_q_offset_range_list; - - // rsrp offset ssb - if (q_offset_range_list.rsrp_offset_ssb.has_value()) { - asn1_q_offset_range_list.rsrp_offset_ssb_present = true; - asn1::number_to_enum(asn1_q_offset_range_list.rsrp_offset_ssb, q_offset_range_list.rsrp_offset_ssb.value()); - } - // rsrq offset ssb - if (q_offset_range_list.rsrq_offset_ssb.has_value()) { - asn1_q_offset_range_list.rsrq_offset_ssb_present = true; - asn1::number_to_enum(asn1_q_offset_range_list.rsrq_offset_ssb, q_offset_range_list.rsrq_offset_ssb.value()); - } - // sinr offset ssb - if (q_offset_range_list.sinr_offset_ssb.has_value()) { - asn1_q_offset_range_list.sinr_offset_ssb_present = true; - asn1::number_to_enum(asn1_q_offset_range_list.sinr_offset_ssb, q_offset_range_list.sinr_offset_ssb.value()); - } - // rsrp offset csi_rs - if (q_offset_range_list.rsrp_offset_csi_rs.has_value()) { - asn1_q_offset_range_list.rsrp_offset_csi_rs_present = true; - asn1::number_to_enum(asn1_q_offset_range_list.rsrp_offset_csi_rs, q_offset_range_list.rsrp_offset_csi_rs.value()); - } - // rsrq offset csi_rs - if (q_offset_range_list.rsrq_offset_csi_rs.has_value()) { - asn1_q_offset_range_list.rsrq_offset_csi_rs_present = true; - asn1::number_to_enum(asn1_q_offset_range_list.rsrq_offset_csi_rs, q_offset_range_list.rsrq_offset_csi_rs.value()); - } - // sinr offset csi_rs - if (q_offset_range_list.sinr_offset_csi_rs.has_value()) { - asn1_q_offset_range_list.sinr_offset_csi_rs_present = true; - asn1::number_to_enum(asn1_q_offset_range_list.sinr_offset_csi_rs, q_offset_range_list.sinr_offset_csi_rs.value()); - } - - return asn1_q_offset_range_list; -} - -inline asn1::rrc_nr::meas_obj_nr_s meas_obj_nr_to_rrc_asn1(const rrc_meas_obj_nr& meas_obj_nr) -{ - asn1::rrc_nr::meas_obj_nr_s asn1_meas_obj_nr; - - // ssb freq - if (meas_obj_nr.ssb_freq.has_value()) { - asn1_meas_obj_nr.ssb_freq_present = true; - asn1_meas_obj_nr.ssb_freq = meas_obj_nr.ssb_freq.value(); - } - - // ssb subcarrier spacing - if (meas_obj_nr.ssb_subcarrier_spacing.has_value()) { - asn1_meas_obj_nr.ssb_subcarrier_spacing_present = true; - asn1_meas_obj_nr.ssb_subcarrier_spacing = - subcarrier_spacing_to_rrc_asn1(meas_obj_nr.ssb_subcarrier_spacing.value()); - } - - // smtc1 - if (meas_obj_nr.smtc1.has_value()) { - asn1_meas_obj_nr.smtc1_present = true; - asn1_meas_obj_nr.smtc1 = ssb_mtc_to_rrc_asn1(meas_obj_nr.smtc1.value()); - } +asn1::rrc_nr::ssb_mtc_s ssb_mtc_to_rrc_asn1(rrc_ssb_mtc ssb_mtc); - // smtc2 - if (meas_obj_nr.smtc2.has_value()) { - asn1_meas_obj_nr.smtc2_present = true; - // pci list - for (const auto& pci : meas_obj_nr.smtc2.value().pci_list) { - asn1_meas_obj_nr.smtc2.pci_list.push_back(pci); - } - // periodicity - asn1::number_to_enum(asn1_meas_obj_nr.smtc2.periodicity, meas_obj_nr.smtc2.value().periodicity); - } - - // ref freq csi rs - if (meas_obj_nr.ref_freq_csi_rs.has_value()) { - asn1_meas_obj_nr.ref_freq_csi_rs_present = true; - asn1_meas_obj_nr.ref_freq_csi_rs = meas_obj_nr.ref_freq_csi_rs.value(); - } - - // ref sig cfg - // ssb cfg mob - if (meas_obj_nr.ref_sig_cfg.ssb_cfg_mob.has_value()) { - asn1_meas_obj_nr.ref_sig_cfg.ssb_cfg_mob_present = true; - asn1_meas_obj_nr.ref_sig_cfg.ssb_cfg_mob = ssb_cfg_mob_to_rrc_asn1(meas_obj_nr.ref_sig_cfg.ssb_cfg_mob.value()); - } - // csi rs res cfg mob - if (meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob.has_value()) { - asn1_meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob_present = true; - asn1_meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob = - csi_res_cfg_mob_to_rrc_asn1(meas_obj_nr.ref_sig_cfg.csi_rs_res_cfg_mob.value()); - } - - // abs thresh ss blocks consolidation - if (meas_obj_nr.abs_thresh_ss_blocks_consolidation.has_value()) { - asn1_meas_obj_nr.abs_thresh_ss_blocks_consolidation_present = true; - asn1_meas_obj_nr.abs_thresh_ss_blocks_consolidation = - thres_nr_to_rrc_asn1(meas_obj_nr.abs_thresh_ss_blocks_consolidation.value()); - } - - // abs thresh csi rs consolidation - if (meas_obj_nr.abs_thresh_csi_rs_consolidation.has_value()) { - asn1_meas_obj_nr.abs_thresh_csi_rs_consolidation_present = true; - asn1_meas_obj_nr.abs_thresh_csi_rs_consolidation = - thres_nr_to_rrc_asn1(meas_obj_nr.abs_thresh_csi_rs_consolidation.value()); - } - - // nrof ss blocks to average - if (meas_obj_nr.nrof_ss_blocks_to_average.has_value()) { - asn1_meas_obj_nr.nrof_ss_blocks_to_average_present = true; - asn1_meas_obj_nr.nrof_ss_blocks_to_average = meas_obj_nr.nrof_ss_blocks_to_average.value(); - } - - // nrof csi rs res to average - if (meas_obj_nr.nrof_csi_rs_res_to_average.has_value()) { - asn1_meas_obj_nr.nrof_csi_rs_res_to_average_present = true; - asn1_meas_obj_nr.nrof_csi_rs_res_to_average = meas_obj_nr.nrof_csi_rs_res_to_average.value(); - } - - // quant cfg idx - asn1_meas_obj_nr.quant_cfg_idx = meas_obj_nr.quant_cfg_idx; - - // offset mo - asn1_meas_obj_nr.offset_mo = q_offset_range_list_to_rrc_asn1(meas_obj_nr.offset_mo); - - // cells to rem list - srsran_assert(meas_obj_nr.cells_to_rem_list.size() <= 32, - "Too many cells to remove ({}>{}).", - meas_obj_nr.cells_to_rem_list.size(), - 32); - for (const auto& cell_to_rem : meas_obj_nr.cells_to_rem_list) { - asn1_meas_obj_nr.cells_to_rem_list.push_back(cell_to_rem); - } - - // cells to add mod list - for (const auto& cell_to_add_mod : meas_obj_nr.cells_to_add_mod_list) { - asn1::rrc_nr::cells_to_add_mod_s asn1_cells_to_add_mod; - - asn1_cells_to_add_mod.pci = cell_to_add_mod.pci; - asn1_cells_to_add_mod.cell_individual_offset = - q_offset_range_list_to_rrc_asn1(cell_to_add_mod.cell_individual_offset); - - asn1_meas_obj_nr.cells_to_add_mod_list.push_back(asn1_cells_to_add_mod); - } - - // excluded cells to rem list - srsran_assert(meas_obj_nr.excluded_cells_to_rem_list.size() <= 8, - "Too many excluded cells to remove ({}>{}).", - meas_obj_nr.excluded_cells_to_rem_list.size(), - 8); - for (const auto& excluded_cell : meas_obj_nr.excluded_cells_to_rem_list) { - asn1_meas_obj_nr.excluded_cells_to_rem_list.push_back(excluded_cell); - } - - // excluded cells to add mod list - for (const auto& excluded_cell : meas_obj_nr.excluded_cells_to_add_mod_list) { - asn1::rrc_nr::pci_range_elem_s asn1_pci_range_elem; - asn1_pci_range_elem.pci_range_idx = excluded_cell.pci_range_idx; - - asn1_pci_range_elem.pci_range.start = excluded_cell.pci_range.start; - if (excluded_cell.pci_range.range.has_value()) { - asn1_pci_range_elem.pci_range.range_present = true; - asn1::number_to_enum(asn1_pci_range_elem.pci_range.range, excluded_cell.pci_range.range.value()); - } - asn1_meas_obj_nr.excluded_cells_to_add_mod_list.push_back(asn1_pci_range_elem); - } - - // allowed cells to rem list - srsran_assert(meas_obj_nr.allowed_cells_to_rem_list.size() <= 8, - "Too many allowed cells to remove ({}>{}).", - meas_obj_nr.allowed_cells_to_rem_list.size(), - 8); - for (const auto& allowed_cell : meas_obj_nr.allowed_cells_to_rem_list) { - asn1_meas_obj_nr.allowed_cells_to_rem_list.push_back(allowed_cell); - } +/// \brief Converty type \c rrc_ssb_cfg_mob to an RRC NR ASN.1 type. +/// \param[in] ssb_cfg_mob ssb config mobility object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::ssb_cfg_mob_s ssb_cfg_mob_to_rrc_asn1(const rrc_ssb_cfg_mob& ssb_cfg_mob); - // allowed cells to add mod list - for (const auto& allowed_cell : meas_obj_nr.allowed_cells_to_add_mod_list) { - asn1::rrc_nr::pci_range_elem_s asn1_pci_range_elem; - asn1_pci_range_elem.pci_range_idx = allowed_cell.pci_range_idx; +/// \brief Convert type \c rrc_csi_rs_res_cfg_mob_setup_release to an RRC NR ASN.1 type. +/// \param[in] csi_rs_res_cfg_mob csi rs res config mobility object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::setup_release_c +csi_res_cfg_mob_to_rrc_asn1(const rrc_csi_rs_res_cfg_mob_setup_release& csi_rs_res_cfg_mob); - asn1_pci_range_elem.pci_range.start = allowed_cell.pci_range.start; - if (allowed_cell.pci_range.range.has_value()) { - asn1_pci_range_elem.pci_range.range_present = true; - asn1::number_to_enum(asn1_pci_range_elem.pci_range.range, allowed_cell.pci_range.range.value()); - } - asn1_meas_obj_nr.allowed_cells_to_add_mod_list.push_back(asn1_pci_range_elem); - } +/// \brief Convert type \c rrc_thres_nr to an RRC NR ASN.1 type. +/// \param[in] thres_nr threshold object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::thres_nr_s thres_nr_to_rrc_asn1(const rrc_thres_nr& thres_nr); - // group 0 - // freq band ind nr - if (meas_obj_nr.freq_band_ind_nr.has_value()) { - asn1_meas_obj_nr.ext = true; - asn1_meas_obj_nr.freq_band_ind_nr_present = true; - asn1_meas_obj_nr.freq_band_ind_nr = meas_obj_nr.freq_band_ind_nr.value(); - } - // meas cycle scell - if (meas_obj_nr.meas_cycle_scell.has_value()) { - asn1_meas_obj_nr.ext = true; - asn1_meas_obj_nr.meas_cycle_scell_present = true; - asn1::number_to_enum(asn1_meas_obj_nr.meas_cycle_scell, meas_obj_nr.meas_cycle_scell.value()); - } +/// \brief Convert type \c rrc_q_offset_range_list to an RRC NR ASN.1 type. +/// \param[in] q_offset_range_list q offset range list object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::q_offset_range_list_s q_offset_range_list_to_rrc_asn1(const rrc_q_offset_range_list& q_offset_range_list); - return asn1_meas_obj_nr; -} +/// \brief Convert type \c rrc_meas_obj_nr to an RRC NR ASN.1 type. +/// \param[in] meas_obj_nr meas object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::meas_obj_nr_s meas_obj_nr_to_rrc_asn1(const rrc_meas_obj_nr& meas_obj_nr); +/// \brief Convert type \c rrc_srs_periodicity_and_offset to an RRC NR ASN.1 type. +/// \param[out] asn1_srs_period_and_offset The RRC NR ASN.1 object where the result of the conversion is stored. +/// \param[in] srs_period_and_offset common type srs periodicity and offset object. template void srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_periodicity_and_offset& asn1_srs_period_and_offset, - const rrc_srs_periodicity_and_offset& srs_period_and_offset) -{ - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms1) { - asn1_srs_period_and_offset.set_sl1(); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms2) { - asn1_srs_period_and_offset.set_sl2() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms4) { - asn1_srs_period_and_offset.set_sl4() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms5) { - asn1_srs_period_and_offset.set_sl5() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms8) { - asn1_srs_period_and_offset.set_sl8() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms10) { - asn1_srs_period_and_offset.set_sl10() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms16) { - asn1_srs_period_and_offset.set_sl16() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms20) { - asn1_srs_period_and_offset.set_sl20() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms32) { - asn1_srs_period_and_offset.set_sl32() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms40) { - asn1_srs_period_and_offset.set_sl40() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms64) { - asn1_srs_period_and_offset.set_sl64() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms80) { - asn1_srs_period_and_offset.set_sl80() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms160) { - asn1_srs_period_and_offset.set_sl160() = static_cast(srs_period_and_offset.offset); - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms320) { - asn1_srs_period_and_offset.set_sl320() = srs_period_and_offset.offset; - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms640) { - asn1_srs_period_and_offset.set_sl640() = srs_period_and_offset.offset; - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms1280) { - asn1_srs_period_and_offset.set_sl1280() = srs_period_and_offset.offset; - } - if (srs_period_and_offset.period == rrc_srs_periodicity_and_offset::period_t::ms2560) { - asn1_srs_period_and_offset.set_sl2560() = srs_period_and_offset.offset; - } -}; - -inline asn1::rrc_nr::srs_res_s srs_res_to_rrc_asn1(const rrc_srs_res& srs_res) -{ - asn1::rrc_nr::srs_res_s asn1_srs_res; - - // srs res id - asn1_srs_res.srs_res_id = srs_res.srs_res_id; - - // nrof srs ports - asn1::number_to_enum(asn1_srs_res.nrof_srs_ports, srs_res.nrof_srs_ports); - - // ptrs port idx - if (srs_res.ptrs_port_idx.has_value()) { - asn1_srs_res.ptrs_port_idx_present = true; - asn1::number_to_enum(asn1_srs_res.ptrs_port_idx, srs_res.ptrs_port_idx.value()); - } - - // tx comb - if (const auto* n2 = std::get_if(&srs_res.tx_comb); n2 != nullptr) { - asn1_srs_res.tx_comb.set_n2(); - asn1_srs_res.tx_comb.n2().comb_offset_n2 = n2->comb_offset_n2; - asn1_srs_res.tx_comb.n2().cyclic_shift_n2 = n2->cyclic_shift_n2; - } - - if (const auto* n4 = std::get_if(&srs_res.tx_comb); n4 != nullptr) { - asn1_srs_res.tx_comb.set_n4(); - asn1_srs_res.tx_comb.n4().comb_offset_n4 = n4->comb_offset_n4; - asn1_srs_res.tx_comb.n4().cyclic_shift_n4 = n4->cyclic_shift_n4; - } - - // res map - asn1_srs_res.res_map.start_position = srs_res.res_map.start_position; - asn1::number_to_enum(asn1_srs_res.res_map.nrof_symbols, srs_res.res_map.nrof_symbols); - asn1::number_to_enum(asn1_srs_res.res_map.repeat_factor, srs_res.res_map.repeat_factor); - - // freq domain position - asn1_srs_res.freq_domain_position = srs_res.freq_domain_position; - - // freq domain shift - asn1_srs_res.freq_domain_shift = srs_res.freq_domain_shift; - - // freq hop - asn1_srs_res.freq_hop.c_srs = srs_res.freq_hop.c_srs; - asn1_srs_res.freq_hop.b_srs = srs_res.freq_hop.b_srs; - asn1_srs_res.freq_hop.b_hop = srs_res.freq_hop.b_hop; - - // group or seq hop - asn1::string_to_enum(asn1_srs_res.group_or_seq_hop, srs_res.group_or_seq_hop); - - // res type - if (std::holds_alternative(srs_res.res_type)) { - asn1_srs_res.res_type.set_aperiodic(); - } - if (std::holds_alternative(srs_res.res_type)) { - asn1_srs_res.res_type.set_semi_persistent(); - srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_res.res_type.semi_persistent().periodicity_and_offset_sp, - std::get(srs_res.res_type).periodicity_and_offset_sp_p); - } - if (std::holds_alternative(srs_res.res_type)) { - asn1_srs_res.res_type.set_periodic(); - srs_periodicity_and_offset_to_rrc_asn1(asn1_srs_res.res_type.periodic().periodicity_and_offset_p, - std::get(srs_res.res_type).periodicity_and_offset_sp_p); - } - // seq id - asn1_srs_res.seq_id = srs_res.seq_id; - - // spatial relation info - if (srs_res.spatial_relation_info.has_value()) { - // serving cell id - if (srs_res.spatial_relation_info.value().serving_cell_id.has_value()) { - asn1_srs_res.spatial_relation_info.serving_cell_id_present = true; - asn1_srs_res.spatial_relation_info.serving_cell_id = - srs_res.spatial_relation_info.value().serving_cell_id.value(); - } - // ref sig - if (std::holds_alternative( - srs_res.spatial_relation_info.value().ref_sig)) { - asn1_srs_res.spatial_relation_info.ref_sig.set_ssb_idx() = static_cast( - std::get(srs_res.spatial_relation_info.value().ref_sig)); - } - if (std::holds_alternative( - srs_res.spatial_relation_info.value().ref_sig)) { - asn1_srs_res.spatial_relation_info.ref_sig.set_csi_rs_idx() = static_cast( - std::get(srs_res.spatial_relation_info.value().ref_sig)); - } - if (std::holds_alternative(srs_res.spatial_relation_info.value().ref_sig)) { - asn1_srs_res.spatial_relation_info.ref_sig.set_srs(); - asn1_srs_res.spatial_relation_info.ref_sig.srs().res_id = - std::get(srs_res.spatial_relation_info.value().ref_sig).res_id; - asn1_srs_res.spatial_relation_info.ref_sig.srs().ul_bwp = - std::get(srs_res.spatial_relation_info.value().ref_sig).ul_bwp; - } - } - - return asn1_srs_res; -} - -inline asn1::rrc_nr::meas_obj_to_add_mod_s -meas_obj_to_add_mod_to_rrc_asn1(const rrc_meas_obj_to_add_mod& meas_obj_to_add_mod) -{ - asn1::rrc_nr::meas_obj_to_add_mod_s asn1_meas_obj_to_add_mod; - - // meas obj id - asn1_meas_obj_to_add_mod.meas_obj_id = meas_obj_id_to_uint(meas_obj_to_add_mod.meas_obj_id); - - // meas obj - if (meas_obj_to_add_mod.meas_obj_nr.has_value()) { - // meas obj nr - asn1_meas_obj_to_add_mod.meas_obj.set_meas_obj_nr(); - asn1_meas_obj_to_add_mod.meas_obj.meas_obj_nr() = meas_obj_nr_to_rrc_asn1(meas_obj_to_add_mod.meas_obj_nr.value()); - } - - return asn1_meas_obj_to_add_mod; -} - -inline asn1::rrc_nr::meas_report_quant_s meas_report_quant_to_rrc_asn1(const rrc_meas_report_quant& meas_report_quant) -{ - asn1::rrc_nr::meas_report_quant_s asn1_meas_report_quant; - - asn1_meas_report_quant.rsrp = meas_report_quant.rsrp; - asn1_meas_report_quant.rsrq = meas_report_quant.rsrq; - asn1_meas_report_quant.sinr = meas_report_quant.sinr; - - return asn1_meas_report_quant; -} - -inline asn1::rrc_nr::nr_rs_type_e rrc_nr_rs_type_to_asn1(const rrc_nr_rs_type& rs_type) -{ - asn1::rrc_nr::nr_rs_type_e asn1_rs_type; + const rrc_srs_periodicity_and_offset& srs_period_and_offset); - switch (rs_type) { - case rrc_nr_rs_type::ssb: - asn1_rs_type = asn1::rrc_nr::nr_rs_type_opts::options::ssb; - break; - case rrc_nr_rs_type::csi_rs: - asn1_rs_type = asn1::rrc_nr::nr_rs_type_opts::options::csi_rs; - break; - } - - return asn1_rs_type; -} - -inline asn1::rrc_nr::report_interv_e report_interval_to_asn1(uint32_t report_interval) -{ - asn1::rrc_nr::report_interv_e asn1_report_interval; +/// \brief Convert type \c rrc_srs_res to an RRC NR ASN.1 type. +/// \param[in] srs_res srs res object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::srs_res_s srs_res_to_rrc_asn1(const rrc_srs_res& srs_res); - return asn1_report_interval; -} +/// \brief Convert type \c rrc_meas_obj_to_add_mod to an RRC NR ASN.1 type. +/// \param[in] meas_obj_to_add_mod measurement object to add mod object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::meas_obj_to_add_mod_s meas_obj_to_add_mod_to_rrc_asn1(const rrc_meas_obj_to_add_mod& meas_obj_to_add_mod); -inline asn1::rrc_nr::periodical_report_cfg_s -periodical_report_cfg_to_rrc_asn1(const rrc_periodical_report_cfg& periodical_report_cfg) -{ - asn1::rrc_nr::periodical_report_cfg_s asn1_periodical_report_cfg; +/// \brief Convert type \c rrc_meas_report_quant to an RRC NR ASN.1 type. +/// \param[in] meas_report_quant measurement report quantity object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::meas_report_quant_s meas_report_quant_to_rrc_asn1(const rrc_meas_report_quant& meas_report_quant); - // rs type - asn1_periodical_report_cfg.rs_type = rrc_nr_rs_type_to_asn1(periodical_report_cfg.rs_type); - // report interv. This struct mixes ms and minutes so we need to convert the value before conversion - if (periodical_report_cfg.report_interv < 60000) { - asn1::number_to_enum(asn1_periodical_report_cfg.report_interv, periodical_report_cfg.report_interv); - } else { - asn1::number_to_enum(asn1_periodical_report_cfg.report_interv, periodical_report_cfg.report_interv / 60000); - } +/// \brief Convert type \c rrc_nr_rs_type to an RRC NR ASN.1 type. +/// \param[in] rs_type rs type object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::nr_rs_type_e rrc_nr_rs_type_to_asn1(const rrc_nr_rs_type& rs_type); - // report amount - asn1::number_to_enum(asn1_periodical_report_cfg.report_amount, periodical_report_cfg.report_amount); - // report quant cell - asn1_periodical_report_cfg.report_quant_cell = meas_report_quant_to_rrc_asn1(periodical_report_cfg.report_quant_cell); - // max report cells - asn1_periodical_report_cfg.max_report_cells = periodical_report_cfg.max_report_cells; - // report quant rx idxes - if (periodical_report_cfg.report_quant_rs_idxes.has_value()) { - asn1_periodical_report_cfg.report_quant_rs_idxes_present = true; - asn1_periodical_report_cfg.report_quant_rs_idxes = - meas_report_quant_to_rrc_asn1(periodical_report_cfg.report_quant_rs_idxes.value()); - } - // max nrof rs idxes to report - if (periodical_report_cfg.max_nrof_rs_idxes_to_report.has_value()) { - asn1_periodical_report_cfg.max_nrof_rs_idxes_to_report_present = true; - asn1_periodical_report_cfg.max_nrof_rs_idxes_to_report = periodical_report_cfg.max_nrof_rs_idxes_to_report.value(); - } - // include beam meass - asn1_periodical_report_cfg.include_beam_meass = periodical_report_cfg.include_beam_meass; - // use allowed cell list - asn1_periodical_report_cfg.use_allowed_cell_list = periodical_report_cfg.use_allowed_cell_list; +/// \brief Convert type \c uint32_t to an RRC NR ASN.1 type. +/// \param[in] report_interval report interval. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::report_interv_e report_interval_to_asn1(uint32_t report_interval); - return asn1_periodical_report_cfg; -} +/// \brief Convert type \c rrc_periodical_report_cfg to an RRC NR ASN.1 type. +/// \param[in] periodical_report_cfg periodical report config object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::periodical_report_cfg_s +periodical_report_cfg_to_rrc_asn1(const rrc_periodical_report_cfg& periodical_report_cfg); +/// \brief Convert type \c rrc_meas_trigger_quant to an RRC NR ASN.1 type. +/// \param[out] asn1_meas_trigger_quant_offset The RRC NR ASN.1 object where the result of the conversion is stored. +/// \param[in] srs_period_and_omeas_trigger_quantffset common type measurement trigger quantity object. template void meas_trigger_quant_to_rrc_asn1(asn1_meas_trigger_quant_quant_offset& asn1_meas_trigger_quant_offset, - const rrc_meas_trigger_quant& meas_trigger_quant) -{ - if (meas_trigger_quant.rsrp.has_value()) { - asn1_meas_trigger_quant_offset.set_rsrp() = meas_trigger_quant.rsrp.value(); - } else if (meas_trigger_quant.rsrq.has_value()) { - asn1_meas_trigger_quant_offset.set_rsrq() = meas_trigger_quant.rsrq.value(); - } else if (meas_trigger_quant.sinr.has_value()) { - asn1_meas_trigger_quant_offset.set_sinr() = meas_trigger_quant.sinr.value(); - } else { - // error - report_fatal_error("Cannot convert meas trigger quant to ASN.1 type"); - } -} - -inline asn1::rrc_nr::event_trigger_cfg_s -event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigger_cfg& event_triggered_cfg) -{ - asn1::rrc_nr::event_trigger_cfg_s asn1_event_trigger_cfg = {}; - - // report add neigh meas present - asn1_event_trigger_cfg.report_add_neigh_meas_present = event_triggered_cfg.report_add_neigh_meas_present; - - const auto& event_id = event_triggered_cfg.event_id; - - // event a1 - if (event_id.id == rrc_event_id::event_id_t::a1) { - auto& asn1_event_a1 = asn1_event_trigger_cfg.event_id.set_event_a1(); - meas_trigger_quant_to_rrc_asn1(asn1_event_a1.a1_thres, event_id.meas_trigger_quant_thres_or_offset.value()); - asn1_event_a1.report_on_leave = event_id.report_on_leave; - asn1_event_a1.hysteresis = event_id.hysteresis; - asn1::number_to_enum(asn1_event_a1.time_to_trigger, event_id.time_to_trigger); - } - - // event a2 - if (event_id.id == rrc_event_id::event_id_t::a2) { - auto& asn1_event_a2 = asn1_event_trigger_cfg.event_id.set_event_a2(); - meas_trigger_quant_to_rrc_asn1(asn1_event_a2.a2_thres, event_id.meas_trigger_quant_thres_or_offset.value()); - asn1_event_a2.report_on_leave = event_id.report_on_leave; - asn1_event_a2.hysteresis = event_id.hysteresis; - asn1::number_to_enum(asn1_event_a2.time_to_trigger, event_id.time_to_trigger); - } - - // event a3 - if (event_id.id == rrc_event_id::event_id_t::a3) { - auto& asn1_event_a3 = asn1_event_trigger_cfg.event_id.set_event_a3(); - meas_trigger_quant_to_rrc_asn1(asn1_event_a3.a3_offset, event_id.meas_trigger_quant_thres_or_offset.value()); - asn1_event_a3.report_on_leave = event_id.report_on_leave; - asn1_event_a3.hysteresis = event_id.hysteresis; - asn1::number_to_enum(asn1_event_a3.time_to_trigger, event_id.time_to_trigger); - asn1_event_a3.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); - } - - // event a4 - if (event_id.id == rrc_event_id::event_id_t::a4) { - auto& asn1_event_a4 = asn1_event_trigger_cfg.event_id.set_event_a4(); - meas_trigger_quant_to_rrc_asn1(asn1_event_a4.a4_thres, event_id.meas_trigger_quant_thres_or_offset.value()); - asn1_event_a4.report_on_leave = event_id.report_on_leave; - asn1_event_a4.hysteresis = event_id.hysteresis; - asn1::number_to_enum(asn1_event_a4.time_to_trigger, event_id.time_to_trigger); - asn1_event_a4.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); - } - - // event a5 - if (event_id.id == rrc_event_id::event_id_t::a5) { - auto& asn1_event_a5 = asn1_event_trigger_cfg.event_id.set_event_a5(); - meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres1, event_id.meas_trigger_quant_thres_or_offset.value()); - meas_trigger_quant_to_rrc_asn1(asn1_event_a5.a5_thres2, event_id.meas_trigger_quant_thres_or_offset.value()); - asn1_event_a5.report_on_leave = event_id.report_on_leave; - asn1_event_a5.hysteresis = event_id.hysteresis; - asn1::number_to_enum(asn1_event_a5.time_to_trigger, event_id.time_to_trigger); - asn1_event_a5.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); - } - - // event a6 - if (event_id.id == rrc_event_id::event_id_t::a6) { - auto& asn1_event_a6 = asn1_event_trigger_cfg.event_id.set_event_a6(); - meas_trigger_quant_to_rrc_asn1(asn1_event_a6.a6_offset, event_id.meas_trigger_quant_thres_or_offset.value()); - asn1_event_a6.report_on_leave = event_id.report_on_leave; - asn1_event_a6.hysteresis = event_id.hysteresis; - asn1::number_to_enum(asn1_event_a6.time_to_trigger, event_id.time_to_trigger); - asn1_event_a6.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); - } - - // rs type - asn1_event_trigger_cfg.rs_type = rrc_nr_rs_type_to_asn1(event_triggered_cfg.rs_type); - - // report interv - // report interv. This struct mixes ms and minutes so we need to convert the value before conversion - if (event_triggered_cfg.report_interv < 60000) { - asn1::number_to_enum(asn1_event_trigger_cfg.report_interv, event_triggered_cfg.report_interv); - } else { - asn1::number_to_enum(asn1_event_trigger_cfg.report_interv, event_triggered_cfg.report_interv / 60000); - } - - // report amount - asn1::number_to_enum(asn1_event_trigger_cfg.report_amount, event_triggered_cfg.report_amount); - - // report quant cell - asn1_event_trigger_cfg.report_quant_cell = meas_report_quant_to_rrc_asn1(event_triggered_cfg.report_quant_cell); - - // max report cells - asn1_event_trigger_cfg.max_report_cells = event_triggered_cfg.max_report_cells; + const rrc_meas_trigger_quant& meas_trigger_quant); - // report quant rx idxes - if (event_triggered_cfg.report_quant_rs_idxes.has_value()) { - asn1_event_trigger_cfg.report_quant_rs_idxes_present = true; - asn1_event_trigger_cfg.report_quant_rs_idxes = - meas_report_quant_to_rrc_asn1(event_triggered_cfg.report_quant_rs_idxes.value()); - } - - // max nrof rs idxes to report - if (event_triggered_cfg.max_nrof_rs_idxes_to_report.has_value()) { - asn1_event_trigger_cfg.max_nrof_rs_idxes_to_report_present = true; - asn1_event_trigger_cfg.max_nrof_rs_idxes_to_report = event_triggered_cfg.max_nrof_rs_idxes_to_report.value(); - } - - // include beam meass - asn1_event_trigger_cfg.include_beam_meass = event_triggered_cfg.include_beam_meass; - - return asn1_event_trigger_cfg; -} - -inline asn1::rrc_nr::report_cfg_nr_s report_cfg_nr_to_rrc_asn1(const rrc_report_cfg_nr& report_cfg_nr) -{ - asn1::rrc_nr::report_cfg_nr_s asn1_report_cfg_nr; - - if (const auto* periodical = std::get_if(&report_cfg_nr); periodical != nullptr) { - // periodical - asn1_report_cfg_nr.report_type.set_periodical() = periodical_report_cfg_to_rrc_asn1(*periodical); - } - - if (const auto* event_triggered = std::get_if(&report_cfg_nr); event_triggered != nullptr) { - // event triggered - asn1_report_cfg_nr.report_type.set_event_triggered() = event_triggered_report_cfg_to_rrc_asn1(*event_triggered); - } - - if (const auto* report_cgi = std::get_if(&report_cfg_nr); report_cgi != nullptr) { - // report cgi - asn1_report_cfg_nr.report_type.set_report_cgi(); - asn1_report_cfg_nr.report_type.report_cgi().cell_for_which_to_report_cgi = report_cgi->cell_for_which_to_report_cgi; - } - - if (const auto* report_sftd = std::get_if(&report_cfg_nr); report_sftd != nullptr) { - // report sftd - asn1_report_cfg_nr.report_type.set_report_sftd(); - asn1_report_cfg_nr.report_type.report_sftd().report_sftd_meas = report_sftd->report_sftd_meas; - asn1_report_cfg_nr.report_type.report_sftd().report_rsrp = report_sftd->report_rsrp; - } - - return asn1_report_cfg_nr; -} - -inline asn1::rrc_nr::report_cfg_to_add_mod_s -report_cfg_to_add_mod_to_rrc_asn1(const rrc_report_cfg_to_add_mod& report_cfg_to_add_mod) -{ - asn1::rrc_nr::report_cfg_to_add_mod_s asn1_report_cfg_to_add_mod; - - // report cfg id - asn1_report_cfg_to_add_mod.report_cfg_id = report_cfg_id_to_uint(report_cfg_to_add_mod.report_cfg_id); - - // report cfg - asn1_report_cfg_to_add_mod.report_cfg.set_report_cfg_nr() = - report_cfg_nr_to_rrc_asn1(report_cfg_to_add_mod.report_cfg); - - return asn1_report_cfg_to_add_mod; -} - -inline asn1::rrc_nr::meas_id_to_add_mod_s -meas_id_to_add_mod_to_rrc_asn1(const rrc_meas_id_to_add_mod& meas_id_to_add_mod) -{ - asn1::rrc_nr::meas_id_to_add_mod_s asn1_meas_id_to_add_mod; - - // meas id - asn1_meas_id_to_add_mod.meas_id = meas_id_to_uint(meas_id_to_add_mod.meas_id); - // meas obj id - asn1_meas_id_to_add_mod.meas_obj_id = meas_obj_id_to_uint(meas_id_to_add_mod.meas_obj_id); - // report cfg ind - asn1_meas_id_to_add_mod.report_cfg_id = report_cfg_id_to_uint(meas_id_to_add_mod.report_cfg_id); - - return asn1_meas_id_to_add_mod; -} - -inline asn1::rrc_nr::filt_cfg_s filt_cfg_to_rrc_asn1(const rrc_filt_cfg& filt_cfg) -{ - asn1::rrc_nr::filt_cfg_s asn1_filt_cfg; - - // filt coef rsrp - if (filt_cfg.filt_coef_rsrp.has_value()) { - asn1_filt_cfg.filt_coef_rsrp_present = true; - asn1::number_to_enum(asn1_filt_cfg.filt_coef_rsrp, filt_cfg.filt_coef_rsrp.value()); - } - - // filt coef rsrq - if (filt_cfg.filt_coef_rsrq.has_value()) { - asn1_filt_cfg.filt_coef_rsrq_present = true; - asn1::number_to_enum(asn1_filt_cfg.filt_coef_rsrq, filt_cfg.filt_coef_rsrq.value()); - } +/// \brief Convert type \c rrc_event_trigger_cfg to an RRC NR ASN.1 type. +/// \param[in] event_trigger_cfg event trigger config object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::event_trigger_cfg_s +event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigger_cfg& event_trigger_cfg); - // filt coef rs sinr - if (filt_cfg.filt_coef_rs_sinr.has_value()) { - asn1_filt_cfg.filt_coef_rs_sinr_present = true; - asn1::number_to_enum(asn1_filt_cfg.filt_coef_rs_sinr, filt_cfg.filt_coef_rs_sinr.value()); - } +/// \brief Convert type \c rrc_report_cfg_nr to an RRC NR ASN.1 type. +/// \param[in] report_cfg_nr report config object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::report_cfg_nr_s report_cfg_nr_to_rrc_asn1(const rrc_report_cfg_nr& report_cfg_nr); - return asn1_filt_cfg; -} +/// \brief Convert type \c rrc_report_cfg_to_add_mod to an RRC NR ASN.1 type. +/// \param[in] report_cfg_to_add_mod report config to add mod object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::report_cfg_to_add_mod_s +report_cfg_to_add_mod_to_rrc_asn1(const rrc_report_cfg_to_add_mod& report_cfg_to_add_mod); -inline asn1::rrc_nr::quant_cfg_rs_s quant_cfg_rs_to_rrc_asn1(const rrc_quant_cfg_rs& quant_cfg_rs) -{ - asn1::rrc_nr::quant_cfg_rs_s asn1_quant_cfg_rs; +/// \brief Convert type \c rrc_meas_id_to_add_mod to an RRC NR ASN.1 type. +/// \param[in] meas_id_to_add_mod measurement id to add mod object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::meas_id_to_add_mod_s meas_id_to_add_mod_to_rrc_asn1(const rrc_meas_id_to_add_mod& meas_id_to_add_mod); - // ssb filt cfg - asn1_quant_cfg_rs.ssb_filt_cfg = filt_cfg_to_rrc_asn1(quant_cfg_rs.ssb_filt_cfg); - // csi rs filt cfg - asn1_quant_cfg_rs.csi_rs_filt_cfg = filt_cfg_to_rrc_asn1(quant_cfg_rs.csi_rs_filt_cfg); +/// \brief Convert type \c rrc_filt_cfg to an RRC NR ASN.1 type. +/// \param[in] filt_cfg filter config object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::filt_cfg_s filt_cfg_to_rrc_asn1(const rrc_filt_cfg& filt_cfg); - return asn1_quant_cfg_rs; -} +/// \brief Convert type \c rrc_quant_cfg_rs to an RRC NR ASN.1 type. +/// \param[in] quant_cfg_rs quantity config rs object. +/// \return The RRC NR ASN.1 object where the result of the conversion is stored. +asn1::rrc_nr::quant_cfg_rs_s quant_cfg_rs_to_rrc_asn1(const rrc_quant_cfg_rs& quant_cfg_rs); /// \brief Converts type \c cu_cp_meas_cfg to an RRC NR ASN.1 type. -/// \param meas_cfg Meas config object. +/// \param[in] meas_cfg Meas config object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. -inline asn1::rrc_nr::meas_cfg_s meas_config_to_rrc_asn1(const rrc_meas_cfg& meas_cfg) -{ - asn1::rrc_nr::meas_cfg_s asn1_meas_cfg; - - // meas obj to rem list - for (const auto& meas_obj_to_rem : meas_cfg.meas_obj_to_rem_list) { - asn1_meas_cfg.meas_obj_to_rem_list.push_back(meas_obj_id_to_uint(meas_obj_to_rem)); - } - - // meas obj to add mod list - for (const auto& meas_obj_to_add_mod : meas_cfg.meas_obj_to_add_mod_list) { - asn1::rrc_nr::meas_obj_to_add_mod_s asn1_meas_obj_to_add_mod = meas_obj_to_add_mod_to_rrc_asn1(meas_obj_to_add_mod); - asn1_meas_cfg.meas_obj_to_add_mod_list.push_back(asn1_meas_obj_to_add_mod); - } - - // report cfg to rem list - for (const auto& report_cfg_to_rem : meas_cfg.report_cfg_to_rem_list) { - asn1_meas_cfg.report_cfg_to_rem_list.push_back(report_cfg_id_to_uint(report_cfg_to_rem)); - } - - // report cfg to add mod list - for (const auto& report_cfg_to_add_mod : meas_cfg.report_cfg_to_add_mod_list) { - asn1::rrc_nr::report_cfg_to_add_mod_s asn1_report_cfg_to_add_mod = - report_cfg_to_add_mod_to_rrc_asn1(report_cfg_to_add_mod); - asn1_meas_cfg.report_cfg_to_add_mod_list.push_back(asn1_report_cfg_to_add_mod); - } - - // meas id to rem list - for (const auto& meas_id_to_rem : meas_cfg.meas_id_to_rem_list) { - asn1_meas_cfg.meas_id_to_rem_list.push_back(meas_id_to_uint(meas_id_to_rem)); - } - - // meas id to add mod list - for (const auto& meas_id_to_add_mod : meas_cfg.meas_id_to_add_mod_list) { - asn1::rrc_nr::meas_id_to_add_mod_s asn1_meas_id_to_add_mod = meas_id_to_add_mod_to_rrc_asn1(meas_id_to_add_mod); - asn1_meas_cfg.meas_id_to_add_mod_list.push_back(asn1_meas_id_to_add_mod); - } - - // s measure cfg - if (meas_cfg.s_measure_cfg.has_value()) { - asn1_meas_cfg.s_measure_cfg_present = true; - if (meas_cfg.s_measure_cfg.value().type == rrc_s_measure_cfg::measure_type_t::ssb_rsrp) { - asn1_meas_cfg.s_measure_cfg.set_ssb_rsrp() = meas_cfg.s_measure_cfg.value().measure_config; - } - - if (meas_cfg.s_measure_cfg.value().type == rrc_s_measure_cfg::measure_type_t::csi_rsrp) { - asn1_meas_cfg.s_measure_cfg.set_csi_rsrp() = meas_cfg.s_measure_cfg.value().measure_config; - } - } - - // quant cfg - if (meas_cfg.quant_cfg.has_value()) { - asn1_meas_cfg.quant_cfg_present = true; - for (const auto& quant_cfg_nr : meas_cfg.quant_cfg.value().quant_cfg_nr_list) { - asn1::rrc_nr::quant_cfg_nr_s asn1_quant_cfg_nr; - - // quant cfg cell - asn1_quant_cfg_nr.quant_cfg_cell = quant_cfg_rs_to_rrc_asn1(quant_cfg_nr.quant_cfg_cell); - - // quant cfg rs idx - if (quant_cfg_nr.quant_cfg_rs_idx.has_value()) { - asn1_quant_cfg_nr.quant_cfg_rs_idx_present = true; - asn1_quant_cfg_nr.quant_cfg_rs_idx = quant_cfg_rs_to_rrc_asn1(quant_cfg_nr.quant_cfg_rs_idx.value()); - } - - asn1_meas_cfg.quant_cfg.quant_cfg_nr_list.push_back(asn1_quant_cfg_nr); - } - } - - // meas gap cfg - if (meas_cfg.meas_gap_cfg.has_value()) { - asn1_meas_cfg.meas_gap_cfg_present = true; - if (meas_cfg.meas_gap_cfg.value().gap_fr2.has_value()) { - asn1_meas_cfg.meas_gap_cfg.gap_fr2_present = true; - if (meas_cfg.meas_gap_cfg.value().gap_fr2.value().is_release) { - asn1_meas_cfg.meas_gap_cfg.gap_fr2.set_release(); - } else if (meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.has_value()) { - asn1_meas_cfg.meas_gap_cfg.gap_fr2.set_setup(); - // gap offset - asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().gap_offset = - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().gap_offset; - // mgl - asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgl, - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgl); - // mgrp - asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgrp, - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgrp); - // mgta - asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgta, - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgta); - } else { - // error - report_fatal_error("Cannot convert gap fr2 to ASN.1 type"); - } - } - } - - // meas gap sharing cfg - if (meas_cfg.meas_gap_sharing_cfg.has_value()) { - asn1_meas_cfg.meas_gap_sharing_cfg_present = true; - if (meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.has_value()) { - asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2_present = true; - if (meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().is_release) { - asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.set_release(); - } else if (!meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().setup.value().empty()) { - asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.set_setup(); - asn1::string_to_enum(asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.setup(), - meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().setup.value()); - } else { - // error - report_fatal_error("Cannot convert gap sharing fr2 to ASN.1 type"); - } - } - } - - return asn1_meas_cfg; -} - -inline rrc_meas_quant_results -asn1_to_meas_quant_results(const asn1::rrc_nr::meas_quant_results_s& asn1_meas_quant_results) -{ - rrc_meas_quant_results meas_quant_results; - - // rsrp - if (asn1_meas_quant_results.rsrp_present) { - meas_quant_results.rsrp = asn1_meas_quant_results.rsrp; - } - - // rsrq - if (asn1_meas_quant_results.rsrq_present) { - meas_quant_results.rsrq = asn1_meas_quant_results.rsrq; - } - - // sinr - if (asn1_meas_quant_results.sinr_present) { - meas_quant_results.sinr = asn1_meas_quant_results.sinr; - } - - return meas_quant_results; -}; - -inline rrc_meas_result_nr asn1_to_meas_result_nr(const asn1::rrc_nr::meas_result_nr_s& asn1_meas_result_nr) -{ - rrc_meas_result_nr meas_result_nr; - - // pci - if (asn1_meas_result_nr.pci_present) { - meas_result_nr.pci = asn1_meas_result_nr.pci; - } - - // cell results - // results ssb cell - if (asn1_meas_result_nr.meas_result.cell_results.results_ssb_cell_present) { - meas_result_nr.cell_results.results_ssb_cell = - asn1_to_meas_quant_results(asn1_meas_result_nr.meas_result.cell_results.results_ssb_cell); - } - // results csi rs cell - if (asn1_meas_result_nr.meas_result.cell_results.results_csi_rs_cell_present) { - meas_result_nr.cell_results.results_csi_rs_cell = - asn1_to_meas_quant_results(asn1_meas_result_nr.meas_result.cell_results.results_csi_rs_cell); - } - - // rs idx results - if (asn1_meas_result_nr.meas_result.rs_idx_results_present) { - rrc_meas_result_nr::rs_idx_results_ rs_idx_result; - - // results ssb idxes - for (const auto& asn1_ssb_result : asn1_meas_result_nr.meas_result.rs_idx_results.results_ssb_idxes) { - rrc_results_per_ssb_idx ssb_result; - - ssb_result.ssb_idx = asn1_ssb_result.ssb_idx; - - if (asn1_ssb_result.ssb_results_present) { - ssb_result.ssb_results = asn1_to_meas_quant_results(asn1_ssb_result.ssb_results); - } - rs_idx_result.results_ssb_idxes.emplace(asn1_ssb_result.ssb_idx, ssb_result); - } - - // results csi_rs idxes - for (const auto& asn1_csi_rs_result : asn1_meas_result_nr.meas_result.rs_idx_results.results_csi_rs_idxes) { - rrc_results_per_csi_rs_idx csi_rs_result; - if (asn1_csi_rs_result.csi_rs_results_present) { - csi_rs_result.csi_rs_results = asn1_to_meas_quant_results(asn1_csi_rs_result.csi_rs_results); - } - rs_idx_result.results_csi_rs_idxes.emplace(asn1_csi_rs_result.csi_rs_idx, csi_rs_result); - } - - meas_result_nr.rs_idx_results = rs_idx_result; - } - - return meas_result_nr; -}; - -inline rrc_meas_results asn1_to_measurement_results(const asn1::rrc_nr::meas_results_s& asn1_meas_results, - srslog::basic_logger& logger) -{ - rrc_meas_results meas_results; - - // meas id - meas_results.meas_id = uint_to_meas_id(asn1_meas_results.meas_id); - - // meas result serving mo list - for (const auto& asn1_meas_result_serv_mo : asn1_meas_results.meas_result_serving_mo_list) { - rrc_meas_result_serv_mo meas_result_serv_mo; - - // serv cell id - meas_result_serv_mo.serv_cell_id = asn1_meas_result_serv_mo.serv_cell_id; - // meas result serving cell - meas_result_serv_mo.meas_result_serving_cell = - asn1_to_meas_result_nr(asn1_meas_result_serv_mo.meas_result_serving_cell); - // meas result best neigh cell - if (asn1_meas_result_serv_mo.meas_result_best_neigh_cell_present) { - meas_result_serv_mo.meas_result_best_neigh_cell = - asn1_to_meas_result_nr(asn1_meas_result_serv_mo.meas_result_best_neigh_cell); - } - - meas_results.meas_result_serving_mo_list.emplace(asn1_meas_result_serv_mo.serv_cell_id, meas_result_serv_mo); - } - - // meas result neigh cells - if (asn1_meas_results.meas_result_neigh_cells_present) { - rrc_meas_result_neigh_cells meas_result_neigh_cell; - - if (asn1_meas_results.meas_result_neigh_cells.type() == - asn1::rrc_nr::meas_results_s::meas_result_neigh_cells_c_::types_opts::options::meas_result_list_nr) { - // meas result list nr - for (const auto& asn1_meas_result_nr : asn1_meas_results.meas_result_neigh_cells.meas_result_list_nr()) { - meas_result_neigh_cell.meas_result_list_nr.push_back(asn1_to_meas_result_nr(asn1_meas_result_nr)); - } - } else { - // error - logger.error("Ignoring neighbor cell measurement. Cause: Unsupported cell type {}", - asn1_meas_results.meas_result_neigh_cells.type().to_string()); - } - - meas_results.meas_result_neigh_cells = meas_result_neigh_cell; - } - - return meas_results; -} +asn1::rrc_nr::meas_cfg_s meas_config_to_rrc_asn1(const rrc_meas_cfg& meas_cfg); +rrc_meas_quant_results asn1_to_meas_quant_results(const asn1::rrc_nr::meas_quant_results_s& asn1_meas_quant_results); + +/// \brief Convert ASN.1 type \c asn1::rrc_nr::meas_result_nr_s to common type. +/// \param[in] asn1_meas_result_nr measurement result nr ASN.1 object. +/// \return The common type object where the result of the conversion is stored. +rrc_meas_result_nr asn1_to_meas_result_nr(const asn1::rrc_nr::meas_result_nr_s& asn1_meas_result_nr); + +/// \brief Convert ASN.1 type \c asn1::rrc_nr::meas_results_s to common type. +/// \param[in] asn1_meas_results measurement result ASN.1 object. +/// \return The common type object where the result of the conversion is stored. +rrc_meas_results asn1_to_measurement_results(const asn1::rrc_nr::meas_results_s& asn1_meas_results, + srslog::basic_logger& logger); } // namespace srs_cu_cp } // namespace srsran From 4716490c2c21bdea3688dc19a17d3b90fd23a7cf Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 13 Aug 2024 09:05:06 +0200 Subject: [PATCH 256/407] ci: update retina version --- .gitlab/ci/e2e/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index a2d6eaa82c..e2dbb38d9f 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.3 +RETINA_VERSION=0.52.5 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From 99f31bef764864b92f5499e205b67ca6824b663a Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 25 Jul 2024 07:37:09 +0200 Subject: [PATCH 257/407] pdcp: apply deciphering and integrity check in a function --- lib/pdcp/pdcp_entity_rx.cpp | 92 ++++++++++++++++++++----------------- lib/pdcp/pdcp_entity_rx.h | 6 ++- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/lib/pdcp/pdcp_entity_rx.cpp b/lib/pdcp/pdcp_entity_rx.cpp index 7814fad7fb..6a4bf01b0c 100644 --- a/lib/pdcp/pdcp_entity_rx.cpp +++ b/lib/pdcp/pdcp_entity_rx.cpp @@ -197,48 +197,13 @@ void pdcp_entity_rx::handle_data_pdu(byte_buffer pdu) return; } - /* - * TS 38.323, section 5.8: Deciphering - * - * The data unit that is ciphered is the MAC-I and the - * data part of the PDCP Data PDU except the - * SDAP header and the SDAP Control PDU if included in the PDCP SDU. - */ - byte_buffer_view sdu_plus_mac = byte_buffer_view{pdu.begin() + hdr_len_bytes, pdu.end()}; - if (ciphering_enabled == security::ciphering_enabled::on && - sec_cfg.cipher_algo != security::ciphering_algorithm::nea0) { - cipher_decrypt(sdu_plus_mac, rcvd_count); - } - - /* - * Extract MAC-I: - * Always extract from SRBs, only extract from DRBs if integrity is enabled - */ - security::sec_mac mac = {}; - if (is_srb() || (is_drb() && (integrity_enabled == security::integrity_enabled::on))) { - extract_mac(pdu, mac); - } - - /* - * TS 38.323, section 5.9: Integrity verification - * - * The data unit that is integrity protected is the PDU header - * and the data part of the PDU before ciphering. - */ - if (integrity_enabled == security::integrity_enabled::on) { - bool is_valid = integrity_verify(pdu, rcvd_count, mac); - if (!is_valid) { - logger.log_warning(pdu.begin(), pdu.end(), "Integrity failed, dropping PDU."); - metrics_add_integrity_failed_pdus(1); - // TODO: Re-enable once the RRC supports notifications from the PDCP - // upper_cn.on_integrity_failure(); - return; // Invalid packet, drop. - } - metrics_add_integrity_verified_pdus(1); - logger.log_debug(pdu.begin(), pdu.end(), "Integrity passed."); + // Apply deciphering and integrity check + expected exp_buf = apply_deciphering_and_integrity_check(std::move(pdu), rcvd_count); + if (!exp_buf.has_value()) { + logger.log_error("Failed deciphering and integrity check, dropping PDU and notifying RRC. count={}", rcvd_count); + return; } - // After checking the integrity, we can discard the header. - discard_data_header(pdu); + pdu = std::move(exp_buf.value()); /* * Check valid rcvd_count: @@ -431,8 +396,51 @@ std::unique_ptr> pdcp_entity_rx::create_rx_window(p } /* - * Security helpers + * Deciphering and Integrity Protection Helpers */ +expected pdcp_entity_rx::apply_deciphering_and_integrity_check(byte_buffer pdu, uint32_t count) +{ + // TS 38.323, section 5.8: Deciphering + // The data unit that is ciphered is the MAC-I and the + // data part of the PDCP Data PDU except the + // SDAP header and the SDAP Control PDU if included in the PDCP SDU. + + byte_buffer_view sdu_plus_mac = byte_buffer_view{pdu.begin() + hdr_len_bytes, pdu.end()}; + if (ciphering_enabled == security::ciphering_enabled::on && + sec_cfg.cipher_algo != security::ciphering_algorithm::nea0) { + cipher_decrypt(sdu_plus_mac, count); + } + + // Extract MAC-I: + // Always extract from SRBs, only extract from DRBs if integrity is enabled + + security::sec_mac mac = {}; + if (is_srb() || (is_drb() && (integrity_enabled == security::integrity_enabled::on))) { + extract_mac(pdu, mac); + } + + // TS 38.323, section 5.9: Integrity verification + // The data unit that is integrity protected is the PDU header + // and the data part of the PDU before ciphering. + + if (integrity_enabled == security::integrity_enabled::on) { + bool is_valid = integrity_verify(pdu, count, mac); + if (!is_valid) { + logger.log_warning(pdu.begin(), pdu.end(), "Integrity failed, dropping PDU."); + metrics_add_integrity_failed_pdus(1); + // TODO: Re-enable once the RRC supports notifications from the PDCP + // upper_cn.on_integrity_failure(); + return make_unexpected(default_error_t{}); // Invalid packet, drop. + } + metrics_add_integrity_verified_pdus(1); + logger.log_debug(pdu.begin(), pdu.end(), "Integrity passed."); + } + // After checking the integrity, we can discard the header. + discard_data_header(pdu); + + return pdu; +} + bool pdcp_entity_rx::integrity_verify(byte_buffer_view buf, uint32_t count, const security::sec_mac& mac) { srsran_assert(sec_cfg.k_128_int.has_value(), "Cannot verify integrity: Integrity key is not configured."); diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index 022169d682..a65fd59d0d 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -183,8 +183,10 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, void deliver_all_sdus(); void discard_all_sdus(); - bool integrity_verify(byte_buffer_view buf, uint32_t count, const security::sec_mac& mac); - byte_buffer cipher_decrypt(byte_buffer_view& msg, uint32_t count); + /// Apply deciphering and integrity check to the PDU + expected apply_deciphering_and_integrity_check(byte_buffer pdu, uint32_t count); + bool integrity_verify(byte_buffer_view buf, uint32_t count, const security::sec_mac& mac); + byte_buffer cipher_decrypt(byte_buffer_view& msg, uint32_t count); /* * Notifiers and handlers From 18a9a90be83f48f64de034a1123c4a74c051e4de Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 25 Jul 2024 10:10:11 +0200 Subject: [PATCH 258/407] sec: implement decryption and integrity verification --- lib/security/integrity_engine_generic.cpp | 41 ++++++++++++++++++++++- lib/security/security_engine_impl.cpp | 16 ++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/lib/security/integrity_engine_generic.cpp b/lib/security/integrity_engine_generic.cpp index 0be6340dd6..80c5a7181c 100644 --- a/lib/security/integrity_engine_generic.cpp +++ b/lib/security/integrity_engine_generic.cpp @@ -60,6 +60,45 @@ security_result integrity_engine_generic::protect_integrity(byte_buffer buf, uin security_result integrity_engine_generic::verify_integrity(byte_buffer buf, uint32_t count) { - security_result result; + security_result result{.buf = std::move(buf), .count = count}; + security::sec_mac mac = {}; + + if (result.buf->length() <= mac.size()) { + result.buf = make_unexpected(security_error::integrity_failure); + return result; + } + + byte_buffer_view v{result.buf.value(), 0, result.buf.value().length() - mac.size()}; + byte_buffer_view m{result.buf.value(), result.buf.value().length() - mac.size(), mac.size()}; + + switch (integ_algo) { + case security::integrity_algorithm::nia0: + // TS 33.501, Sec. D.1 + // The NIA0 algorithm shall be implemented in such way that it shall generate a 32 bit MAC-I/NAS-MAC and + // XMAC-I/XNAS-MAC of all zeroes (see sub-clause D.3.1). + std::fill(mac.begin(), mac.end(), 0); + break; + case security::integrity_algorithm::nia1: + security_nia1(mac, k_128_int, count, bearer_id, direction, v); + break; + case security::integrity_algorithm::nia2: + security_nia2(mac, k_128_int, count, bearer_id, direction, v); + break; + case security::integrity_algorithm::nia3: + security_nia3(mac, k_128_int, count, bearer_id, direction, v); + break; + default: + break; + } + + // Verify MAC + if (!std::equal(mac.begin(), mac.end(), m.begin(), m.end())) { + result.buf = make_unexpected(security_error::integrity_failure); + return result; + } + + // Trim MAC from PDU + result.buf.value().trim_tail(mac.size()); + return result; } diff --git a/lib/security/security_engine_impl.cpp b/lib/security/security_engine_impl.cpp index 13612384ec..0dd9224bc0 100644 --- a/lib/security/security_engine_impl.cpp +++ b/lib/security/security_engine_impl.cpp @@ -84,6 +84,20 @@ security_result security_engine_impl::encrypt_and_protect_integrity(byte_buffer security_result security_engine_impl::decrypt_and_verify_integrity(byte_buffer buf, size_t offset, uint32_t count) { - security_result result; + security_result result{.buf = std::move(buf), .count = count}; + + // apply deciphering if activated + if (cipher_eng != nullptr) { + result = cipher_eng->apply_ciphering(std::move(result.buf.value()), offset, result.count); + if (!result.buf.has_value()) { + return result; + } + } + + // verify integrity if activated + if (integ_eng != nullptr) { + result = integ_eng->verify_integrity(std::move(result.buf.value()), result.count); + } + return result; } From 5a97cc46d9d0f00b01d79dee4a8d6e38f31329cc Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 26 Jul 2024 11:55:07 +0200 Subject: [PATCH 259/407] pdcp: tests verify updated sec config on reestablishment implicitly by passing PDUs This way the sec config does not need to be extractable from PDCP RX entity --- lib/pdcp/pdcp_entity_rx.h | 7 +++---- tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp | 12 +++++++----- tests/unittests/pdcp/pdcp_rx_test_helpers.h | 9 +++++++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index a65fd59d0d..e09e8b7e04 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -145,10 +145,9 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, /* * Testing Helpers */ - void set_state(pdcp_rx_state st_) { st = st_; } - pdcp_rx_state get_state() { return st; } - security::sec_128_as_config get_sec_config() { return sec_cfg; } - bool is_reordering_timer_running() { return reordering_timer.is_running(); } + void set_state(pdcp_rx_state st_) { st = st_; } + pdcp_rx_state get_state() { return st; } + bool is_reordering_timer_running() { return reordering_timer.is_running(); } private: pdcp_bearer_logger logger; diff --git a/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp b/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp index cc2616a7d7..04c10b96b9 100644 --- a/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp +++ b/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp @@ -29,6 +29,8 @@ TEST_P(pdcp_rx_reestablish_test, when_srb_reestablish_then_sdus_dropped) reest_sec_cfg.integ_algo = security::integrity_algorithm::nia3; reest_sec_cfg.cipher_algo = security::ciphering_algorithm::nea3; pdcp_rx->configure_security(sec_cfg); + pdcp_rx->set_integrity_protection(security::integrity_enabled::on); + pdcp_rx->set_ciphering(security::ciphering_enabled::on); // Prepare 3 PDUs. byte_buffer test_pdu1; @@ -62,11 +64,11 @@ TEST_P(pdcp_rx_reestablish_test, when_srb_reestablish_then_sdus_dropped) } ASSERT_EQ(0, test_frame->sdu_queue.size()); - // Check security config changed - { - security::sec_128_as_config reest_sec_config2 = pdcp_rx->get_sec_config(); - ASSERT_EQ(reest_sec_cfg, reest_sec_config2); - } + // Check security config changed by passing test PDUs from NxA3 testset + byte_buffer test_pdu_nxa3; + get_test_pdu(count, test_pdu_nxa3, 3); + pdcp_rx->handle_pdu(byte_buffer_chain::create(std::move(test_pdu_nxa3)).value()); + ASSERT_EQ(1, test_frame->sdu_queue.size()); } /// Test DRB UM reestablishment diff --git a/tests/unittests/pdcp/pdcp_rx_test_helpers.h b/tests/unittests/pdcp/pdcp_rx_test_helpers.h index 7a6c9689ca..2da3b0ee7c 100644 --- a/tests/unittests/pdcp/pdcp_rx_test_helpers.h +++ b/tests/unittests/pdcp/pdcp_rx_test_helpers.h @@ -113,6 +113,15 @@ class pdcp_rx_test_helper ASSERT_EQ(true, get_pdu_test_vector(sn_size, count, exp_pdu, algo)); } + /// \brief Gets test PDU based on the COUNT and SN size and algo + /// \param count COUNT being tested + /// \param exp_pdu Expected PDU that is set to the correct test vector + /// \param custom_algo Pick PDU for a specific algorithm (which may differ from current config) + void get_test_pdu(uint32_t count, byte_buffer& exp_pdu, unsigned custom_algo) + { + ASSERT_EQ(true, get_pdu_test_vector(sn_size, count, exp_pdu, custom_algo)); + } + /// \brief Helper to advance the timers /// \param nof_tick Number of ticks to advance timers void tick_all(uint32_t nof_ticks) From 45047a5e6cbd5b894a2cc8c7632d4dfb4b838a01 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 26 Jul 2024 11:58:15 +0200 Subject: [PATCH 260/407] pdcp: enable integrity and ciphering in rx reestablish test --- tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp b/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp index 04c10b96b9..aad064f1a3 100644 --- a/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp +++ b/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp @@ -78,6 +78,8 @@ TEST_P(pdcp_rx_reestablish_test, when_drb_um_reestablish_then_pdus_forwared) uint32_t count = 0; pdcp_rx->configure_security(sec_cfg); + pdcp_rx->set_integrity_protection(security::integrity_enabled::on); + pdcp_rx->set_ciphering(security::ciphering_enabled::on); // Prepare 3 PDUs. byte_buffer test_pdu1; @@ -125,6 +127,8 @@ TEST_P(pdcp_rx_reestablish_test, when_drb_am_reestablish_then_state_preserved) security::sec_128_as_config reest_sec_cfg = sec_cfg; pdcp_rx->configure_security(sec_cfg); + pdcp_rx->set_integrity_protection(security::integrity_enabled::on); + pdcp_rx->set_ciphering(security::ciphering_enabled::on); // Prepare 3 PDUs. byte_buffer test_pdu1; From a63f1d0a3d3daaa7028abeb8b0fa9fefce3582ed Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 26 Jul 2024 15:18:34 +0200 Subject: [PATCH 261/407] pdcp: integrate security engine in RX entity --- include/srsran/pdcp/pdcp_rx.h | 8 +- lib/cu_up/pdu_session_manager_impl.cpp | 4 +- lib/pdcp/pdcp_entity_rx.cpp | 214 ++++++++---------- lib/pdcp/pdcp_entity_rx.h | 70 +----- lib/rrc/ue/rrc_ue_srb_context.h | 10 +- tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp | 4 +- .../integrationtests/rlc/rlc_stress_test.cpp | 2 +- tests/unittests/pdcp/pdcp_rx_metrics_test.cpp | 12 +- tests/unittests/pdcp/pdcp_rx_metrics_test.h | 4 - .../pdcp/pdcp_rx_reestablish_test.cpp | 16 +- .../unittests/pdcp/pdcp_rx_reestablish_test.h | 4 - .../pdcp/pdcp_rx_status_report_test.cpp | 5 +- tests/unittests/pdcp/pdcp_rx_test.cpp | 29 +-- tests/unittests/pdcp/pdcp_rx_test.h | 4 - 14 files changed, 133 insertions(+), 253 deletions(-) diff --git a/include/srsran/pdcp/pdcp_rx.h b/include/srsran/pdcp/pdcp_rx.h index 91e0eefba6..1c88ab1b56 100644 --- a/include/srsran/pdcp/pdcp_rx.h +++ b/include/srsran/pdcp/pdcp_rx.h @@ -99,11 +99,11 @@ class pdcp_rx_upper_control_interface pdcp_rx_upper_control_interface& operator=(const pdcp_rx_upper_control_interface&&) = delete; /// Handle the incoming security config. - virtual void configure_security(security::sec_128_as_config sec_cfg) = 0; - virtual void set_integrity_protection(security::integrity_enabled integrity_enabled_) = 0; - virtual void set_ciphering(security::ciphering_enabled ciphering_enabled_) = 0; + virtual void configure_security(security::sec_128_as_config sec_cfg, + security::integrity_enabled integrity_enabled_, + security::ciphering_enabled ciphering_enabled_) = 0; /// Trigger re-establishment - virtual void reestablish(security::sec_128_as_config sec_cfg_) = 0; + virtual void reestablish(security::sec_128_as_config sec_cfg) = 0; }; } // namespace srsran diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index b1465961aa..700ec58d24 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -287,9 +287,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& // configure rx security auto& pdcp_rx_ctrl = new_drb->pdcp->get_rx_upper_control_interface(); - pdcp_rx_ctrl.configure_security(sec_128); - pdcp_rx_ctrl.set_integrity_protection(integrity_enabled); - pdcp_rx_ctrl.set_ciphering(ciphering_enabled); + pdcp_rx_ctrl.configure_security(sec_128, integrity_enabled, ciphering_enabled); // Connect "PDCP-E1AP" adapter to E1AP new_drb->pdcp_tx_to_e1ap_adapter.connect_e1ap(); // TODO: pass actual E1AP handler diff --git a/lib/pdcp/pdcp_entity_rx.cpp b/lib/pdcp/pdcp_entity_rx.cpp index 6a4bf01b0c..9c124434e5 100644 --- a/lib/pdcp/pdcp_entity_rx.cpp +++ b/lib/pdcp/pdcp_entity_rx.cpp @@ -9,10 +9,9 @@ */ #include "pdcp_entity_rx.h" +#include "../security/security_engine_impl.h" #include "../support/sdu_window_impl.h" #include "srsran/instrumentation/traces/up_traces.h" -#include "srsran/security/ciphering.h" -#include "srsran/security/integrity.h" #include "srsran/support/bit_encoding.h" using namespace srsran; @@ -28,8 +27,6 @@ pdcp_entity_rx::pdcp_entity_rx(uint32_t ue_index, pdcp_entity_tx_rx_base(rb_id_, cfg_.rb_type, cfg_.rlc_mode, cfg_.sn_size), logger("PDCP", {ue_index, rb_id_, "UL"}), cfg(cfg_), - direction(cfg.direction == pdcp_security_direction::uplink ? security::security_direction::uplink - : security::security_direction::downlink), rx_window(create_rx_window(cfg.sn_size)), upper_dn(upper_dn_), upper_cn(upper_cn_), @@ -86,7 +83,7 @@ void pdcp_entity_rx::handle_pdu(byte_buffer_chain buf) up_tracer << trace_event{"pdcp_rx_pdu", rx_tp}; } -void pdcp_entity_rx::reestablish(security::sec_128_as_config sec_cfg_) +void pdcp_entity_rx::reestablish(security::sec_128_as_config sec_cfg) { // - process the PDCP Data PDUs that are received from lower layers due to the re-establishment of the lower layers, // as specified in the clause 5.2.2.1; @@ -129,7 +126,7 @@ void pdcp_entity_rx::reestablish(security::sec_128_as_config sec_cfg_) // procedure; // - apply the integrity protection algorithm and key provided by upper layers during the PDCP entity re- // establishment procedure. - configure_security(sec_cfg_); + configure_security(sec_cfg, integrity_enabled, ciphering_enabled); } void pdcp_entity_rx::handle_data_pdu(byte_buffer pdu) @@ -200,9 +197,14 @@ void pdcp_entity_rx::handle_data_pdu(byte_buffer pdu) // Apply deciphering and integrity check expected exp_buf = apply_deciphering_and_integrity_check(std::move(pdu), rcvd_count); if (!exp_buf.has_value()) { - logger.log_error("Failed deciphering and integrity check, dropping PDU and notifying RRC. count={}", rcvd_count); + logger.log_warning("Failed deciphering and integrity check. count={}", rcvd_count); return; } + + // After checking the integrity, we can discard the header. + unsigned hdr_size = cfg.sn_size == pdcp_sn_size::size12bits ? 2 : 3; + exp_buf.value().trim_head(hdr_size); + pdu = std::move(exp_buf.value()); /* @@ -398,119 +400,116 @@ std::unique_ptr> pdcp_entity_rx::create_rx_window(p /* * Deciphering and Integrity Protection Helpers */ -expected pdcp_entity_rx::apply_deciphering_and_integrity_check(byte_buffer pdu, uint32_t count) +expected pdcp_entity_rx::apply_deciphering_and_integrity_check(byte_buffer buf, uint32_t count) { + if (sec_engine == nullptr) { + // Security is not configured. Pass through for DRBs; trim zero MAC-I for SRBs. + if (is_srb()) { + if (buf.length() <= security::sec_mac_len) { + logger.log_warning("Failed to trim MAC-I from PDU. count={}", count); + return make_unexpected(default_error_t{}); + } + buf.trim_tail(security::sec_mac_len); + } + return buf; + } + // TS 38.323, section 5.8: Deciphering // The data unit that is ciphered is the MAC-I and the // data part of the PDCP Data PDU except the // SDAP header and the SDAP Control PDU if included in the PDCP SDU. - byte_buffer_view sdu_plus_mac = byte_buffer_view{pdu.begin() + hdr_len_bytes, pdu.end()}; - if (ciphering_enabled == security::ciphering_enabled::on && - sec_cfg.cipher_algo != security::ciphering_algorithm::nea0) { - cipher_decrypt(sdu_plus_mac, count); - } - - // Extract MAC-I: - // Always extract from SRBs, only extract from DRBs if integrity is enabled - - security::sec_mac mac = {}; - if (is_srb() || (is_drb() && (integrity_enabled == security::integrity_enabled::on))) { - extract_mac(pdu, mac); - } - // TS 38.323, section 5.9: Integrity verification // The data unit that is integrity protected is the PDU header // and the data part of the PDU before ciphering. - if (integrity_enabled == security::integrity_enabled::on) { - bool is_valid = integrity_verify(pdu, count, mac); - if (!is_valid) { - logger.log_warning(pdu.begin(), pdu.end(), "Integrity failed, dropping PDU."); - metrics_add_integrity_failed_pdus(1); - // TODO: Re-enable once the RRC supports notifications from the PDCP - // upper_cn.on_integrity_failure(); - return make_unexpected(default_error_t{}); // Invalid packet, drop. + unsigned hdr_size = cfg.sn_size == pdcp_sn_size::size12bits ? 2 : 3; + security::security_result result = sec_engine->decrypt_and_verify_integrity(std::move(buf), hdr_size, count); + if (!result.buf.has_value()) { + switch (result.buf.error()) { + case srsran::security::security_error::integrity_failure: + logger.log_warning("Integrity failed, dropping PDU. count={}", result.count); + metrics_add_integrity_failed_pdus(1); + upper_cn.on_integrity_failure(); + break; + case srsran::security::security_error::ciphering_failure: + logger.log_warning("Deciphering failed, dropping PDU. count={}", result.count); + upper_cn.on_protocol_failure(); + break; + case srsran::security::security_error::buffer_failure: + logger.log_error("Buffer error when decrypting and verifying integrity, dropping PDU. count={}", result.count); + upper_cn.on_protocol_failure(); + break; } - metrics_add_integrity_verified_pdus(1); - logger.log_debug(pdu.begin(), pdu.end(), "Integrity passed."); + return make_unexpected(default_error_t{}); } - // After checking the integrity, we can discard the header. - discard_data_header(pdu); + metrics_add_integrity_verified_pdus(1); + logger.log_debug(result.buf.value().begin(), result.buf.value().end(), "Integrity passed."); - return pdu; + return {std::move(result.buf.value())}; } -bool pdcp_entity_rx::integrity_verify(byte_buffer_view buf, uint32_t count, const security::sec_mac& mac) +/* + * Security configuration + */ +void pdcp_entity_rx::configure_security(security::sec_128_as_config sec_cfg, + security::integrity_enabled integrity_enabled_, + security::ciphering_enabled ciphering_enabled_) { - srsran_assert(sec_cfg.k_128_int.has_value(), "Cannot verify integrity: Integrity key is not configured."); - srsran_assert(sec_cfg.integ_algo.has_value(), "Cannot verify integrity: Integrity algorithm is not configured."); - security::sec_mac mac_exp = {}; - bool is_valid = true; - switch (sec_cfg.integ_algo.value()) { - case security::integrity_algorithm::nia0: - break; - case security::integrity_algorithm::nia1: - security_nia1(mac_exp, sec_cfg.k_128_int.value(), count, bearer_id, direction, buf); - break; - case security::integrity_algorithm::nia2: - security_nia2(mac_exp, sec_cfg.k_128_int.value(), count, bearer_id, direction, buf); - break; - case security::integrity_algorithm::nia3: - security_nia3(mac_exp, sec_cfg.k_128_int.value(), count, bearer_id, direction, buf); - break; - default: - break; - } - - if (sec_cfg.integ_algo != security::integrity_algorithm::nia0) { - for (uint8_t i = 0; i < 4; i++) { - if (mac[i] != mac_exp[i]) { - is_valid = false; - break; - } + srsran_assert((is_srb() && sec_cfg.domain == security::sec_domain::rrc) || + (is_drb() && sec_cfg.domain == security::sec_domain::up), + "Invalid sec_domain={} for {} in {}", + sec_cfg.domain, + rb_type, + rb_id); + // The 'NULL' integrity protection algorithm (nia0) is used only for SRBs and for the UE in limited service mode, + // see TS 33.501 [11] and when used for SRBs, integrity protection is disabled for DRBs. In case the ′NULL' + // integrity protection algorithm is used, 'NULL' ciphering algorithm is also used. + // Ref: TS 38.331 Sec. 5.3.1.2 + // + // From TS 38.501 Sec. 6.7.3.6: UEs that are in limited service mode (LSM) and that cannot be authenticated (...) may + // still be allowed to establish emergency session by sending the emergency registration request message. (...) + if ((sec_cfg.integ_algo == security::integrity_algorithm::nia0) && + (is_drb() || (is_srb() && sec_cfg.cipher_algo != security::ciphering_algorithm::nea0))) { + logger.log_error("Integrity algorithm NIA0 is only permitted for SRBs configured with NEA0. is_srb={} NIA{} NEA{}", + is_srb(), + sec_cfg.integ_algo, + sec_cfg.cipher_algo); + } + + // Evaluate and store integrity indication + if (integrity_enabled_ == security::integrity_enabled::on) { + if (!sec_cfg.k_128_int.has_value()) { + logger.log_error("Cannot enable integrity protection: Integrity key is not configured."); + return; } - srslog::basic_levels level = is_valid ? srslog::basic_levels::debug : srslog::basic_levels::warning; - logger.log(level, - buf.begin(), - buf.end(), - "Integrity check. is_valid={} count={} bearer_id={} dir={}", - is_valid, - count, - bearer_id, - direction); - logger.log(level, "Integrity check key: {}", sec_cfg.k_128_int); - logger.log(level, "MAC expected: {}", mac_exp); - logger.log(level, "MAC found: {}", mac); - logger.log(level, buf.begin(), buf.end(), "Integrity check input message. len={}", buf.length()); - } - - return is_valid; -} + if (!sec_cfg.integ_algo.has_value()) { + logger.log_error("Cannot enable integrity protection: Integrity algorithm is not configured."); + return; + } + } else { + srsran_assert(!is_srb(), "Integrity protection cannot be disabled for SRBs."); + } + integrity_enabled = integrity_enabled_; -byte_buffer pdcp_entity_rx::cipher_decrypt(byte_buffer_view& msg, uint32_t count) -{ - logger.log_debug("Cipher decrypt. count={} bearer_id={} dir={}", count, bearer_id, direction); - logger.log_debug("Cipher decrypt key: {}", sec_cfg.k_128_enc); - logger.log_debug(msg.begin(), msg.end(), "Cipher decrypt input msg."); + // Evaluate and store ciphering indication + ciphering_enabled = ciphering_enabled_; - byte_buffer ct; + auto direction = cfg.direction == pdcp_security_direction::uplink ? security::security_direction::uplink + : security::security_direction::downlink; + sec_engine = std::make_unique( + sec_cfg, bearer_id, direction, integrity_enabled, ciphering_enabled); - switch (sec_cfg.cipher_algo) { - case security::ciphering_algorithm::nea1: - security_nea1(sec_cfg.k_128_enc, count, bearer_id, direction, msg); - break; - case security::ciphering_algorithm::nea2: - security_nea2(sec_cfg.k_128_enc, count, bearer_id, direction, msg); - break; - case security::ciphering_algorithm::nea3: - security_nea3(sec_cfg.k_128_enc, count, bearer_id, direction, msg); - break; - default: - break; + logger.log_info("Security configured: NIA{} ({}) NEA{} ({}) domain={}", + sec_cfg.integ_algo, + integrity_enabled, + sec_cfg.cipher_algo, + ciphering_enabled, + sec_cfg.domain); + if (sec_cfg.k_128_int.has_value()) { + logger.log_info("128 K_int: {}", sec_cfg.k_128_int); } - logger.log_debug(msg.begin(), msg.end(), "Cipher decrypt output msg."); - return ct; + logger.log_info("128 K_enc: {}", sec_cfg.k_128_enc); } /* @@ -594,20 +593,3 @@ bool pdcp_entity_rx::read_data_pdu_header(pdcp_data_pdu_header& hdr, const byte_ } return true; } - -void pdcp_entity_rx::discard_data_header(byte_buffer& buf) const -{ - buf.trim_head(hdr_len_bytes); -} - -void pdcp_entity_rx::extract_mac(byte_buffer& buf, security::sec_mac& mac) const -{ - if (buf.length() <= security::sec_mac_len) { - logger.log_error("PDU too small to extract MAC-I. pdu_len={} mac_len={}", buf.length(), security::sec_mac_len); - return; - } - for (unsigned i = 0; i < security::sec_mac_len; i++) { - mac[i] = buf[buf.length() - security::sec_mac_len + i]; - } - buf.trim_tail(security::sec_mac_len); -} diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index e09e8b7e04..aff48b76eb 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -19,6 +19,7 @@ #include "srsran/adt/byte_buffer_chain.h" #include "srsran/pdcp/pdcp_config.h" #include "srsran/pdcp/pdcp_rx.h" +#include "srsran/security/security_engine.h" #include "srsran/support/sdu_window.h" #include "srsran/support/timers.h" #include "fmt/format.h" @@ -64,7 +65,7 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, void handle_pdu(byte_buffer_chain buf) override; /// \brief Triggers re-establishment as specified in TS 38.323, section 5.1.2 - void reestablish(security::sec_128_as_config sec_cfg_) override; + void reestablish(security::sec_128_as_config sec_cfg) override; // Rx/Tx interconnect void set_status_handler(pdcp_tx_status_handler* status_handler_) { status_handler = status_handler_; } @@ -85,62 +86,13 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, /// \param[in] buf Reference to the PDU bytes /// \return True if header was read successfully, false otherwise bool read_data_pdu_header(pdcp_data_pdu_header& hdr, const byte_buffer& buf) const; - void discard_data_header(byte_buffer& buf) const; - void extract_mac(byte_buffer& buf, security::sec_mac& mac) const; /* * Security configuration */ - void configure_security(security::sec_128_as_config sec_cfg_) override - { - srsran_assert((is_srb() && sec_cfg_.domain == security::sec_domain::rrc) || - (is_drb() && sec_cfg_.domain == security::sec_domain::up), - "Invalid sec_domain={} for {} in {}", - sec_cfg.domain, - rb_type, - rb_id); - // The 'NULL' integrity protection algorithm (nia0) is used only for SRBs and for the UE in limited service mode, - // see TS 33.501 [11] and when used for SRBs, integrity protection is disabled for DRBs. In case the ′NULL' - // integrity protection algorithm is used, 'NULL' ciphering algorithm is also used. - // Ref: TS 38.331 Sec. 5.3.1.2 - if ((sec_cfg_.integ_algo == security::integrity_algorithm::nia0) && - (is_drb() || (is_srb() && sec_cfg_.cipher_algo != security::ciphering_algorithm::nea0))) { - logger.log_error( - "Integrity algorithm NIA0 is only permitted for SRBs configured with NEA0. is_srb={} NIA{} NEA{}", - is_srb(), - sec_cfg_.integ_algo, - sec_cfg_.cipher_algo); - } - - sec_cfg = sec_cfg_; - logger.log_info( - "Security configured: NIA{} NEA{} domain={}", sec_cfg.integ_algo, sec_cfg.cipher_algo, sec_cfg.domain); - if (sec_cfg.k_128_int.has_value()) { - logger.log_info("128 K_int: {}", sec_cfg.k_128_int); - } - logger.log_info("128 K_enc: {}", sec_cfg.k_128_enc); - } - - void set_integrity_protection(security::integrity_enabled integrity_enabled_) override - { - if (integrity_enabled_ == security::integrity_enabled::on) { - if (!sec_cfg.k_128_int.has_value()) { - logger.log_error("Cannot enable integrity protection: Integrity key is not configured."); - return; - } - if (!sec_cfg.integ_algo.has_value()) { - logger.log_error("Cannot enable integrity protection: Integrity algorithm is not configured."); - return; - } - } - integrity_enabled = integrity_enabled_; - logger.log_info("Set integrity_enabled={}", integrity_enabled); - } - void set_ciphering(security::ciphering_enabled ciphering_enabled_) override - { - ciphering_enabled = ciphering_enabled_; - logger.log_info("Set ciphering_enabled={}", ciphering_enabled); - } + void configure_security(security::sec_128_as_config sec_cfg, + security::integrity_enabled integrity_enabled_, + security::ciphering_enabled ciphering_enabled_) override; /* * Testing Helpers @@ -153,10 +105,10 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, pdcp_bearer_logger logger; const pdcp_rx_config cfg; - security::sec_128_as_config sec_cfg = {}; - security::security_direction direction = security::security_direction::uplink; - security::integrity_enabled integrity_enabled = security::integrity_enabled::off; - security::ciphering_enabled ciphering_enabled = security::ciphering_enabled::off; + std::unique_ptr sec_engine; + + security::integrity_enabled integrity_enabled = security::integrity_enabled::off; + security::ciphering_enabled ciphering_enabled = security::ciphering_enabled::off; pdcp_rx_state st = {}; @@ -183,9 +135,7 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, void discard_all_sdus(); /// Apply deciphering and integrity check to the PDU - expected apply_deciphering_and_integrity_check(byte_buffer pdu, uint32_t count); - bool integrity_verify(byte_buffer_view buf, uint32_t count, const security::sec_mac& mac); - byte_buffer cipher_decrypt(byte_buffer_view& msg, uint32_t count); + expected apply_deciphering_and_integrity_check(byte_buffer buf, uint32_t count); /* * Notifiers and handlers diff --git a/lib/rrc/ue/rrc_ue_srb_context.h b/lib/rrc/ue/rrc_ue_srb_context.h index 4dc388156f..c41b337e5c 100644 --- a/lib/rrc/ue/rrc_ue_srb_context.h +++ b/lib/rrc/ue/rrc_ue_srb_context.h @@ -93,11 +93,9 @@ class ue_srb_context security::ciphering_enabled ciph_enabled, security::sec_128_as_config sec_cfg) const { - // Configure tx security + // Configure rx security auto& pdcp_rx_ctrl = pdcp_context.entity->get_rx_upper_control_interface(); - pdcp_rx_ctrl.configure_security(sec_cfg); - pdcp_rx_ctrl.set_integrity_protection(int_enabled); - pdcp_rx_ctrl.set_ciphering(ciph_enabled); + pdcp_rx_ctrl.configure_security(sec_cfg, int_enabled, ciph_enabled); } // Full security setup. Used e.g., with SRB2 @@ -109,9 +107,7 @@ class ue_srb_context // Configure tx security auto& pdcp_rx_ctrl = pdcp_context.entity->get_rx_upper_control_interface(); - pdcp_rx_ctrl.configure_security(sec_cfg); - pdcp_rx_ctrl.set_integrity_protection(security::integrity_enabled::on); - pdcp_rx_ctrl.set_ciphering(security::ciphering_enabled::on); + pdcp_rx_ctrl.configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); } // Add ciphering and integrity protection to an RRC PDU. diff --git a/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp b/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp index 56aa9b7bc5..380f5a7e54 100644 --- a/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp +++ b/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp @@ -212,9 +212,7 @@ void benchmark_pdcp_rx(bench_params params, // Create PDCP entities std::unique_ptr pdcp_rx = std::make_unique( 0, drb_id_t::drb1, config, frame, frame, timer_factory{timers, worker}, worker, worker); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(int_enabled); - pdcp_rx->set_ciphering(ciph_enabled); + pdcp_rx->configure_security(sec_cfg, int_enabled, ciph_enabled); // Prepare SDU list for benchmark std::vector sdu_list = {}; diff --git a/tests/integrationtests/rlc/rlc_stress_test.cpp b/tests/integrationtests/rlc/rlc_stress_test.cpp index 19a8700a7c..c8ca0baa1a 100644 --- a/tests/integrationtests/rlc/rlc_stress_test.cpp +++ b/tests/integrationtests/rlc/rlc_stress_test.cpp @@ -68,7 +68,7 @@ stress_stack::stress_stack(const stress_test_args& args_, uint32_t id, rb_id_t r pdcp_tx_upper_control_interface& rrc_tx_if = pdcp->get_tx_upper_control_interface(); rrc_tx_if.configure_security(sec_cfg, security::integrity_enabled::off, security::ciphering_enabled::off); pdcp_rx_upper_control_interface& rrc_rx_if = pdcp->get_rx_upper_control_interface(); - rrc_rx_if.configure_security(sec_cfg); + rrc_rx_if.configure_security(sec_cfg, security::integrity_enabled::off, security::ciphering_enabled::off); // RLC rlc_config rlc_cnfg = get_rlc_config_from_args(args_); diff --git a/tests/unittests/pdcp/pdcp_rx_metrics_test.cpp b/tests/unittests/pdcp/pdcp_rx_metrics_test.cpp index 2b13c0e1a6..203596e66b 100644 --- a/tests/unittests/pdcp/pdcp_rx_metrics_test.cpp +++ b/tests/unittests/pdcp/pdcp_rx_metrics_test.cpp @@ -25,9 +25,7 @@ TEST_P(pdcp_rx_metrics_test, sdu_pdu_metrics) init(GetParam()); srsran::test_delimit_logger delimiter("RX PDU/SDU metrics tests. SN_SIZE={} COUNT={}", sn_size, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu; get_test_pdu(count, test_pdu); @@ -75,9 +73,7 @@ TEST_P(pdcp_rx_metrics_test, integrity_metrics) srsran::test_delimit_logger delimiter( "RX PDU with bad integrity metrics test. SN_SIZE={} COUNT={}", sn_size, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu; get_test_pdu(count, test_pdu); @@ -124,9 +120,7 @@ TEST_P(pdcp_rx_metrics_test, rx_reordering_timer) srsran::test_delimit_logger delimiter( "t-Reordering expiration metrics test. SN_SIZE={} COUNT=[{}, {}]", sn_size, count + 1, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); diff --git a/tests/unittests/pdcp/pdcp_rx_metrics_test.h b/tests/unittests/pdcp/pdcp_rx_metrics_test.h index b7a4926925..1aa5271429 100644 --- a/tests/unittests/pdcp/pdcp_rx_metrics_test.h +++ b/tests/unittests/pdcp/pdcp_rx_metrics_test.h @@ -10,12 +10,8 @@ #pragma once -#include "lib/pdcp/pdcp_entity_rx.h" #include "pdcp_rx_test_helpers.h" -#include "pdcp_test_vectors.h" -#include "srsran/pdcp/pdcp_config.h" #include -#include namespace srsran { diff --git a/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp b/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp index aad064f1a3..3419fa7a80 100644 --- a/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp +++ b/tests/unittests/pdcp/pdcp_rx_reestablish_test.cpp @@ -9,11 +9,7 @@ */ #include "pdcp_rx_reestablish_test.h" -#include "lib/pdcp/pdcp_entity_impl.h" -#include "pdcp_test_vectors.h" #include "srsran/pdcp/pdcp_config.h" -#include "srsran/support/bit_encoding.h" -#include "srsran/support/test_utils.h" #include #include @@ -28,9 +24,7 @@ TEST_P(pdcp_rx_reestablish_test, when_srb_reestablish_then_sdus_dropped) security::sec_128_as_config reest_sec_cfg = sec_cfg; reest_sec_cfg.integ_algo = security::integrity_algorithm::nia3; reest_sec_cfg.cipher_algo = security::ciphering_algorithm::nea3; - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); // Prepare 3 PDUs. byte_buffer test_pdu1; @@ -77,9 +71,7 @@ TEST_P(pdcp_rx_reestablish_test, when_drb_um_reestablish_then_pdus_forwared) init(GetParam(), pdcp_rb_type::drb, pdcp_rlc_mode::um); uint32_t count = 0; - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); // Prepare 3 PDUs. byte_buffer test_pdu1; @@ -126,9 +118,7 @@ TEST_P(pdcp_rx_reestablish_test, when_drb_am_reestablish_then_state_preserved) uint32_t count = 0; security::sec_128_as_config reest_sec_cfg = sec_cfg; - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); // Prepare 3 PDUs. byte_buffer test_pdu1; diff --git a/tests/unittests/pdcp/pdcp_rx_reestablish_test.h b/tests/unittests/pdcp/pdcp_rx_reestablish_test.h index e522e90625..dbb2099efb 100644 --- a/tests/unittests/pdcp/pdcp_rx_reestablish_test.h +++ b/tests/unittests/pdcp/pdcp_rx_reestablish_test.h @@ -10,12 +10,8 @@ #pragma once -#include "lib/pdcp/pdcp_entity_rx.h" #include "pdcp_rx_test_helpers.h" -#include "pdcp_test_vectors.h" -#include "srsran/pdcp/pdcp_config.h" #include -#include namespace srsran { diff --git a/tests/unittests/pdcp/pdcp_rx_status_report_test.cpp b/tests/unittests/pdcp/pdcp_rx_status_report_test.cpp index 76a2f7da58..a1e1355c79 100644 --- a/tests/unittests/pdcp/pdcp_rx_status_report_test.cpp +++ b/tests/unittests/pdcp/pdcp_rx_status_report_test.cpp @@ -9,9 +9,6 @@ */ #include "pdcp_rx_status_report_test.h" -#include "lib/pdcp/pdcp_entity_impl.h" -#include "pdcp_test_vectors.h" -#include "srsran/pdcp/pdcp_config.h" #include "srsran/support/bit_encoding.h" #include "srsran/support/test_utils.h" #include @@ -153,7 +150,7 @@ TEST_P(pdcp_rx_status_report_test, rx_status_report) { init(GetParam()); - pdcp_rx->configure_security(sec_cfg); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); ASSERT_TRUE(test_frame->status_report_queue.empty()); diff --git a/tests/unittests/pdcp/pdcp_rx_test.cpp b/tests/unittests/pdcp/pdcp_rx_test.cpp index 37f138903f..1f263af88e 100644 --- a/tests/unittests/pdcp/pdcp_rx_test.cpp +++ b/tests/unittests/pdcp/pdcp_rx_test.cpp @@ -9,7 +9,6 @@ */ #include "pdcp_rx_test.h" -#include "lib/pdcp/pdcp_entity_impl.h" #include "pdcp_test_vectors.h" #include "srsran/pdcp/pdcp_config.h" #include "srsran/support/test_utils.h" @@ -64,9 +63,7 @@ TEST_P(pdcp_rx_test, rx_in_order) auto test_rx_in_order = [this](uint32_t count) { srsran::test_delimit_logger delimiter("RX in order test. SN_SIZE={} COUNT={}", sn_size, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); @@ -106,9 +103,7 @@ TEST_P(pdcp_rx_test, rx_out_of_order) srsran::test_delimit_logger delimiter( "RX out-of-order test, no t-Reordering. SN_SIZE={} COUNT=[{}, {}]", sn_size, count + 1, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); @@ -161,9 +156,7 @@ TEST_P(pdcp_rx_test, rx_reordering_timer) srsran::test_delimit_logger delimiter( "RX out-of-order test, t-Reordering expires. SN_SIZE={} COUNT=[{}, {}]", sn_size, count + 1, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); @@ -204,9 +197,7 @@ TEST_P(pdcp_rx_test, rx_reordering_timer_0ms) srsran::test_delimit_logger delimiter( "RX out-of-order test, t-Reordering is set to 0. SN_SIZE={} COUNT=[{}, {}]", sn_size, count + 1, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); @@ -246,9 +237,7 @@ TEST_P(pdcp_rx_test, rx_reordering_timer_infinite) srsran::test_delimit_logger delimiter( "RX out-of-order test, t-Reordering is set to infinity. SN_SIZE={} COUNT=[{}, {}]", sn_size, count + 1, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); @@ -287,19 +276,17 @@ TEST_P(pdcp_rx_test, rx_integrity_fail) auto test_rx_integrity_fail = [this](uint32_t count) { srsran::test_delimit_logger delimiter("RX PDU with bad integrity. SN_SIZE={} COUNT={}", sn_size, count); - pdcp_rx->configure_security(sec_cfg); - pdcp_rx->set_integrity_protection(security::integrity_enabled::on); - pdcp_rx->set_ciphering(security::ciphering_enabled::on); + pdcp_rx->configure_security(sec_cfg, security::integrity_enabled::on, security::ciphering_enabled::on); byte_buffer test_pdu1; get_test_pdu(count, test_pdu1); ASSERT_TRUE(test_pdu1.append(0)); // mess up MAC-I pdcp_rx_state init_state = {.rx_next = count, .rx_deliv = count, .rx_reord = 0}; pdcp_rx->set_state(init_state); + uint32_t prev_integrity_fail_counter = test_frame->integrity_fail_counter; pdcp_rx->handle_pdu(byte_buffer_chain::create(std::move(test_pdu1)).value()); ASSERT_EQ(0, test_frame->sdu_queue.size()); - // TODO: Re-enable once the RRC supports notifications from the PDCP - // ASSERT_EQ(1, test_frame->integrity_fail_counter); + ASSERT_EQ(prev_integrity_fail_counter + 1, test_frame->integrity_fail_counter); }; if (sn_size == pdcp_sn_size::size12bits) { diff --git a/tests/unittests/pdcp/pdcp_rx_test.h b/tests/unittests/pdcp/pdcp_rx_test.h index 71cdcb050d..00eff815a5 100644 --- a/tests/unittests/pdcp/pdcp_rx_test.h +++ b/tests/unittests/pdcp/pdcp_rx_test.h @@ -10,12 +10,8 @@ #pragma once -#include "lib/pdcp/pdcp_entity_rx.h" #include "pdcp_rx_test_helpers.h" -#include "pdcp_test_vectors.h" -#include "srsran/pdcp/pdcp_config.h" #include -#include namespace srsran { From e3465c7cde5bf6efad5af99150921eb7a98acc87 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 12 Aug 2024 16:20:37 +0200 Subject: [PATCH 262/407] sec: add verify_integrity to NIA2 engine (variant with CMAC) --- lib/security/integrity_engine_nia2_cmac.cpp | 64 ++++++++++++++++----- lib/security/integrity_engine_nia2_cmac.h | 2 + 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/lib/security/integrity_engine_nia2_cmac.cpp b/lib/security/integrity_engine_nia2_cmac.cpp index c9585d2ef4..dec4c8d2bb 100644 --- a/lib/security/integrity_engine_nia2_cmac.cpp +++ b/lib/security/integrity_engine_nia2_cmac.cpp @@ -50,19 +50,16 @@ integrity_engine_nia2_cmac::~integrity_engine_nia2_cmac() mbedtls_cipher_free(&ctx); } -security_result integrity_engine_nia2_cmac::protect_integrity(byte_buffer buf, uint32_t count) +expected integrity_engine_nia2_cmac::compute_mac(const byte_buffer_view v, + uint32_t count) { - security_result result{.buf = std::move(buf), .count = count}; security::sec_mac mac = {}; - byte_buffer_view v{result.buf.value().begin(), result.buf.value().end()}; - // reset state machine int ret; ret = mbedtls_cipher_cmac_reset(&ctx); if (ret != 0) { - result.buf = make_unexpected(security_error::integrity_failure); - return result; + return make_unexpected(security_error::integrity_failure); } // process preamble @@ -74,8 +71,7 @@ security_result integrity_engine_nia2_cmac::protect_integrity(byte_buffer buf, u preamble[4] = (bearer_id << 3) | (to_number(direction) << 2); ret = mbedtls_cipher_cmac_update(&ctx, preamble.data(), preamble.size()); if (ret != 0) { - result.buf = make_unexpected(security_error::integrity_failure); - return result; + return make_unexpected(security_error::integrity_failure); } // process PDU segments @@ -83,8 +79,7 @@ security_result integrity_engine_nia2_cmac::protect_integrity(byte_buffer buf, u for (const auto& segment : segments) { ret = mbedtls_cipher_cmac_update(&ctx, segment.data(), segment.size()); if (ret != 0) { - result.buf = make_unexpected(security_error::integrity_failure); - return result; + return make_unexpected(security_error::integrity_failure); } } @@ -92,22 +87,63 @@ security_result integrity_engine_nia2_cmac::protect_integrity(byte_buffer buf, u std::array tmp_mac; ret = mbedtls_cipher_cmac_finish(&ctx, tmp_mac.data()); if (ret != 0) { - result.buf = make_unexpected(security_error::integrity_failure); - return result; + return make_unexpected(security_error::integrity_failure); } // copy first 4 bytes std::copy(tmp_mac.begin(), tmp_mac.begin() + 4, mac.begin()); - if (not result.buf->append(mac)) { + return mac; +} + +security_result integrity_engine_nia2_cmac::protect_integrity(byte_buffer buf, uint32_t count) +{ + security_result result{.buf = std::move(buf), .count = count}; + byte_buffer_view v{result.buf.value().begin(), result.buf.value().end()}; + + expected mac = compute_mac(v, count); + + if (not mac.has_value()) { + result.buf = make_unexpected(mac.error()); + return result; + } + + if (not result.buf->append(mac.value())) { result.buf = make_unexpected(security_error::buffer_failure); } + return result; } security_result integrity_engine_nia2_cmac::verify_integrity(byte_buffer buf, uint32_t count) { - security_result result; + security_result result{.buf = std::move(buf), .count = count}; + + if (result.buf->length() <= sec_mac_len) { + result.buf = make_unexpected(security_error::integrity_failure); + return result; + } + + byte_buffer_view v{result.buf.value(), 0, result.buf.value().length() - sec_mac_len}; + byte_buffer_view m{result.buf.value(), result.buf.value().length() - sec_mac_len, sec_mac_len}; + + // compute MAC + expected mac = compute_mac(v, count); + + if (not mac.has_value()) { + result.buf = make_unexpected(mac.error()); + return result; + } + + // verify MAC + if (!std::equal(mac.value().begin(), mac.value().end(), m.begin(), m.end())) { + result.buf = make_unexpected(security_error::integrity_failure); + return result; + } + + // trim MAC from PDU + result.buf.value().trim_tail(sec_mac_len); + return result; } diff --git a/lib/security/integrity_engine_nia2_cmac.h b/lib/security/integrity_engine_nia2_cmac.h index c6b483ebc8..776684f256 100644 --- a/lib/security/integrity_engine_nia2_cmac.h +++ b/lib/security/integrity_engine_nia2_cmac.h @@ -32,6 +32,8 @@ class integrity_engine_nia2_cmac final : public integrity_engine security_result verify_integrity(byte_buffer buf, uint32_t count) override; private: + expected compute_mac(const byte_buffer_view v, uint32_t count); + sec_128_key k_128_int; uint8_t bearer_id; security_direction direction; From ee4762bb7d4df93f626ec8b0716a8d1c2c3adf8a Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 12 Aug 2024 16:27:18 +0200 Subject: [PATCH 263/407] sec: add verify_integrity to NIA2 engine (variant without CMAC) --- .../integrity_engine_nia2_non_cmac.cpp | 52 ++++++++++++++++--- lib/security/integrity_engine_nia2_non_cmac.h | 2 + 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/lib/security/integrity_engine_nia2_non_cmac.cpp b/lib/security/integrity_engine_nia2_non_cmac.cpp index 08ed1b3bca..5b4fa48037 100644 --- a/lib/security/integrity_engine_nia2_non_cmac.cpp +++ b/lib/security/integrity_engine_nia2_non_cmac.cpp @@ -47,13 +47,11 @@ integrity_engine_nia2_non_cmac::integrity_engine_nia2_non_cmac(sec_128_key } } -security_result integrity_engine_nia2_non_cmac::protect_integrity(byte_buffer buf, uint32_t count) +expected integrity_engine_nia2_non_cmac::compute_mac(const byte_buffer_view v, + uint32_t count) { - security_result result{.buf = std::move(buf), .count = count}; security::sec_mac mac = {}; - byte_buffer_view v{result.buf.value().begin(), result.buf.value().end()}; - uint32_t len = v.length(); uint32_t len_bits = len * 8; @@ -106,14 +104,56 @@ security_result integrity_engine_nia2_non_cmac::protect_integrity(byte_buffer bu // copy first 4 bytes std::copy(tmp_mac.begin(), tmp_mac.begin() + 4, mac.begin()); - if (not result.buf->append(mac)) { + return mac; +} + +security_result integrity_engine_nia2_non_cmac::protect_integrity(byte_buffer buf, uint32_t count) +{ + security_result result{.buf = std::move(buf), .count = count}; + byte_buffer_view v{result.buf.value().begin(), result.buf.value().end()}; + + expected mac = compute_mac(v, count); + + if (not mac.has_value()) { + result.buf = make_unexpected(mac.error()); + return result; + } + + if (not result.buf->append(mac.value())) { result.buf = make_unexpected(security_error::buffer_failure); } + return result; } security_result integrity_engine_nia2_non_cmac::verify_integrity(byte_buffer buf, uint32_t count) { - security_result result; + security_result result{.buf = std::move(buf), .count = count}; + + if (result.buf->length() <= sec_mac_len) { + result.buf = make_unexpected(security_error::integrity_failure); + return result; + } + + byte_buffer_view v{result.buf.value(), 0, result.buf.value().length() - sec_mac_len}; + byte_buffer_view m{result.buf.value(), result.buf.value().length() - sec_mac_len, sec_mac_len}; + + // compute MAC + expected mac = compute_mac(v, count); + + if (not mac.has_value()) { + result.buf = make_unexpected(mac.error()); + return result; + } + + // verify MAC + if (!std::equal(mac.value().begin(), mac.value().end(), m.begin(), m.end())) { + result.buf = make_unexpected(security_error::integrity_failure); + return result; + } + + // trim MAC from PDU + result.buf.value().trim_tail(sec_mac_len); + return result; } diff --git a/lib/security/integrity_engine_nia2_non_cmac.h b/lib/security/integrity_engine_nia2_non_cmac.h index a44b766601..c2bf0e4e3f 100644 --- a/lib/security/integrity_engine_nia2_non_cmac.h +++ b/lib/security/integrity_engine_nia2_non_cmac.h @@ -29,6 +29,8 @@ class integrity_engine_nia2_non_cmac final : public integrity_engine security_result verify_integrity(byte_buffer buf, uint32_t count) override; private: + expected compute_mac(const byte_buffer_view v, uint32_t count); + sec_128_key k_128_int; uint8_t bearer_id; security_direction direction; From d0119de1f79c85435e2baf73d2cf498ae6040e20 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 12 Aug 2024 16:44:03 +0200 Subject: [PATCH 264/407] sec: unit test all variants of verify_integrity --- .../security/integrity_engine_test.cpp | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/unittests/security/integrity_engine_test.cpp b/tests/unittests/security/integrity_engine_test.cpp index 7075351d1a..41c3902e25 100644 --- a/tests/unittests/security/integrity_engine_test.cpp +++ b/tests/unittests/security/integrity_engine_test.cpp @@ -130,6 +130,16 @@ TEST_P(fxt_nia1, integrity_engine_generic_nia1) EXPECT_EQ(result.buf.value(), prot_buf); EXPECT_EQ(result.count, param.count_i); } + + // Verify integrity + for (unsigned i = 0; i < 2; i++) { + security_result result = nia->verify_integrity(prot_buf.deep_copy().value(), param.count_i); + ASSERT_TRUE(result.buf.has_value()); + logger.info(result.buf.value().begin(), result.buf.value().end(), "result:"); + logger.info(message.begin(), message.end(), "exp:"); + EXPECT_EQ(result.buf.value(), message); + EXPECT_EQ(result.count, param.count_i); + } } #ifdef MBEDTLS_CMAC_C @@ -157,6 +167,16 @@ TEST_P(fxt_nia2, integrity_engine_nia2_cmac) EXPECT_EQ(result.buf.value(), prot_buf); EXPECT_EQ(result.count, param.count_i); } + + // Verify integrity + for (unsigned i = 0; i < 2; i++) { + security_result result = nia->verify_integrity(prot_buf.deep_copy().value(), param.count_i); + ASSERT_TRUE(result.buf.has_value()); + logger.info(result.buf.value().begin(), result.buf.value().end(), "result:"); + logger.info(message.begin(), message.end(), "exp:"); + EXPECT_EQ(result.buf.value(), message); + EXPECT_EQ(result.count, param.count_i); + } } #endif // MBEDTLS_CMAC_C @@ -184,6 +204,16 @@ TEST_P(fxt_nia2, integrity_engine_nia2_non_cmac) EXPECT_EQ(result.buf.value(), prot_buf); EXPECT_EQ(result.count, param.count_i); } + + // Verify integrity + for (unsigned i = 0; i < 2; i++) { + security_result result = nia->verify_integrity(prot_buf.deep_copy().value(), param.count_i); + ASSERT_TRUE(result.buf.has_value()); + logger.info(result.buf.value().begin(), result.buf.value().end(), "result:"); + logger.info(message.begin(), message.end(), "exp:"); + EXPECT_EQ(result.buf.value(), message); + EXPECT_EQ(result.count, param.count_i); + } } TEST_P(fxt_nia2, integrity_engine_generic_nia2) @@ -211,6 +241,16 @@ TEST_P(fxt_nia2, integrity_engine_generic_nia2) EXPECT_EQ(result.buf.value(), prot_buf); EXPECT_EQ(result.count, param.count_i); } + + // Verify integrity + for (unsigned i = 0; i < 2; i++) { + security_result result = nia->verify_integrity(prot_buf.deep_copy().value(), param.count_i); + ASSERT_TRUE(result.buf.has_value()); + logger.info(result.buf.value().begin(), result.buf.value().end(), "result:"); + logger.info(message.begin(), message.end(), "exp:"); + EXPECT_EQ(result.buf.value(), message); + EXPECT_EQ(result.count, param.count_i); + } } TEST_P(fxt_nia3, integrity_engine_generic_nia3) @@ -238,6 +278,16 @@ TEST_P(fxt_nia3, integrity_engine_generic_nia3) EXPECT_EQ(result.buf.value(), prot_buf); EXPECT_EQ(result.count, param.count_i); } + + // Verify integrity + for (unsigned i = 0; i < 2; i++) { + security_result result = nia->verify_integrity(prot_buf.deep_copy().value(), param.count_i); + ASSERT_TRUE(result.buf.has_value()); + logger.info(result.buf.value().begin(), result.buf.value().end(), "result:"); + logger.info(message.begin(), message.end(), "exp:"); + EXPECT_EQ(result.buf.value(), message); + EXPECT_EQ(result.count, param.count_i); + } } ////////////////////////////////////////////////////////// From 2020efc694d65a885fd1b4db54b7f9d7b21b8b28 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 13 Aug 2024 15:15:04 +0200 Subject: [PATCH 265/407] pdcp: add const to testing helpers --- lib/pdcp/pdcp_entity_rx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index aff48b76eb..7841963804 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -98,8 +98,8 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, * Testing Helpers */ void set_state(pdcp_rx_state st_) { st = st_; } - pdcp_rx_state get_state() { return st; } - bool is_reordering_timer_running() { return reordering_timer.is_running(); } + pdcp_rx_state get_state() const { return st; } + bool is_reordering_timer_running() const { return reordering_timer.is_running(); } private: pdcp_bearer_logger logger; From 98448dd0a38a7ae56ce2e9a58100c6c7cafc3511 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 12 Aug 2024 11:31:10 +0200 Subject: [PATCH 266/407] phy: optimize LDPC encoder --- .../channel_coding/ldpc/ldpc_encoder_avx2.cpp | 21 +++++++++---------- .../channel_coding/ldpc/ldpc_encoder_neon.cpp | 21 +++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp index 42fb7e351d..dbff6f6c57 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_avx2.cpp @@ -177,12 +177,12 @@ static void fast_xor(span out, span in0, span in1) template void ldpc_encoder_avx2::systematic_bits_inner() { - mm256::avx2_const_span codeblock(codeblock_buffer, codeblock_used_size); + static constexpr unsigned node_size_byte = NODE_SIZE_AVX2_PH * AVX2_SIZE_BYTE; + mm256::avx2_const_span codeblock(codeblock_buffer, codeblock_used_size); + mm256::avx2_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_AVX2_PH); - mm256::avx2_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_AVX2_PH); - - std::array tmp_blk; - span blk = span(tmp_blk).first(2 * lifting_size); + std::array tmp_blk = {}; + span blk = span(tmp_blk); for (unsigned m = 0; m != bg_hr_parity_nodes; ++m) { const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); @@ -200,15 +200,14 @@ void ldpc_encoder_avx2::systematic_bits_inner() unsigned i_aux = m * NODE_SIZE_AVX2_PH; unsigned i_blk = k * NODE_SIZE_AVX2_PH; - srsvec::copy(blk.first(lifting_size), codeblock.plain_span(i_blk, lifting_size)); - srsvec::copy(blk.last(lifting_size), codeblock.plain_span(i_blk, lifting_size)); - - span plain_auxiliary = auxiliary.plain_span(i_aux, lifting_size); + span plain_auxiliary = auxiliary.plain_span(i_aux, node_size_byte); if (k == row[0]) { - srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); + srsvec::circ_shift_backward( + plain_auxiliary.first(lifting_size), codeblock.plain_span(i_blk, lifting_size), node_shift); } else { - fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); + srsvec::circ_shift_backward(blk.first(lifting_size), codeblock.plain_span(i_blk, lifting_size), node_shift); + fast_xor(plain_auxiliary, blk, plain_auxiliary); } } } diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp index a6a92ec0df..a3267954ee 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_encoder_neon.cpp @@ -154,12 +154,12 @@ static void fast_xor(span out, span in0, span in1) template void ldpc_encoder_neon::systematic_bits_inner() { - neon::neon_const_span codeblock(codeblock_buffer, codeblock_used_size); + static constexpr unsigned node_size_byte = NODE_SIZE_NEON_PH * NEON_SIZE_BYTE; + neon::neon_const_span codeblock(codeblock_buffer, codeblock_used_size); + neon::neon_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_NEON_PH); - neon::neon_span auxiliary(auxiliary_buffer, bg_hr_parity_nodes * NODE_SIZE_NEON_PH); - - std::array tmp_blk; - span blk = span(tmp_blk).first(2 * lifting_size); + std::array tmp_blk = {}; + span blk = span(tmp_blk); for (unsigned m = 0; m != bg_hr_parity_nodes; ++m) { const ldpc::BG_adjacency_row_t& row = current_graph->get_adjacency_row(m); @@ -177,15 +177,14 @@ void ldpc_encoder_neon::systematic_bits_inner() unsigned i_aux = m * NODE_SIZE_NEON_PH; unsigned i_blk = k * NODE_SIZE_NEON_PH; - srsvec::copy(blk.first(lifting_size), codeblock.plain_span(i_blk, lifting_size)); - srsvec::copy(blk.last(lifting_size), codeblock.plain_span(i_blk, lifting_size)); - - span plain_auxiliary = auxiliary.plain_span(i_aux, lifting_size); + span plain_auxiliary = auxiliary.plain_span(i_aux, node_size_byte); if (k == row[0]) { - srsvec::copy(plain_auxiliary, blk.subspan(node_shift, lifting_size)); + srsvec::circ_shift_backward( + plain_auxiliary.first(lifting_size), codeblock.plain_span(i_blk, lifting_size), node_shift); } else { - fast_xor(plain_auxiliary, blk.subspan(node_shift, lifting_size), plain_auxiliary); + srsvec::circ_shift_backward(blk.first(lifting_size), codeblock.plain_span(i_blk, lifting_size), node_shift); + fast_xor(plain_auxiliary, blk, plain_auxiliary); } } } From e071d2c96282736592a846be39e94d2a097226a3 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 12 Aug 2024 13:27:47 +0200 Subject: [PATCH 267/407] ci: remove Ubuntu 20.04 Cause: Generic build (march=x86-64) with Clang 10 has issues with `vmovlpd` which is part of AVX instruction set. --- .gitlab/ci/build.yml | 146 +--------------------------------------- .gitlab/ci/builders.yml | 100 +++------------------------ 2 files changed, 13 insertions(+), 233 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index c6f30c3454..d640d3417f 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -36,7 +36,6 @@ variables: - "ubuntu-24.04" - "ubuntu-23.10" - "ubuntu-22.04" - - "ubuntu-20.04" - "debian-12" - "debian-11" - "archlinux-latest" @@ -926,8 +925,6 @@ package: tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - - OS_VERSION: "20.04" - extraopts: -DMARCH=x86-64 -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" @@ -946,7 +943,6 @@ install-package: - gnb --version parallel: matrix: - - OS_VERSION: "20.04" - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" @@ -975,12 +971,9 @@ export on amd64: tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04, ubuntu-20.04] + - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v3 - # - OS: ubuntu-20.04 - # MARCH: x86-64 - # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" export on amd64 avx512: extends: export on amd64 @@ -989,9 +982,6 @@ export on amd64 avx512: matrix: - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v4 - # - OS: ubuntu-20.04 - # MARCH: x86-64 - # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" # Build + unit tests combinations @@ -1065,21 +1055,6 @@ ubuntu-22.04 amd64 avx2: <<: *basic_combinations MARCH: x86-64-v3 -# ubuntu-20.04 amd64 avx2: -# extends: .build_and_unit -# rules: -# - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ -# when: delayed -# start_in: 210 minutes -# interruptible: false -# tags: ["${AMD64_AVX2_TAG}"] -# parallel: -# matrix: -# - OS: ubuntu-20.04 -# <<: *basic_combinations -# MARCH: x86-64 -# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" - rhel-8 amd64 avx2: extends: .build_and_unit rules: @@ -1151,11 +1126,6 @@ ubuntu dpdk: - OS: ubuntu-22.04 COMPILER: [gcc, clang] DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] - # - OS: ubuntu-20.04 - # COMPILER: [gcc, clang] - # DPDK_VERSION: ["22.11.3", "23.11"] - # MARCH: x86-64 - # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" ################### # Alternative OSs # @@ -1304,14 +1274,13 @@ debian 11 amd64 avx512: BUILD_TYPE: Debug parallel: matrix: - # ubuntu-20.04 disabled due to https://bugs.launchpad.net/ubuntu/+source/gcc-9/+bug/2029910 # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan COMPILER: [gcc, clang] ENABLE_TSAN: "True" TEST_MODE: default - - OS: [ubuntu-22.04, ubuntu-20.04] + - OS: [ubuntu-22.04] SANITIZER: asan COMPILER: [gcc, clang] ENABLE_ASAN: "True" @@ -1331,14 +1300,13 @@ sanitizers amd64 native: tags: ["${AMD64_TAG}"] parallel: matrix: - # ubuntu-20.04 disabled due to https://bugs.launchpad.net/ubuntu/+source/gcc-9/+bug/2029910 # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan COMPILER: [gcc, clang] ENABLE_TSAN: "True" TEST_MODE: default - - OS: [ubuntu-22.04, ubuntu-20.04] + - OS: [ubuntu-22.04] SANITIZER: asan COMPILER: [gcc, clang] ENABLE_ASAN: "True" @@ -1357,7 +1325,6 @@ sanitizers amd64 avx2: tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - # ubuntu-20.04 disabled due to https://bugs.launchpad.net/ubuntu/+source/gcc-9/+bug/2029910 # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan @@ -1369,13 +1336,6 @@ sanitizers amd64 avx2: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - # - OS: ubuntu-20.04 - # SANITIZER: asan - # COMPILER: [gcc, clang] - # ENABLE_ASAN: "True" - # TEST_MODE: default - # MARCH: x86-64 - # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang @@ -1393,7 +1353,6 @@ sanitizers amd64 avx512: tags: ["${AMD64_AVX512_TAG}"] parallel: matrix: - # ubuntu-20.04 disabled due to https://bugs.launchpad.net/ubuntu/+source/gcc-9/+bug/2029910 # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan @@ -1405,13 +1364,6 @@ sanitizers amd64 avx512: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - # - OS: ubuntu-20.04 - # SANITIZER: asan - # COMPILER: [gcc, clang] - # ENABLE_ASAN: "True" - # TEST_MODE: default - # MARCH: x86-64 - # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" - OS: [ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang @@ -1452,11 +1404,6 @@ build uhd alt: - OS: ubuntu-22.04 COMPILER: [gcc, clang] UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] - # - OS: ubuntu-20.04 - # COMPILER: [gcc, clang] - # UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] - # MARCH: x86-64 - # BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" # Build + unit tests combinations @@ -1566,61 +1513,6 @@ ubuntu-22.04 arm neon: <<: *basic_combinations MARCH: armv8.2-a+crypto+fp16+dotprod -ubuntu-20.04 amd64 native: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 90 minutes - interruptible: false - tags: ["${AMD64_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations - -# ubuntu-20.04 amd64 avx512: -# extends: .build_and_unit -# rules: -# - if: $CI_DESCRIPTION =~ /Weekly/ -# when: delayed -# start_in: 90 minutes -# interruptible: false -# tags: ["${AMD64_AVX512_TAG}"] -# parallel: -# matrix: -# - OS: ubuntu-20.04 -# <<: *basic_combinations -# MARCH: x86-64 -# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" - -ubuntu-20.04 arm native: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 90 minutes - interruptible: false - tags: ["${ARM64_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations - -ubuntu-20.04 arm neon: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Weekly/ - when: delayed - start_in: 90 minutes - interruptible: false - tags: ["${ARM64_TAG}"] - parallel: - matrix: - - OS: ubuntu-20.04 - <<: *basic_combinations - MARCH: armv8.2-a+crypto+fp16+dotprod - rhel-8 amd64 native: extends: .build_and_unit rules: @@ -1684,38 +1576,6 @@ rhel-8 arm neon: ENABLE_DPDK: "True" COMPILER: [gcc, clang] -# ubuntu-20.04 amd64 avx2 dpdk: -# extends: .build_and_unit -# rules: -# - if: $CI_DESCRIPTION =~ /Weekly/ -# when: delayed -# start_in: 180 minutes -# interruptible: false -# tags: ["${AMD64_AVX2_TAG}"] -# parallel: -# matrix: -# - OS: ubuntu-20.04 -# <<: *basic_combinations_dpdk -# DPDK_VERSION: ["22.11.3", "23.11"] -# MARCH: x86-64 -# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt" - -# ubuntu-20.04 amd64 avx512 dpdk: -# extends: .build_and_unit -# rules: -# - if: $CI_DESCRIPTION =~ /Weekly/ -# when: delayed -# start_in: 210 minutes -# interruptible: false -# tags: ["${AMD64_AVX512_TAG}"] -# parallel: -# matrix: -# - OS: ubuntu-20.04 -# <<: *basic_combinations_dpdk -# DPDK_VERSION: ["22.11.3", "23.11"] -# MARCH: x86-64 -# BUILD_ARGS: -DCMAKE_CXX_FLAGS="-mavx2 -mbmi -mbmi2 -mmovbe -mfma -mlzcnt -mavx512f -mavx512dq -mavx512ifma -mavx512pf -mavx512er -mavx512cd -mavx512bw -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512vnni -mavx512bitalg -mavx512vpopcntdq" - ubuntu-22.04 amd64 avx2 dpdk: extends: .build_and_unit rules: diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index 1be5d3580f..eefe1dfeb1 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -110,9 +110,6 @@ tox python in builder: expire_in: 8 hours parallel: matrix: - - &uhd_2004_matrix - os_version: "20.04" - uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] # uhd 3.15.0.0 default - &uhd_2204_matrix os_version: "22.04" uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0"] # "4.1.0.5" default @@ -131,7 +128,7 @@ ubuntu-uhd-builder no isa: target_arch: x86-64 # x86-64-vX not supported in compilers' versions parallel: matrix: - - *uhd_2004_matrix + - *uhd_2204_matrix ubuntu-uhd-builder avx2: extends: .ubuntu-uhd-builder @@ -223,9 +220,9 @@ ubuntu-uhd-builder arm64: expire_in: 8 hours parallel: matrix: - - &dpdk_2004_matrix - os_version: "20.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] + - &dpdk_2204_no_isa_matrix + os_version: "22.04" + dpdk_version: ["22.11.3", "23.11"] - &dpdk_2204_matrix os_version: "22.04" dpdk_version: ["21.08", "22.11.3", "23.11"] @@ -245,7 +242,7 @@ ubuntu-dpdk-builder no isa: target_arch: x86-64 parallel: matrix: - - *dpdk_2004_matrix + - *dpdk_2204_no_isa_matrix ubuntu-dpdk-builder avx2: extends: .ubuntu-dpdk-builder @@ -388,88 +385,6 @@ alternative-tag [codechecker]: - builder version - image-build-publish [codechecker] -################################################################################ -# Ubuntu 20.04 -################################################################################ -image-build-publish [ubuntu, 20.04, amd64]: - extends: - - .image-build-publish - variables: - OS_FAMILY: debian - OS_NAME: ubuntu - OS_VERSION: "20.04" - PLATFORM: amd64 - needs: - - builder version - - job: ubuntu-uhd-builder no isa - parallel: - matrix: - - os_version: "20.04" - uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] - - job: ubuntu-dpdk-builder no isa - parallel: - matrix: - - os_version: "20.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] - -alternative-tag [ubuntu, 20.04, amd64]: - extends: - - .alternative-tag - variables: - OS_NAME: ubuntu - OS_VERSION: "20.04" - VERSION: ${DOCKER_BUILDER_VERSION}-amd64 - needs: - - builder version - - image-build-publish [ubuntu, 20.04, amd64] - -image-build-publish [ubuntu, 20.04, arm64]: - extends: - - .image-build-publish - variables: - OS_FAMILY: debian - OS_NAME: ubuntu - OS_VERSION: "20.04" - PLATFORM: arm64 - needs: - - builder version - - job: ubuntu-uhd-builder arm64 - parallel: - matrix: - - os_version: "20.04" - uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] - - job: ubuntu-dpdk-builder arm64 - parallel: - matrix: - - os_version: "20.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] - -alternative-tag [ubuntu, 20.04, arm64]: - extends: - - .alternative-tag - variables: - OS_NAME: ubuntu - OS_VERSION: "20.04" - VERSION: ${DOCKER_BUILDER_VERSION}-arm64 - needs: - - builder version - - image-build-publish [ubuntu, 20.04, arm64] - -manifest [ubuntu, 20.04]: - extends: .manifest - variables: - OS_NAME: ubuntu - OS_VERSION: "20.04" - needs: - - builder version - - job: alternative-tag [ubuntu, 20.04, amd64] - optional: false - - job: alternative-tag [ubuntu, 20.04, arm64] - optional: false - parallel: - matrix: - - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] - ################################################################################ # Ubuntu 22.04 ################################################################################ @@ -488,6 +403,11 @@ image-build-publish [ubuntu, 22.04, amd64]: matrix: - os_version: "22.04" uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0"] + - job: ubuntu-dpdk-builder no isa + parallel: + matrix: + - os_version: "22.04" + dpdk_version: ["22.11.3", "23.11"] - job: ubuntu-dpdk-builder avx2 parallel: matrix: From 49ef6bc48afd43e82390843143f6d05eb5339469 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 14 Aug 2024 10:59:32 +0200 Subject: [PATCH 268/407] cu-up: change mechanism to shut down CU-UP UE executor mapper --- lib/cu_up/cu_up_executor_pool.cpp | 165 +++++++++++++++++------------- 1 file changed, 93 insertions(+), 72 deletions(-) diff --git a/lib/cu_up/cu_up_executor_pool.cpp b/lib/cu_up/cu_up_executor_pool.cpp index bf1c540224..b95a5b4bf9 100644 --- a/lib/cu_up/cu_up_executor_pool.cpp +++ b/lib/cu_up/cu_up_executor_pool.cpp @@ -14,88 +14,97 @@ using namespace srsran; using namespace srs_cu_up; -class cu_up_executor_pool_impl final : public cu_up_executor_pool +namespace { + +/// Task executor adaptor that allows cancelling pending tasks, from within the executor's context. +class cancellable_task_executor final : public task_executor { - struct ue_executor_context { - task_executor& ctrl_exec; - task_executor& ul_exec; - task_executor& dl_exec; - task_executor& crypto_exec; +public: + cancellable_task_executor(task_executor& exec_) : exec(&exec_) {} - ue_executor_context(task_executor& ctrl_exec_, - task_executor& ul_exec_, - task_executor& dl_exec_, - task_executor& crypto_exec_) : - ctrl_exec(ctrl_exec_), ul_exec(ul_exec_), dl_exec(dl_exec_), crypto_exec(crypto_exec_) - { - } - }; + /// \brief Cancel pending tasks. + /// Note: This needs to be called from within the executor's context. + void cancel() { cancelled = true; } -public: - /// Implementation of the UE executor mapper. - class ue_executor_mapper_impl final : public ue_executor_mapper + [[nodiscard]] bool execute(unique_task task) override { - public: - ue_executor_mapper_impl(cu_up_executor_pool_impl& parent_, ue_executor_context& ctxt_) : - parent(parent_), ctxt(&ctxt_) - { - } + return exec->execute([this, task = std::move(task)]() { + if (cancelled) { + return; + } + task(); + }); + } - ~ue_executor_mapper_impl() override { parent.release_ue_executors(*ctxt); } + [[nodiscard]] bool defer(unique_task task) override + { + return exec->defer([this, task = std::move(task)]() { + if (cancelled) { + return; + } + task(); + }); + } - async_task stop() override - { - ue_executor_context* ctxt_tmp = nullptr; - return launch_async([this, ctxt_tmp](coro_context>& ctx) mutable { - CORO_BEGIN(ctx); +private: + task_executor* exec; + bool cancelled = false; +}; - // Switch to the UE execution context. - CORO_AWAIT(defer_to_blocking(ctxt->ctrl_exec)); +/// Implementation of the UE executor mapper. +class ue_executor_mapper_impl final : public ue_executor_mapper +{ +public: + ue_executor_mapper_impl(task_executor& ctrl_exec_, + task_executor& ul_exec_, + task_executor& dl_exec_, + task_executor& crypto_exec_, + task_executor& main_exec_) : + ctrl_exec(ctrl_exec_), ul_exec(ul_exec_), dl_exec(dl_exec_), crypto_exec(crypto_exec_), main_exec(main_exec_) + { + } - // Make executors inaccessible via the ue_executor_mapper_impl public interface. - // Any public access after this point should assert. - ctxt_tmp = std::exchange(ctxt, nullptr); + ~ue_executor_mapper_impl() override = default; - // Synchronize with remaining executors to ensure there are no more pending tasks for this UE. - CORO_AWAIT(defer_to_blocking(ctxt_tmp->ul_exec)); - CORO_AWAIT(defer_to_blocking(ctxt_tmp->dl_exec)); + async_task stop() override + { + return launch_async([this](coro_context>& ctx) mutable { + CORO_BEGIN(ctx); - // Return back to main control execution context. - CORO_AWAIT(defer_to_blocking(parent.main_exec)); + // Switch to the UE execution context. + CORO_AWAIT(defer_to_blocking(ctrl_exec)); - // Finally, deregister UE executors. - parent.release_ue_executors(*ctxt_tmp); + // Cancel all pending tasks. + // Note: this operation is only thread-safe because we are calling it from the UE executor's context. + ctrl_exec.cancel(); + ul_exec.cancel(); + dl_exec.cancel(); - CORO_RETURN(); - }); - } + // Return back to main control execution context. + CORO_AWAIT(defer_to_blocking(main_exec)); - task_executor& ctrl_executor() override - { - srsran_assert(ctxt != nullptr, "UE executor mapper already stopped"); - return ctxt->ctrl_exec; - } - task_executor& ul_pdu_executor() override - { - srsran_assert(ctxt != nullptr, "UE executor mapper already stopped"); - return ctxt->ul_exec; - } - task_executor& dl_pdu_executor() override - { - srsran_assert(ctxt != nullptr, "UE executor mapper already stopped"); - return ctxt->dl_exec; - } - task_executor& crypto_executor() override - { - srsran_assert(ctxt != nullptr, "UE executor mapper already stopped"); - return ctxt->crypto_exec; - } + CORO_RETURN(); + }); + } - private: - cu_up_executor_pool_impl& parent; - ue_executor_context* ctxt; - }; + task_executor& ctrl_executor() override { return ctrl_exec; } + task_executor& ul_pdu_executor() override { return ul_exec; } + task_executor& dl_pdu_executor() override { return dl_exec; } + task_executor& crypto_executor() override { return crypto_exec; } + +private: + cancellable_task_executor ctrl_exec; + cancellable_task_executor ul_exec; + cancellable_task_executor dl_exec; + task_executor& crypto_exec; + task_executor& main_exec; +}; +} // namespace + +class cu_up_executor_pool_impl final : public cu_up_executor_pool +{ +public: cu_up_executor_pool_impl(task_executor& cu_up_main_exec, span dl_executors, span ul_executors, @@ -124,15 +133,26 @@ class cu_up_executor_pool_impl final : public cu_up_executor_pool std::unique_ptr create_ue_executor_mapper() override { + auto& ctxt = execs[round_robin_index.fetch_add(1, std::memory_order_relaxed) % execs.size()]; return std::make_unique( - *this, execs[round_robin_index.fetch_add(1, std::memory_order_relaxed) % execs.size()]); + ctxt.ctrl_exec, ctxt.ul_exec, ctxt.dl_exec, ctxt.crypto_exec, main_exec); } private: - void release_ue_executors(ue_executor_context& ue_execs) - { - // do nothing. - } + struct ue_executor_context { + task_executor& ctrl_exec; + task_executor& ul_exec; + task_executor& dl_exec; + task_executor& crypto_exec; + + ue_executor_context(task_executor& ctrl_exec_, + task_executor& ul_exec_, + task_executor& dl_exec_, + task_executor& crypto_exec_) : + ctrl_exec(ctrl_exec_), ul_exec(ul_exec_), dl_exec(dl_exec_), crypto_exec(crypto_exec_) + { + } + }; // Main executor of the CU-UP. task_executor& main_exec; @@ -140,6 +160,7 @@ class cu_up_executor_pool_impl final : public cu_up_executor_pool // List of UE executor mapper contexts created. std::vector execs; + // A round-robin algorithm is used to distribute executors to UEs. std::atomic round_robin_index{0}; }; From 3c47cf64cf7ad515caf5c8ac36f2a53eacb4c543 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 14 Aug 2024 09:48:54 +0200 Subject: [PATCH 269/407] cu_cp,rrc: fix unit tests --- .../rrc_measurement_types_asn1_converters.cpp | 24 +++++++++++++++---- .../cell_meas_manager_test_helpers.cpp | 6 +++++ .../cu_cp/cu_cp_test_environment.cpp | 2 ++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp b/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp index 9e939cb6c6..3294895d02 100644 --- a/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp @@ -844,7 +844,11 @@ srsran::srs_cu_cp::event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigge asn1_event_a3.report_on_leave = event_id.report_on_leave; asn1_event_a3.hysteresis = event_id.hysteresis; asn1::number_to_enum(asn1_event_a3.time_to_trigger, event_id.time_to_trigger); - asn1_event_a3.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + if (event_id.use_allowed_cell_list.has_value()) { + asn1_event_a3.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } else { + asn1_event_a3.use_allowed_cell_list = false; + } } // event a4 @@ -854,7 +858,11 @@ srsran::srs_cu_cp::event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigge asn1_event_a4.report_on_leave = event_id.report_on_leave; asn1_event_a4.hysteresis = event_id.hysteresis; asn1::number_to_enum(asn1_event_a4.time_to_trigger, event_id.time_to_trigger); - asn1_event_a4.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + if (event_id.use_allowed_cell_list.has_value()) { + asn1_event_a4.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } else { + asn1_event_a4.use_allowed_cell_list = false; + } } // event a5 @@ -865,7 +873,11 @@ srsran::srs_cu_cp::event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigge asn1_event_a5.report_on_leave = event_id.report_on_leave; asn1_event_a5.hysteresis = event_id.hysteresis; asn1::number_to_enum(asn1_event_a5.time_to_trigger, event_id.time_to_trigger); - asn1_event_a5.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + if (event_id.use_allowed_cell_list.has_value()) { + asn1_event_a5.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } else { + asn1_event_a5.use_allowed_cell_list = false; + } } // event a6 @@ -875,7 +887,11 @@ srsran::srs_cu_cp::event_triggered_report_cfg_to_rrc_asn1(const rrc_event_trigge asn1_event_a6.report_on_leave = event_id.report_on_leave; asn1_event_a6.hysteresis = event_id.hysteresis; asn1::number_to_enum(asn1_event_a6.time_to_trigger, event_id.time_to_trigger); - asn1_event_a6.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + if (event_id.use_allowed_cell_list.has_value()) { + asn1_event_a6.use_allowed_cell_list = event_id.use_allowed_cell_list.value(); + } else { + asn1_event_a6.use_allowed_cell_list = false; + } } // rs type diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp index d05b3ac5f8..d156cac51b 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp @@ -115,10 +115,12 @@ void cell_meas_manager_test::create_default_manager() rrc_event_trigger_cfg event_trigger_cfg = {}; rrc_event_id event_a3; + event_a3.id = rrc_event_id::event_id_t::a3; event_a3.meas_trigger_quant_thres_or_offset.emplace(); event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_a3.use_allowed_cell_list = false; event_trigger_cfg.event_id = event_a3; @@ -194,10 +196,12 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r rrc_event_trigger_cfg event_trigger_cfg = {}; rrc_event_id event_a3; + event_a3.id = rrc_event_id::event_id_t::a3; event_a3.meas_trigger_quant_thres_or_offset.emplace(); event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_a3.use_allowed_cell_list = false; event_trigger_cfg.event_id = event_a3; @@ -249,10 +253,12 @@ void cell_meas_manager_test::create_manager_without_ncells_and_periodic_report() rrc_event_trigger_cfg event_trigger_cfg = {}; rrc_event_id event_a3; + event_a3.id = rrc_event_id::event_id_t::a3; event_a3.meas_trigger_quant_thres_or_offset.emplace(); event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_a3.use_allowed_cell_list = false; event_trigger_cfg.event_id = event_a3; diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index e291bf0de6..ba0e051f74 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -159,10 +159,12 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : rrc_event_trigger_cfg event_trigger_cfg = {}; rrc_event_id event_a3; + event_a3.id = rrc_event_id::event_id_t::a3; event_a3.meas_trigger_quant_thres_or_offset.emplace(); event_a3.meas_trigger_quant_thres_or_offset.value().rsrp.emplace() = 6; event_a3.hysteresis = 0; event_a3.time_to_trigger = 100; + event_a3.use_allowed_cell_list = false; event_trigger_cfg.event_id = event_a3; From 4cbc5a3631749649410b0fa3ea25a2d468b21c85 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 13 Aug 2024 15:49:20 +0200 Subject: [PATCH 270/407] f1u,gw,test: adjust timeouts in unit tests... a) 1s -> 5s where a PDU RX is expected b) 1s -> 200ms where no PDU RX is expected a) avoids false-negative (timeouts) on heavy-loaded machines; b) speeds up tests that expect no PDU reception within timeout window. --- tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp | 4 ++-- tests/unittests/f1u/common/f1u_du_split_connector_test.cpp | 2 +- tests/unittests/gateways/test_helpers.h | 4 ++-- .../gateways/udp_network_gateway_pool_depletion_test.cpp | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) 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 eb7f35b2f0..b17c17f8d8 100644 --- a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp @@ -277,7 +277,7 @@ TEST_F(f1u_cu_split_connector_test, send_sdu_without_dl_teid_attached) io_tx_executor.run_pending_tasks(); // No PDU expected - expected du_rx_pdu = server_data_notifier.get_rx_pdu_blocking(); + expected du_rx_pdu = server_data_notifier.get_rx_pdu_blocking(std::chrono::milliseconds(200)); ASSERT_FALSE(du_rx_pdu.has_value()); } @@ -391,7 +391,7 @@ TEST_F(f1u_cu_split_connector_test, disconnect_stops_tx) io_tx_executor.run_pending_tasks(); // No PDU expected - expected du_rx_pdu2 = server_data_notifier.get_rx_pdu_blocking(); + expected du_rx_pdu2 = server_data_notifier.get_rx_pdu_blocking(std::chrono::milliseconds(200)); ASSERT_FALSE(du_rx_pdu2.has_value()); // Destructor of cu_bearer tries to disconnect tunnel again, hence we see a warning. diff --git a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp index 2460e14295..28a7f70b97 100644 --- a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp @@ -318,7 +318,7 @@ TEST_F(f1u_du_split_connector_test, disconnect_stops_tx) io_tx_executor.run_pending_tasks(); // No PDU expected - expected cu_rx_pdu2 = server_data_notifier.get_rx_pdu_blocking(); + expected cu_rx_pdu2 = server_data_notifier.get_rx_pdu_blocking(std::chrono::milliseconds(200)); ASSERT_FALSE(cu_rx_pdu2.has_value()); // Destructor of du_bearer tries to disconnect tunnel again, hence we see a warning. diff --git a/tests/unittests/gateways/test_helpers.h b/tests/unittests/gateways/test_helpers.h index 74036517a9..8d21993fec 100644 --- a/tests/unittests/gateways/test_helpers.h +++ b/tests/unittests/gateways/test_helpers.h @@ -155,7 +155,7 @@ class dummy_network_gateway_data_notifier_with_src_addr : public network_gateway return rx_bytes; } - expected get_rx_pdu_blocking(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds(1000)) + expected get_rx_pdu_blocking(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds(5000)) { // wait until at least one PDU is received std::unique_lock lock(rx_mutex); @@ -205,4 +205,4 @@ class dummy_network_gateway_data_handler : public sctp_network_gateway_data_hand byte_buffer last_pdu; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp b/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp index 227105ae0f..6e6e889a37 100644 --- a/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp +++ b/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp @@ -152,7 +152,8 @@ TEST_F(udp_pool_network_gateway_tester, when_config_valid_then_trx_succeeds) } send_to_server(server_address_v4, server_port.value()); - expected rx_pdu = server_data_notifier.get_rx_pdu_blocking(); + // No PDU expected + expected rx_pdu = server_data_notifier.get_rx_pdu_blocking(std::chrono::milliseconds(200)); ASSERT_FALSE(rx_pdu.has_value()); // should not have been received } From 19f740162f5e255a3210f0aacb63edab9da1c4f7 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Tue, 13 Aug 2024 18:14:05 +0200 Subject: [PATCH 271/407] config: fix b210 clock config --- configs/gnb_rf_b210_fdd_srsUE.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/gnb_rf_b210_fdd_srsUE.yml b/configs/gnb_rf_b210_fdd_srsUE.yml index 23a480dd4e..9940c4aea1 100644 --- a/configs/gnb_rf_b210_fdd_srsUE.yml +++ b/configs/gnb_rf_b210_fdd_srsUE.yml @@ -12,7 +12,7 @@ amf: ru_sdr: device_driver: uhd device_args: type=b200 - sync: external + clock: external srate: 23.04 tx_gain: 80 rx_gain: 40 From bf96b3492eda492eef6fc8815c13015ecb439d74 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 13 Aug 2024 14:24:28 +0200 Subject: [PATCH 272/407] sched: schedule SRB1 PDU even if CQI reported is zero --- .../ue_scheduling/ue_fallback_scheduler.cpp | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 8617791197..53cf2d16a1 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -991,7 +991,28 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 grant_prbs_mcs mcs_prbs_estimate = ue_pcell.required_dl_prbs(pdsch_td_cfg, pending_bytes, dci_type); if (mcs_prbs_estimate.n_prbs == 0) { - return {}; + // This is a case where CSI detected by PHY is a false positive, which is decoded as CQI=0. Since these false + // positives cannot be avoided completely, we need to schedule the UE even with CQI==0 in the case of the fallback + // scheduler, so that it gets a config that it can use to report a CQI > 0. + sch_mcs_index mcs_idx = 0; + sch_prbs_tbs prbs_tbs{}; + + // Try to find least MCS to fit SRB1 message. + while (mcs_idx < expert_cfg.max_msg4_mcs) { + const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_cfg.mcs_table, mcs_idx); + prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, + static_cast(pdsch_cfg.symbols.length()), + calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), + pdsch_cfg.nof_oh_prb, + mcs_config, + pdsch_cfg.nof_layers}); + if (unused_crbs.length() >= prbs_tbs.nof_prbs) { + break; + } + ++mcs_idx; + } + mcs_prbs_estimate.n_prbs = prbs_tbs.nof_prbs; + mcs_prbs_estimate.mcs = mcs_idx; } // [Implementation-defined] In case of partial slots and nof. PRBs allocated equals to 1 probability of KO is @@ -1005,6 +1026,10 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, mcs_prbs_estimate.n_prbs, 0); if (ue_grant_crbs.empty() or (set_min_nof_prbs and ue_grant_crbs.length() < min_nof_prbs_partial_slots)) { + logger.debug("ue={} rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: No space in PDSCH.", + u.ue_index, + u.crnti, + pdsch_alloc.slot); return {}; } From 791dd0cece36396af86a27ec89b9cb472b342642 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 13 Aug 2024 14:24:50 +0200 Subject: [PATCH 273/407] sched: fix code comments --- lib/scheduler/ue_scheduling/ue_cell.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_cell.h b/lib/scheduler/ue_scheduling/ue_cell.h index 624e842415..ef030bd916 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.h +++ b/lib/scheduler/ue_scheduling/ue_cell.h @@ -25,9 +25,9 @@ namespace srsran { struct ul_crc_pdu_indication; struct grant_prbs_mcs { - /// MCS to use for the UE's PUSCH. + /// MCS to use for the UE's PxSCH. sch_mcs_index mcs; - /// Number of PRBs to be allocated for the UE's PUSCH. + /// Number of PRBs to be allocated for the UE's PxSCH. unsigned n_prbs; }; From 77d41a749aef0c86ebc22e75eacb2954fdbd4d00 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 13 Aug 2024 14:25:58 +0200 Subject: [PATCH 274/407] unittest: add test to verify allocation of resources for SRB1 PDU when reported CQI is 0 --- .../ue_scheduling/fallback_scheduler_test.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index de23b4a69c..aa683ee439 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -410,6 +410,46 @@ TEST_P(fallback_scheduler_tester, successfully_allocated_resources) ASSERT_FALSE(test_ue.has_pending_dl_newtx_bytes(LCID_SRB0)); } +TEST_P(fallback_scheduler_tester, successfully_allocated_resources_for_srb1_pdu_even_if_cqi_is_zero) +{ + setup_sched(create_expert_config(3), create_custom_cell_config_request(params.k0)); + // Add UE. + const du_ue_index_t ue_idx = to_du_ue_index(0); + add_ue(to_rnti(0x4601), ue_idx); + auto& test_ue = get_ue(ue_idx); + // UE reports CQI 0. + csi_report_data csi_report{}; + csi_report.first_tb_wideband_cqi.emplace(0); + test_ue.get_pcell().handle_csi_report(csi_report); + // Notify about SRB1 message in DL of size 320 bytes. + const unsigned mac_srb1_sdu_size = 320; + push_buffer_state_to_dl_ue(ue_idx, current_slot, mac_srb1_sdu_size, false); + + bool is_ue_allocated_pdcch{false}; + bool is_ue_allocated_pdsch{false}; + for (unsigned sl_idx = 0; sl_idx < bench->max_test_run_slots_per_ue * (1U << current_slot.numerology()); sl_idx++) { + run_slot(); + const pdcch_dl_information* pdcch_it = get_ue_allocated_pdcch(test_ue); + if (pdcch_it != nullptr) { + is_ue_allocated_pdcch = true; + } + if (is_ue_allocated_pdcch) { + const dl_msg_alloc* pdsch_it = get_ue_allocated_pdsch(test_ue); + if (pdsch_it != nullptr) { + for (const auto& lc_info : pdsch_it->tb_list.back().lc_chs_to_sched) { + if (lc_info.lcid.is_sdu() and lc_info.lcid == LCID_SRB1) { + is_ue_allocated_pdsch = true; + break; + } + } + } + } + } + ASSERT_TRUE(is_ue_allocated_pdcch); + ASSERT_TRUE(is_ue_allocated_pdsch); + ASSERT_FALSE(test_ue.has_pending_dl_newtx_bytes(LCID_SRB1)); +} + TEST_P(fallback_scheduler_tester, failed_allocating_resources) { setup_sched(create_expert_config(3), create_custom_cell_config_request(params.k0)); From 8fc1bf2759ba58e63b50d4a0dd3be256617065cb Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 13 Aug 2024 16:16:32 +0200 Subject: [PATCH 275/407] sched: fix condition to check whether PDCCH and PDSCH slot is DL enabled --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 53cf2d16a1..1b40a7844e 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -430,7 +430,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_a const cell_slot_resource_allocator& pdcch_alloc = res_alloc[offset_to_sched_ref_slot]; const cell_slot_resource_allocator& pdsch_alloc = res_alloc[offset_to_sched_ref_slot]; - if ((not cell_cfg.is_dl_enabled(pdsch_alloc.slot)) or (not cell_cfg.is_dl_enabled(pdsch_alloc.slot))) { + if ((not cell_cfg.is_dl_enabled(pdcch_alloc.slot)) or (not cell_cfg.is_dl_enabled(pdsch_alloc.slot))) { continue; } From 05311aded25922f9b30ac59d5a8b58afd9d02795 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 14 Aug 2024 10:57:00 +0200 Subject: [PATCH 276/407] sched: use initial CQI while scheduling SRB1 PDU in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 59 ++++++++++--------- .../ue_scheduling/fallback_scheduler_test.cpp | 10 ++-- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 1b40a7844e..4f3705b1e0 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -12,6 +12,7 @@ #include "../support/csi_rs_helpers.h" #include "../support/dci_builder.h" #include "../support/dmrs_helpers.h" +#include "../support/mcs_calculator.h" #include "../support/pdsch/pdsch_resource_allocation.h" #include "../support/prbs_calculator.h" #include "../support/pusch/pusch_td_resource_indices.h" @@ -987,33 +988,28 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 // Find available symbol x RB resources. const unsigned pending_bytes = get_srb1_pending_tot_bytes(u.ue_index); - // If there is no free PRBs left on this slot for this UE, then this slot should be avoided by the other UEs too. - grant_prbs_mcs mcs_prbs_estimate = ue_pcell.required_dl_prbs(pdsch_td_cfg, pending_bytes, dci_type); - - if (mcs_prbs_estimate.n_prbs == 0) { - // This is a case where CSI detected by PHY is a false positive, which is decoded as CQI=0. Since these false - // positives cannot be avoided completely, we need to schedule the UE even with CQI==0 in the case of the fallback - // scheduler, so that it gets a config that it can use to report a CQI > 0. - sch_mcs_index mcs_idx = 0; - sch_prbs_tbs prbs_tbs{}; - - // Try to find least MCS to fit SRB1 message. - while (mcs_idx < expert_cfg.max_msg4_mcs) { - const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_cfg.mcs_table, mcs_idx); - prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, - static_cast(pdsch_cfg.symbols.length()), - calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), - pdsch_cfg.nof_oh_prb, - mcs_config, - pdsch_cfg.nof_layers}); - if (unused_crbs.length() >= prbs_tbs.nof_prbs) { - break; - } - ++mcs_idx; - } - mcs_prbs_estimate.n_prbs = prbs_tbs.nof_prbs; - mcs_prbs_estimate.mcs = mcs_idx; + // Fallback scheduler should always work with initial CQI and not rely on CSI reported by UE since UE may not have + // received the configuration to report CSI. + std::optional mcs_idx = map_cqi_to_mcs(expert_cfg.initial_cqi, pdsch_cfg.mcs_table); + if (not mcs_idx.has_value()) { + logger.warning("ue={} rnti={}: Failed to schedule SRB1 PDU for slot={}. Cause: No valid MCS found for CQI={}.", + u.ue_index, + u.crnti, + pdsch_alloc.slot, + expert_cfg.initial_cqi); + return {}; + } + const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_cfg.mcs_table, *mcs_idx); + sch_prbs_tbs prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, + static_cast(pdsch_cfg.symbols.length()), + calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), + pdsch_cfg.nof_oh_prb, + mcs_config, + pdsch_cfg.nof_layers}); + if (prbs_tbs.nof_prbs == 0) { + return {}; } + grant_prbs_mcs mcs_prbs_estimate{.mcs = *mcs_idx, .n_prbs = prbs_tbs.nof_prbs}; // [Implementation-defined] In case of partial slots and nof. PRBs allocated equals to 1 probability of KO is // high due to code not being able to cope with interference. So the solution is to increase the PRB allocation @@ -1056,9 +1052,14 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 // If ConRes CE is pending then ensure that there is enough RBs/TBS such that ConRes CE is not segmented. if (u.is_conres_ce_pending()) { const unsigned only_conres_ce_pending_bytes = u.pending_conres_ce_bytes(); - grant_prbs_mcs only_conres_mcs_prbs_estimate = - ue_pcell.required_dl_prbs(pdsch_td_cfg, only_conres_ce_pending_bytes, dci_dl_rnti_config_type::tc_rnti_f1_0); - if ((mcs_prbs_estimate.n_prbs < only_conres_mcs_prbs_estimate.n_prbs) or + sch_prbs_tbs only_conres_prbs_tbs = + get_nof_prbs(prbs_calculator_sch_config{only_conres_ce_pending_bytes, + static_cast(pdsch_cfg.symbols.length()), + calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), + pdsch_cfg.nof_oh_prb, + mcs_config, + pdsch_cfg.nof_layers}); + if ((mcs_prbs_estimate.n_prbs < only_conres_prbs_tbs.nof_prbs) or (mcs_tbs->tbs < (only_conres_ce_pending_bytes + FIXED_SIZED_MAC_CE_SUBHEADER_SIZE))) { logger.debug("ue={} rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: Grant is too small to fit even " "ConRes CE.", diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index aa683ee439..ee019ad695 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -699,7 +699,8 @@ class fallback_scheduler_head_scheduling : public base_fallback_tester, protected: const unsigned MAX_NOF_SLOTS_GRID_IS_BUSY = 4; const unsigned MAX_TEST_RUN_SLOTS = 2100; - const unsigned MAC_SRB0_SDU_SIZE = 128; + // NOTE: Ensure that the SDU size is small enough so that there is no segmentation when tested for SRB1. + const unsigned MAC_SRB_SDU_SIZE = 101; fallback_scheduler_head_scheduling() : base_fallback_tester(GetParam().duplx_mode) { @@ -814,7 +815,7 @@ TEST_P(fallback_scheduler_head_scheduling, test_ahead_scheduling_for_srb_allocat // Allocate buffer and occupy the grid to test the scheduler in advance scheduling. if (current_slot == slot_update_srb_traffic) { - push_buffer_state_to_dl_ue(to_du_ue_index(du_idx), current_slot, MAC_SRB0_SDU_SIZE, GetParam().is_srb0); + push_buffer_state_to_dl_ue(to_du_ue_index(du_idx), current_slot, MAC_SRB_SDU_SIZE, GetParam().is_srb0); // Mark resource grid as occupied. fill_resource_grid(current_slot, @@ -868,7 +869,7 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T void slot_indication(slot_point sl) { switch (state) { - // Wait until the slot to update the SRB0 traffic. + // Wait until the slot to update the SRB0/SRB1 traffic. case ue_state::idle: { if (sl == slot_update_srb_traffic and nof_packet_to_tx > 0) { // Notify about SRB0/SRB1 message in DL. @@ -978,7 +979,8 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T const unsigned SRB_PACKETS_TOT_TX = 20; const unsigned MAX_UES = 1; const unsigned MAX_TEST_RUN_SLOTS = 2100; - const unsigned MAC_SRB0_SDU_SIZE = 128; + // NOTE: Ensure that the SDU size is small enough so that there is no segmentation when tested for SRB1. + const unsigned MAC_SRB0_SDU_SIZE = 101; std::vector ues_testers; }; From d56e407b214cc2e8499d18269e3197b913f6a674 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 5 Aug 2024 15:41:45 +0200 Subject: [PATCH 277/407] gnb: enable transform precoding in the gNb gnb: review transform precoding related --- .../flexible_du/du_high/du_high_config.h | 3 ++ .../du_high/du_high_config_cli11_schema.cpp | 4 ++ .../du_high/du_high_config_translators.cpp | 1 + .../du_high/du_high_config_validator.cpp | 19 ++++++++ include/srsran/ran/prach/rach_config_common.h | 2 +- .../transform_precoding_helpers.h | 44 ++++++++++++++++++- .../converters/asn1_rrc_config_helpers.cpp | 3 ++ lib/fapi_adaptor/mac/messages/pusch.cpp | 3 -- .../config/serving_cell_config_factory.cpp | 1 - lib/scheduler/support/sch_pdu_builder.cpp | 20 +++++---- 10 files changed, 85 insertions(+), 15 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 036140cf47..357bd271e4 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -203,6 +203,9 @@ struct du_high_unit_pusch_config { unsigned start_rb = 0; /// End RB for resource allocation of UE PUSCHs. unsigned end_rb = MAX_NOF_PRBS; + + /// Set to true to enable transform precoding in PUSCH. + bool enable_transform_precoding = false; }; struct du_high_unit_pucch_config { 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 d8f9940c7d..ec4febcb4e 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 @@ -749,6 +749,10 @@ static void configure_cli11_pusch_args(CLI::App& app, du_high_unit_pusch_config& app.add_option("--end_rb", pusch_params.end_rb, "End RB for resource allocation of UE PUSCHs") ->capture_default_str() ->check(CLI::Range(0U, (unsigned)MAX_NOF_PRBS)); + app.add_option("--enable_transform_precoding", + pusch_params.enable_transform_precoding, + "Enable transform precoding for PUSCH.") + ->capture_default_str(); } static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& pucch_params) 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 ba750dc51e..65c29a1280 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 @@ -356,6 +356,7 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c rach_cfg.rach_cfg_generic.prach_config_index = base_cell.prach_cfg.prach_config_index.value(); rach_cfg.rach_cfg_generic.preamble_trans_max = base_cell.prach_cfg.preamble_trans_max; rach_cfg.rach_cfg_generic.power_ramping_step_db = base_cell.prach_cfg.power_ramping_step_db; + rach_cfg.msg3_transform_precoder = cell.cell.pusch_cfg.enable_transform_precoding; const bool is_long_prach = is_long_preamble(prach_configuration_get(band_helper::get_freq_range(param.band.value()), band_helper::get_duplex_mode(param.band.value()), 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 1eef910602..65077c8ddf 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 @@ -15,6 +15,7 @@ #include "srsran/ran/pdcch/pdcch_type0_css_coreset_config.h" #include "srsran/ran/prach/prach_helper.h" #include "srsran/ran/pucch/pucch_constants.h" +#include "srsran/ran/transform_precoding/transform_precoding_helpers.h" #include "srsran/rlc/rlc_config.h" #include @@ -363,6 +364,24 @@ static bool validate_pusch_cell_unit_config(const du_high_unit_pusch_config& con return false; } + if (config.enable_transform_precoding && !is_transform_precoding_nof_prb_valid(config.min_rb_size)) { + fmt::print("Invalid minimum UE PUSCH RB (i.e., {}) with transform precoding. The nearest lower number of PRB is {} " + "and the higher is {}.\n", + config.min_rb_size, + get_transform_precoding_nearest_lower_nof_prb_valid(config.min_rb_size), + get_transform_precoding_nearest_higher_nof_prb_valid(config.min_rb_size)); + return false; + } + + if (config.enable_transform_precoding && !is_transform_precoding_nof_prb_valid(config.max_rb_size)) { + fmt::print("Invalid maximum UE PUSCH RB (i.e., {}) with transform precoding. The nearest lower number of PRB is {} " + "and the higher is {}.\n", + config.max_rb_size, + get_transform_precoding_nearest_lower_nof_prb_valid(config.max_rb_size), + get_transform_precoding_nearest_higher_nof_prb_valid(config.max_rb_size)); + return false; + } + if (config.end_rb < config.start_rb) { fmt::print("Invalid RB allocation range [{}, {}) for UE PUSCHs. The start_rb must be less or equal to the end_rb", config.start_rb, diff --git a/include/srsran/ran/prach/rach_config_common.h b/include/srsran/ran/prach/rach_config_common.h index 3e306e3a5b..6b2e4e550a 100644 --- a/include/srsran/ran/prach/rach_config_common.h +++ b/include/srsran/ran/prach/rach_config_common.h @@ -56,7 +56,7 @@ struct rach_config_common { subcarrier_spacing msg1_scs; restricted_set_config restricted_set; /// Enables the transform precoder for Msg3 transmission according to clause 6.1.3 of TS 38.214. - bool msg3_transform_precoder; + bool msg3_transform_precoder = false; /// Indicates the number of SSBs per RACH occasion (L1 parameter 'SSB-per-rach-occasion'). See TS 38.331, \c /// ssb-perRACH-OccasionAndCB-PreamblesPerSSB. Values {1/8, 1/4, 1/2, 1, 2, 4, 8, 16}. /// Value 1/8 corresponds to one SSB associated with 8 RACH occasions and so on so forth. diff --git a/include/srsran/ran/transform_precoding/transform_precoding_helpers.h b/include/srsran/ran/transform_precoding/transform_precoding_helpers.h index 173d4666b3..b91feb8171 100644 --- a/include/srsran/ran/transform_precoding/transform_precoding_helpers.h +++ b/include/srsran/ran/transform_precoding/transform_precoding_helpers.h @@ -18,6 +18,7 @@ #include "srsran/adt/span.h" #include "srsran/ran/resource_block.h" +#include namespace srsran { @@ -49,7 +50,48 @@ inline span get_transform_precoding_valid_nof_prb() /// Determines whether a number of PRB is valid. inline bool is_transform_precoding_nof_prb_valid(unsigned nof_prb) { - return get_transform_precoding_valid_nof_prb()[nof_prb]; + span valid_nof_prb = get_transform_precoding_valid_nof_prb(); + if (nof_prb >= valid_nof_prb.size()) { + return false; + } + return valid_nof_prb[nof_prb]; +} + +/// \brief Gets the nearest valid of PRB for transform precoding. +/// \return A number of PRB equal to or higher than the given number of PRB. +inline std::optional get_transform_precoding_nearest_higher_nof_prb_valid(unsigned nof_prb) +{ + span valid_nof_prb = get_transform_precoding_valid_nof_prb(); + if (nof_prb > valid_nof_prb.size()) { + return std::nullopt; + } + + auto nearest = std::find(valid_nof_prb.begin() + nof_prb, valid_nof_prb.end(), true); + if (nearest == valid_nof_prb.end()) { + return std::nullopt; + } + + return std::distance(valid_nof_prb.begin(), nearest); +} + +/// \brief Gets the nearest valid of PRB for transform precoding. +/// \return A number of PRB equal to or lower than the given number of PRB. +inline std::optional get_transform_precoding_nearest_lower_nof_prb_valid(unsigned nof_prb) +{ + span valid_nof_prb = get_transform_precoding_valid_nof_prb(); + if (nof_prb > valid_nof_prb.size()) { + return std::nullopt; + } + + // Limit search to the first PRB. + valid_nof_prb = valid_nof_prb.first(nof_prb); + + auto nearest = std::find(valid_nof_prb.rbegin(), valid_nof_prb.rend(), true); + if (nearest == valid_nof_prb.rend()) { + return std::nullopt; + } + + return std::distance(valid_nof_prb.begin(), (++nearest).base()); } } // namespace srsran diff --git a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp index 8596b5aeb7..e2a65d7cc7 100644 --- a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp +++ b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp @@ -817,6 +817,9 @@ asn1::rrc_nr::bwp_ul_common_s srsran::srs_du::make_asn1_rrc_initial_up_bwp(const rach_cfg.nof_ssb_per_ro, rach_cfg.nof_cb_preambles_per_ssb, rach); rach.ra_contention_resolution_timer.value = asn1::rrc_nr::rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64; + if (rach_cfg.msg3_transform_precoder) { + rach.msg3_transform_precoder_present = true; + } if (rach_cfg.is_prach_root_seq_index_l839) { rach.prach_root_seq_idx.set_l839() = rach_cfg.prach_root_seq_index; } else { diff --git a/lib/fapi_adaptor/mac/messages/pusch.cpp b/lib/fapi_adaptor/mac/messages/pusch.cpp index 8fba37aab0..b2df7778a2 100644 --- a/lib/fapi_adaptor/mac/messages/pusch.cpp +++ b/lib/fapi_adaptor/mac/messages/pusch.cpp @@ -88,9 +88,6 @@ void srsran::fapi_adaptor::convert_pusch_mac_to_fapi(fapi::ul_pusch_pdu_builder& pusch_pdu.n_id, pusch_pdu.nof_layers); - // The low_papr_dmrs field expects transform precoding to be disabled. - srsran_assert(!pusch_pdu.transform_precoding, "Transform precoding not yet supported"); - const dmrs_information& dmrs_cfg = pusch_pdu.dmrs; builder.set_dmrs_parameters(dmrs_cfg.dmrs_symb_pos.to_uint64(), dmrs_cfg.config_type, diff --git a/lib/scheduler/config/serving_cell_config_factory.cpp b/lib/scheduler/config/serving_cell_config_factory.cpp index 31f0a94649..28c7a4b496 100644 --- a/lib/scheduler/config/serving_cell_config_factory.cpp +++ b/lib/scheduler/config/serving_cell_config_factory.cpp @@ -378,7 +378,6 @@ srsran::config_helpers::make_default_ul_config_common(const cell_config_builder_ prach_configuration_get(freq_range, duplex, cfg.init_ul_bwp.rach_cfg_common->rach_cfg_generic.prach_config_index) .format); cfg.init_ul_bwp.rach_cfg_common->prach_root_seq_index = 1; - cfg.init_ul_bwp.rach_cfg_common->msg3_transform_precoder = false; cfg.init_ul_bwp.rach_cfg_common->rach_cfg_generic.msg1_fdm = 1; // Add +3 PRBS to the MSG1 frequency start, which act as a guardband between the PUCCH and PRACH. cfg.init_ul_bwp.rach_cfg_common->rach_cfg_generic.msg1_frequency_start = 6; diff --git a/lib/scheduler/support/sch_pdu_builder.cpp b/lib/scheduler/support/sch_pdu_builder.cpp index b493e96ffa..8ae30c3096 100644 --- a/lib/scheduler/support/sch_pdu_builder.cpp +++ b/lib/scheduler/support/sch_pdu_builder.cpp @@ -629,10 +629,11 @@ void srsran::build_pusch_f0_0_tc_rnti(pusch_information& pusch // parameter msg3-transformPrecoder". pusch.transform_precoding = cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->msg3_transform_precoder; // As per TS 38.211, Section 6.3.1.1, n_ID is set to Physical Cell ID for TC-RNTI. - pusch.n_id = cell_cfg.pci; - pusch.nof_layers = pusch_cfg.nof_layers; - pusch.dmrs = pusch_cfg.dmrs; - pusch.pusch_dmrs_id = 0; + pusch.n_id = cell_cfg.pci; + pusch.nof_layers = pusch_cfg.nof_layers; + pusch.dmrs = pusch_cfg.dmrs; + // TS 38.211, Section 6.4.1.1.1.2, n^RS_ID is set to to Physical Cell ID for TC-RNTI. + pusch.pusch_dmrs_id = cell_cfg.pci; pusch.rv_index = dci_cfg.redundancy_version; // TS 38.321, 5.4.2.1 - "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is used". pusch.harq_id = 0; @@ -729,15 +730,17 @@ void srsran::build_pusch_f0_1_c_rnti(pusch_information& pusch, pusch.mcs_index = dci_cfg.modulation_coding_scheme; pusch.mcs_descr = pusch_mcs_get_config(pusch.mcs_table, pusch.mcs_index, pusch_cfg.tp_pi2bpsk_present); - pusch.n_id = cell_cfg.pci; + pusch.n_id = cell_cfg.pci; + pusch.pusch_dmrs_id = cell_cfg.pci; + if (opt_rach_cfg.has_value()) { + pusch.transform_precoding = opt_rach_cfg.value().msg3_transform_precoder; + } // Dedicated config overrides previously set value. if (pusch_cfg_ded.has_value()) { pusch.transform_precoding = false; if (pusch_cfg_ded.value().trans_precoder != pusch_config::transform_precoder::not_set) { pusch.transform_precoding = pusch_cfg_ded.value().trans_precoder == pusch_config::transform_precoder::enabled; - } else if (opt_rach_cfg.has_value()) { - pusch.transform_precoding = opt_rach_cfg.value().msg3_transform_precoder; } if (pusch_cfg_ded.value().data_scrambling_id_pusch.has_value()) { @@ -745,8 +748,7 @@ void srsran::build_pusch_f0_1_c_rnti(pusch_information& pusch, } } - pusch.dmrs = pusch_cfg.dmrs; - pusch.pusch_dmrs_id = pusch_cfg.dmrs.dmrs_scrambling_id; + pusch.dmrs = pusch_cfg.dmrs; // TBS. pusch.nof_layers = pusch_cfg.nof_layers; From 51426924f31a2206583e7cfcf6df7707d8d3f3cb Mon Sep 17 00:00:00 2001 From: sauka Date: Mon, 12 Aug 2024 17:37:33 +0300 Subject: [PATCH 278/407] gnb: avoid using march=native for aarch64 processors, use armv8-a instead as a default value --- CMakeLists.txt | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e06e212261..13d764772e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,8 +308,24 @@ endif (ENABLE_DPDK) ######################################################################## # Instruction Set Architecture setup ######################################################################## -set(MARCH "native" CACHE STRING "Compiler march flag. Default value is 'native'") -set(MTUNE "generic" CACHE STRING "Compiler mtune flag. Default value is 'generic'") +set(MTUNE "generic" CACHE STRING "Compiler -mtune flag. Default value is 'generic'") +if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(MARCH "armv8-a" CACHE STRING "Compiler -march flag. Default value is 'armv8-a' for aarch64.") + message(STATUS "Detected aarch64 processor") +else (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(MARCH "native" CACHE STRING "Compiler -march flag. Default value is 'native' for x86-64.") +endif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + +add_cxx_compiler_flag_if_available("-march=${MARCH}" HAVE_MARCH) +if (NOT HAVE_MARCH) + message(WARNING "The compiler does not support -march=${MARCH}, try setting a different value.") +endif (NOT HAVE_MARCH) + +add_cxx_compiler_flag_if_available("-mtune=${MTUNE}" HAVE_MTUNE) +if (NOT HAVE_MTUNE) + message(WARNING "The compiler does not support -mtune=${MTUNE}, try setting a different value.") +endif (NOT HAVE_MTUNE) + message(STATUS "ARCH value is ${MARCH}") message(STATUS "TUNE value is ${MTUNE}") From 10482612c59a7bb4609403056d9d1bd4a0b06d9e Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 15 Aug 2024 16:35:48 +0200 Subject: [PATCH 279/407] sched: fix bad access to .end() iterator Signed-off-by: Carlo Galiotto --- lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 8b9b4b4fce..675ca115c4 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -228,11 +228,12 @@ std::optional pucch_allocator_impl::alloc_common_and_ded_harq_res(cell if (new_ue_grant_added) { pucch_grants.emplace_back(ue_grants{.rnti = rnti}); } + ue_grants& current_grants = new_ue_grant_added ? pucch_grants.back() : *ue_grants_it; // Find a couple of PUCCH resources (1 common, 1 dedicated) that are (i) are available and that (ii) have the same // PUCCH resource indicator. std::optional pucch_common_info = - find_common_and_ded_harq_res_available(pucch_slot_alloc, *ue_grants_it, rnti, ue_cell_cfg, dci_info.ctx); + find_common_and_ded_harq_res_available(pucch_slot_alloc, current_grants, rnti, ue_cell_cfg, dci_info.ctx); if (pucch_common_info.has_value()) { compute_pucch_common_params_and_alloc(pucch_slot_alloc, rnti, pucch_common_info.value()); From 7433484b4603d6d26fc49111727bfd4460ed1a10 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 16 Aug 2024 14:09:23 +0200 Subject: [PATCH 280/407] rrc: configurable timeout for SMC and HO-reconfig-complete This replaces the arbitrary hard-coded timeout_ms = 1000 with the configured value for all other RRC procedures, i.e. "--rrc_procedure_timeout_ms" --- lib/rrc/ue/rrc_ue_message_handlers.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 34cf7904fb..2667323d14 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -309,11 +309,9 @@ rrc_ue_security_mode_command_context rrc_ue_impl::get_security_mode_command_cont async_task rrc_ue_impl::handle_security_mode_complete_expected(uint8_t transaction_id) { - // arbitrary timeout for RRC Reconfig procedure, UE will be removed if timer fires - const std::chrono::milliseconds timeout_ms{1000}; - return launch_async( - [this, timeout_ms, transaction_id, transaction = rrc_transaction{}](coro_context>& ctx) mutable { + [this, timeout_ms = context.cfg.rrc_procedure_timeout_ms, transaction_id, transaction = rrc_transaction{}]( + coro_context>& ctx) mutable { CORO_BEGIN(ctx); logger.log_debug("Awaiting RRC Security Mode Complete (timeout={}ms)", timeout_ms.count()); @@ -413,11 +411,9 @@ rrc_ue_impl::get_rrc_ue_handover_reconfiguration_context(const rrc_reconfigurati async_task rrc_ue_impl::handle_handover_reconfiguration_complete_expected(uint8_t transaction_id) { - // arbitrary timeout for RRC Reconfig procedure, UE will be removed if timer fires - const std::chrono::milliseconds timeout_ms{1000}; - return launch_async( - [this, timeout_ms, transaction_id, transaction = rrc_transaction{}](coro_context>& ctx) mutable { + [this, timeout_ms = context.cfg.rrc_procedure_timeout_ms, transaction_id, transaction = rrc_transaction{}]( + coro_context>& ctx) mutable { CORO_BEGIN(ctx); logger.log_debug("Awaiting RRC Reconfiguration Complete (timeout={}ms)", timeout_ms.count()); From 08a49b5ba997565381d9a7d5c1d50f4cb54a2005 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 6 Aug 2024 16:52:32 +0200 Subject: [PATCH 281/407] Add FR2 support in band helper du: review validator for TDD pattern gNb: add more validators related to band, bw and scs du: fix validator for 300MHz ran: review band helper test for FR2 --- .../flexible_du/du_high/du_high_config.h | 2 +- .../du_high/du_high_config_cli11_schema.cpp | 7 +- .../du_high/du_high_config_translators.cpp | 2 +- .../du_high/du_high_config_validator.cpp | 54 ++- .../flexible_du/split_7_2/ru_ofh_config.h | 2 +- .../split_8/ru_sdr_config_validator.h | 2 +- include/srsran/ofh/ofh_sector_config.h | 4 +- .../ofh/receiver/ofh_receiver_configuration.h | 2 +- .../ofh_transmitter_configuration.h | 4 +- include/srsran/ran/band_helper.h | 18 +- include/srsran/ran/bs_channel_bandwidth.h | 20 +- include/srsran/ran/ssb_gscn.h | 8 +- include/srsran/ru/ru_ofh_configuration.h | 4 +- .../config/cell_config_builder_params.h | 2 +- lib/ran/band_helper.cpp | 379 +++++++++++------- lib/ran/ssb_gscn.cpp | 14 +- .../benchmarks/du_high/du_high_benchmark.cpp | 2 +- .../ofh/ofh_compression_benchmark.cpp | 66 +-- .../scheduler_multi_ue_benchmark.cpp | 2 +- .../ofh/ofh_integration_test.cpp | 42 +- .../ofh/ru_emulator_appconfig.h | 2 +- tests/unittests/ran/band_helper_test.cpp | 172 ++++---- tests/unittests/ran/ssb_gscn_test.cpp | 48 +-- .../paging_scheduler_test.cpp | 8 +- .../prach_scheduler_test.cpp | 5 +- .../common_scheduling/ra_scheduler_test.cpp | 2 +- .../common_scheduling/sib1_scheduler_test.cpp | 6 +- .../scheduler/multi_cell_scheduler_test.cpp | 2 +- .../scheduler/multiple_ue_sched_test.cpp | 6 +- .../pdcch/pdcch_resource_allocator_test.cpp | 4 +- .../policy/scheduler_policy_test.cpp | 2 +- .../scheduler/scheduler_ta_cmd_test.cpp | 4 +- .../scheduler/scheduler_tdd_test.cpp | 2 +- .../scheduler_ue_fallback_mode_test.cpp | 2 +- .../slicing/slice_scheduler_test.cpp | 2 +- .../scheduler/uci_and_pucch/uci_test_utils.h | 4 +- .../ue_scheduling/fallback_scheduler_test.cpp | 2 +- .../ue_scheduling/ue_configuration_test.cpp | 2 +- .../ue_scheduling/ue_grid_allocator_test.cpp | 2 +- 39 files changed, 531 insertions(+), 382 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 357bd271e4..83ede6b479 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -521,7 +521,7 @@ struct du_high_unit_base_cell_config { /// NR band. std::optional band; /// Channel bandwidth in MHz. - bs_channel_bandwidth_fr1 channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + bs_channel_bandwidth channel_bw_mhz = bs_channel_bandwidth::MHz20; /// Number of antennas in downlink. unsigned nof_antennas_dl = 1; /// Number of antennas in uplink. 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 ec4febcb4e..cc8bb5e366 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 @@ -1102,7 +1102,7 @@ static void configure_cli11_common_cell_args(CLI::App& app, du_high_unit_base_ce unsigned bw; ss >> bw; const std::string& error_message = "Error in the channel bandwidth property. Valid values " - "[5,10,15,20,25,30,40,50,60,70,80,90,100]"; + "[5,10,15,20,25,30,40,50,60,70,80,90,100,200,400]"; // Bandwidth cannot be less than 5MHz. if (bw < 5U) { return error_message; @@ -1118,6 +1118,11 @@ static void configure_cli11_common_cell_args(CLI::App& app, du_high_unit_base_ce return ((bw % 10) == 0) ? "" : error_message; } + // Check from [200-400] in steps of 200. + if (bw < 401U) { + return ((bw % 200) == 0) ? "" : error_message; + } + return error_message; }); add_option(app, "--nof_antennas_ul", cell_params.nof_antennas_ul, "Number of antennas in uplink") 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 65c29a1280..46b2b7455d 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 @@ -233,7 +233,7 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c // in one extra symbol to be used for PDSCH. if (base_cell.pdcch_cfg.common.max_coreset0_duration.has_value()) { param.max_coreset0_duration = base_cell.pdcch_cfg.common.max_coreset0_duration.value(); - } else if (param.channel_bw_mhz > bs_channel_bandwidth_fr1::MHz50) { + } else if (param.channel_bw_mhz > bs_channel_bandwidth::MHz50) { param.max_coreset0_duration = 1; } const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( 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 65077c8ddf..ccef53ed15 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 @@ -556,8 +556,9 @@ static bool validate_tdd_ul_dl_pattern_unit_config(const tdd_ul_dl_pattern_unit_ subcarrier_spacing common_scs) { // NOTE: TDD pattern is assumed to use common SCS as reference SCS. - if (common_scs > subcarrier_spacing::kHz60) { - fmt::print("Invalid TDD UL DL reference SCS={}kHz. Must be 15, 30 or 60 kHz for FR1.\n", scs_to_khz(common_scs)); + if (common_scs > subcarrier_spacing::kHz120) { + fmt::print("Invalid TDD UL DL reference SCS={}kHz. Must be 15, 30 or 60 kHz for FR1 and 120 kHz for FR2.\n", + scs_to_khz(common_scs)); return false; } @@ -605,17 +606,36 @@ static bool validate_dl_arfcn_and_band(const du_high_unit_base_cell_config& conf // NOTE: Band n46 would be compatible with the 10MHz BW, but there is no sync raster that falls within the band // limits. Also, the Coreset#0 width in RBs given in Table 13-4A, TS 38.213, is larger than the band itself, which is // odd. Therefore, we limit the band to minimum 20MHz BW. - if (band == srsran::nr_band::n46 and config.channel_bw_mhz < bs_channel_bandwidth_fr1::MHz20) { + if (band == srsran::nr_band::n46 and config.channel_bw_mhz < bs_channel_bandwidth::MHz20) { fmt::print("Minimum supported bandwidth for n46 is 20MHz.\n"); return false; } - if (bs_channel_bandwidth_to_MHz(config.channel_bw_mhz) < - min_channel_bandwidth_to_MHz(band_helper::get_min_channel_bw(band, config.common_scs))) { + // Check if the subcarier spacing is valid for the frequency range. + frequency_range fr = band_helper::get_freq_range(band); + if ((fr == frequency_range::FR1) && (config.common_scs > subcarrier_spacing::kHz60)) { + fmt::print("Frequency range 1 does not support the subcarrier spacing of {}.\n", to_string(config.common_scs)); + return false; + } + + if ((fr == frequency_range::FR2) && (config.common_scs < subcarrier_spacing::kHz60)) { + fmt::print("Frequency range 2 does not support the subcarrier spacing of {}.\n", to_string(config.common_scs)); + return false; + } + + // Obtain the minimum bandwidth for the subcarrier and band combination. + min_channel_bandwidth min_chan_bw = band_helper::get_min_channel_bw(band, config.common_scs); + if (min_chan_bw == min_channel_bandwidth::invalid) { + fmt::print("Invalid combination for band n{} and subcarrier spacing {}.\n", band, to_string(config.common_scs)); + return false; + } + + // Check that the configured bandwidth is greater than or equal to the minimum bandwidth + if (bs_channel_bandwidth_to_MHz(config.channel_bw_mhz) < min_channel_bandwidth_to_MHz(min_chan_bw)) { fmt::print("Minimum supported bandwidth for n{} with SCS {} is {}MHz.\n", - config.band, + band, to_string(config.common_scs), - min_channel_bandwidth_to_MHz(band_helper::get_min_channel_bw(band, config.common_scs))); + min_channel_bandwidth_to_MHz(min_chan_bw)); return false; } @@ -709,16 +729,30 @@ static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& return false; } if (config.common_scs == srsran::subcarrier_spacing::kHz15 and - config.channel_bw_mhz > srsran::bs_channel_bandwidth_fr1::MHz50) { + config.channel_bw_mhz > srsran::bs_channel_bandwidth::MHz50) { fmt::print("Maximum Channel BW with SCS common 15kHz is 50MHz.\n"); return false; } if (config.common_scs == srsran::subcarrier_spacing::kHz30 and - config.channel_bw_mhz < srsran::bs_channel_bandwidth_fr1::MHz10) { + config.channel_bw_mhz < srsran::bs_channel_bandwidth::MHz10) { fmt::print("Minimum supported Channel BW with SCS common 30kHz is 10MHz.\n"); return false; } - + if (config.common_scs == srsran::subcarrier_spacing::kHz30 and + config.channel_bw_mhz > srsran::bs_channel_bandwidth::MHz100) { + fmt::print("Maximum Channel BW with SCS common 30kHz is 100MHz.\n"); + return false; + } + if (config.common_scs == srsran::subcarrier_spacing::kHz60 and + config.channel_bw_mhz > srsran::bs_channel_bandwidth::MHz200) { + fmt::print("Maximum Channel BW with SCS common 60kHz is 200MHz.\n"); + return false; + } + if (config.common_scs == srsran::subcarrier_spacing::kHz120 and + config.channel_bw_mhz > srsran::bs_channel_bandwidth::MHz400) { + fmt::print("Maximum Channel BW with SCS common 120kHz is 400MHz.\n"); + return false; + } if (!validate_dl_arfcn_and_band(config)) { return false; } diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config.h b/apps/units/flexible_du/split_7_2/ru_ofh_config.h index b5a0b39fd9..e6944539eb 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config.h +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config.h @@ -25,7 +25,7 @@ struct ru_ofh_unit_base_cell_config { /// \brief RU operating bandwidth. /// /// Set this option when the operating bandwidth of the RU is larger than the configured bandwidth of the cell. - std::optional ru_operating_bw; + std::optional ru_operating_bw; /// T1a maximum parameter for downlink Control-Plane in microseconds. std::chrono::microseconds T1a_max_cp_dl{500}; /// T1a minimum parameter for downlink Control-Plane in microseconds. diff --git a/apps/units/flexible_du/split_8/ru_sdr_config_validator.h b/apps/units/flexible_du/split_8/ru_sdr_config_validator.h index 3a5d6b5db7..2372be0c50 100644 --- a/apps/units/flexible_du/split_8/ru_sdr_config_validator.h +++ b/apps/units/flexible_du/split_8/ru_sdr_config_validator.h @@ -28,7 +28,7 @@ struct ru_sdr_cell_validation_config { /// PRACH preamble information. prach_preamble_information preamble_info; /// Channel bandwidth in MHz. - bs_channel_bandwidth_fr1 channel_bw_mhz; + bs_channel_bandwidth channel_bw_mhz; /// Duplex mode. duplex_mode dplx_mode; }; diff --git a/include/srsran/ofh/ofh_sector_config.h b/include/srsran/ofh/ofh_sector_config.h index d4e1f6a3a6..bcaad0a321 100644 --- a/include/srsran/ofh/ofh_sector_config.h +++ b/include/srsran/ofh/ofh_sector_config.h @@ -58,11 +58,11 @@ struct sector_configuration { /// Highest subcarrier spacing. subcarrier_spacing scs; /// Cell channel bandwidth. - bs_channel_bandwidth_fr1 bw; + bs_channel_bandwidth bw; /// \brief RU operating bandwidth. /// /// Set this option when the operating bandwidth of the RU is larger than the configured bandwidth of the cell. - bs_channel_bandwidth_fr1 ru_operating_bw; + bs_channel_bandwidth ru_operating_bw; /// PRACH eAxC. static_vector prach_eaxc; diff --git a/include/srsran/ofh/receiver/ofh_receiver_configuration.h b/include/srsran/ofh/receiver/ofh_receiver_configuration.h index 27f635b8d3..f5237d5c7a 100644 --- a/include/srsran/ofh/receiver/ofh_receiver_configuration.h +++ b/include/srsran/ofh/receiver/ofh_receiver_configuration.h @@ -43,7 +43,7 @@ struct receiver_config { /// \brief RU operating bandwidth. /// /// Set this option when the operating bandwidth of the RU is larger than the configured bandwidth of the cell. - bs_channel_bandwidth_fr1 ru_operating_bw; + bs_channel_bandwidth ru_operating_bw; /// Uplink compression parameters. ofh::ru_compression_params ul_compression_params; /// PRACH compression parameters. diff --git a/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h b/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h index b987060390..43099159b2 100644 --- a/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h +++ b/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h @@ -32,7 +32,7 @@ struct transmitter_config { /// Radio sector identifier. unsigned sector; /// Channel bandwidth. - bs_channel_bandwidth_fr1 bw; + bs_channel_bandwidth bw; /// Subcarrier spacing. subcarrier_spacing scs; /// Cyclic prefix. @@ -62,7 +62,7 @@ struct transmitter_config { /// MTU size. units::bytes mtu_size; /// RU working bandwidth. - bs_channel_bandwidth_fr1 ru_working_bw; + bs_channel_bandwidth ru_working_bw; /// Downlink compression parameters. ru_compression_params dl_compr_params; /// Uplink compression parameters. diff --git a/include/srsran/ran/band_helper.h b/include/srsran/ran/band_helper.h index 7d78819a28..c057582227 100644 --- a/include/srsran/ran/band_helper.h +++ b/include/srsran/ran/band_helper.h @@ -80,10 +80,10 @@ bool is_band_40mhz_min_ch_bw_equivalent(nr_band band); /// for bands n41, n77, n78, n79. /// \param[in] bw Channel Bandwidth in MHz, which is required to validate some bands' ARFCN values. /// \return If the DL ARFCN is invalid for the band, a std::string value is returned with the reason. -error_type is_dl_arfcn_valid_given_band(nr_band band, - uint32_t arfcn, - subcarrier_spacing scs, - bs_channel_bandwidth_fr1 bw = bs_channel_bandwidth_fr1::MHz10); +error_type is_dl_arfcn_valid_given_band(nr_band band, + uint32_t arfcn, + subcarrier_spacing scs, + bs_channel_bandwidth bw = bs_channel_bandwidth::MHz10); /// @brief Get the respective UL ARFCN of a DL ARFCN. /// @@ -194,7 +194,7 @@ double get_f_ref_from_abs_freq_point_a(double abs_freq_point_a, uint32_t nof_rbs /// \param[in] scs is the subcarrier spacing of reference for \f$N_{RB}\f$, as per TS 38.104, Table 5.3.2-1. /// \param[in] fr is frequency range FR1 or FR2. /// \return \f$N_{RB}\f$, as per TS 38.104, Table 5.3.2-1. -unsigned get_n_rbs_from_bw(bs_channel_bandwidth_fr1 bw, subcarrier_spacing scs, frequency_range fr); +unsigned get_n_rbs_from_bw(bs_channel_bandwidth bw, subcarrier_spacing scs, frequency_range fr); /// \brief Returns the minimum BS Channel Bandwidth for a given band and SCS from Table 5.3.5-1, TS 38.104, for FR1. /// @@ -328,10 +328,10 @@ std::optional get_ssb_arfcn(unsigned dl_arfcn, /// \param[in] ssb_scs SSB subcarrier spacing. /// \param[in] bw Channel Bandwidth in MHz, which is required to validate some bands' ARFCN values. /// \return If the ARFCN (GSCN) is invalid for the band, a std::string value is returned with the reason. -error_type is_ssb_arfcn_valid_given_band(uint32_t ssb_arfcn, - nr_band band, - subcarrier_spacing scs, - bs_channel_bandwidth_fr1 bw = bs_channel_bandwidth_fr1::invalid); +error_type is_ssb_arfcn_valid_given_band(uint32_t ssb_arfcn, + nr_band band, + subcarrier_spacing scs, + bs_channel_bandwidth bw = bs_channel_bandwidth::invalid); } // namespace band_helper diff --git a/include/srsran/ran/bs_channel_bandwidth.h b/include/srsran/ran/bs_channel_bandwidth.h index a2e29e42ce..d440d35515 100644 --- a/include/srsran/ran/bs_channel_bandwidth.h +++ b/include/srsran/ran/bs_channel_bandwidth.h @@ -14,8 +14,8 @@ namespace srsran { -/// Labels for the BS Channel Bandwidth for FR1, described in TS38.104, Table 5.3.2-1. -enum class bs_channel_bandwidth_fr1 { +/// Labels for the BS Channel Bandwidth, described in TS38.104, Table 5.3.2-1 for FR1 and Table 5.3.2-2 for FR2. +enum class bs_channel_bandwidth { invalid = 0, MHz5 = 5, MHz10 = 10, @@ -32,24 +32,26 @@ enum class bs_channel_bandwidth_fr1 { MHz80 = 80, MHz90 = 90, MHz100 = 100, + MHz200 = 200, + MHz400 = 400, }; /// Converts the BS channel bandwidth label into the actual BW value in MHz. -constexpr inline unsigned bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1 bw) +constexpr inline unsigned bs_channel_bandwidth_to_MHz(bs_channel_bandwidth bw) { return static_cast(bw); } /// Converts the actual BW value in MHz to the BS channel bandwidth label. -constexpr inline bs_channel_bandwidth_fr1 MHz_to_bs_channel_bandwidth(unsigned bw) +constexpr inline bs_channel_bandwidth MHz_to_bs_channel_bandwidth(unsigned bw) { - return static_cast(bw); + return static_cast(bw); } /// Labels for the Minimum Channel Bandwidth for FR1<\em>. This is not explicitly defined in the TS, but it is used -/// by TS 38.213, Section 13 for the Coreset 0 configuration. As per TS 38.104, Table 5.3.5-1, there are three possible -/// minimum BW: 5MHz, 10MHz, 20MHz, and 40MHz. -enum class min_channel_bandwidth { MHz5 = 0, MHz10, MHz20, MHz40, invalid }; +/// by TS 38.213, Section 13 for the Coreset 0 configuration. As per TS 38.104, Table 5.3.5-1 for FR1 and Table 5.3.5-2 +/// for FR2, there are three possible minimum BW: 5MHz, 10MHz, 20MHz, 40MHz and 50MHz. +enum class min_channel_bandwidth { MHz5 = 0, MHz10, MHz20, MHz40, MHz50, invalid }; /// Converts the Minimum Channel Bandwidth for FR1 into the actual BW value in MHz. constexpr inline unsigned min_channel_bandwidth_to_MHz(min_channel_bandwidth bw) @@ -63,6 +65,8 @@ constexpr inline unsigned min_channel_bandwidth_to_MHz(min_channel_bandwidth bw) return 20; case min_channel_bandwidth::MHz40: return 40; + case min_channel_bandwidth::MHz50: + return 50; default: report_fatal_error("Un-supported minimum channel bw."); } diff --git a/include/srsran/ran/ssb_gscn.h b/include/srsran/ran/ssb_gscn.h index a248e5d329..8399992ce5 100644 --- a/include/srsran/ran/ssb_gscn.h +++ b/include/srsran/ran/ssb_gscn.h @@ -27,10 +27,10 @@ namespace band_helper { /// \param[in] ssb_scs SSB subcarrier spacing. /// \param[in] bw Channel Bandwidth in MHz, which is required to validate some bands' GSCN values. /// \return If the GSCN is invalid for the band, a std::string value is returned with the reason. -error_type is_gscn_valid_given_band(unsigned gscn, - nr_band band, - subcarrier_spacing ssb_scs, - bs_channel_bandwidth_fr1 bw = bs_channel_bandwidth_fr1::invalid); +error_type is_gscn_valid_given_band(unsigned gscn, + nr_band band, + subcarrier_spacing ssb_scs, + bs_channel_bandwidth bw = bs_channel_bandwidth::invalid); /// \brief Get an iterator to the GSCN values for bands with special GSCN rasters. /// diff --git a/include/srsran/ru/ru_ofh_configuration.h b/include/srsran/ru/ru_ofh_configuration.h index bc90b38503..b7d411482f 100644 --- a/include/srsran/ru/ru_ofh_configuration.h +++ b/include/srsran/ru/ru_ofh_configuration.h @@ -28,11 +28,11 @@ struct ru_ofh_sector_configuration { /// Highest subcarrier spacing. subcarrier_spacing scs; /// Cell channel bandwidth. - bs_channel_bandwidth_fr1 bw; + bs_channel_bandwidth bw; /// \brief RU operating bandwidth. /// /// Set this option when the operating bandwidth of the RU is larger than the configured bandwidth of the cell. - std::optional ru_operating_bw; + std::optional ru_operating_bw; /// DU transmission window timing parameters. ofh::tx_window_timing_parameters tx_window_timing_params; diff --git a/include/srsran/scheduler/config/cell_config_builder_params.h b/include/srsran/scheduler/config/cell_config_builder_params.h index 178a9f1363..b1513be875 100644 --- a/include/srsran/scheduler/config/cell_config_builder_params.h +++ b/include/srsran/scheduler/config/cell_config_builder_params.h @@ -27,7 +27,7 @@ struct cell_config_builder_params { /// subCarrierSpacingCommon, as per \c MIB, TS 38.331. subcarrier_spacing scs_common = subcarrier_spacing::kHz15; /// BS Channel Bandwidth, as per TS 38.104, Section 5.3.1. - bs_channel_bandwidth_fr1 channel_bw_mhz = bs_channel_bandwidth_fr1::MHz10; + bs_channel_bandwidth channel_bw_mhz = bs_channel_bandwidth::MHz10; /// This ARFCN represents "f_ref" for DL, as per TS 38.211, Section 5.4.2.1. unsigned dl_arfcn = 365000; /// 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 diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index 7da8b3edf9..908c57ac4c 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -47,96 +47,109 @@ struct nr_band_raster { uint32_t dl_nref_last; }; -// From Table 5.4.2.3-1 in TS 38.104, this is the number of NR FR1 bands that has a DL allocated band (FDD, TDD or SDL). -// NOTE: Band 41 has two different Freq raster, we only consider raster 15kHz. -const uint32_t nof_nr_DL_bands_fr1 = 71; - -// Table with NR operating FR1 band and related ARFCN lower-bound and upper-bound. See Table 5.4.2.3-1 in TS 38.104. +// From Tables 5.4.2.3-1 and 5.4.2.3-2 in TS 38.104, table with NR operating FR1 and FR2 band and related ARFCN +// 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 -static constexpr std::array nr_band_table_fr1 = {{ - // 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}, - {nr_band::n5, delta_freq_raster::kHz100, 164800, 20, 169800, 173800, 20, 178800}, - {nr_band::n7, delta_freq_raster::kHz100, 500000, 20, 514000, 524000, 20, 538000}, - {nr_band::n8, delta_freq_raster::kHz100, 176000, 20, 183000, 185000, 20, 192000}, - {nr_band::n12, delta_freq_raster::kHz100, 139800, 20, 143200, 145800, 20, 149200}, - {nr_band::n13, delta_freq_raster::kHz100, 155400, 20, 157400, 149200, 20, 151200}, - {nr_band::n14, delta_freq_raster::kHz100, 157600, 20, 159600, 151600, 20, 153600}, - {nr_band::n18, delta_freq_raster::kHz100, 163000, 20, 166000, 172000, 20, 175000}, - {nr_band::n20, delta_freq_raster::kHz100, 166400, 20, 172400, 158200, 20, 164200}, - {nr_band::n25, delta_freq_raster::kHz100, 370000, 20, 383000, 386000, 20, 399000}, - {nr_band::n24, delta_freq_raster::kHz100, 325300, 20, 332100, 305000, 20, 311800}, - {nr_band::n26, delta_freq_raster::kHz100, 162800, 20, 169800, 171800, 20, 178800}, - {nr_band::n28, delta_freq_raster::kHz100, 140600, 20, 149600, 151600, 20, 160600}, - {nr_band::n28, delta_freq_raster::kHz100, 144608, 0, 144608, 155608, 0, 155608}, - {nr_band::n29, delta_freq_raster::kHz100, 0, 0, 0, 143400, 20, 145600}, - {nr_band::n30, delta_freq_raster::kHz100, 461000, 20, 463000, 470000, 20, 472000}, - {nr_band::n34, delta_freq_raster::kHz100, 402000, 20, 405000, 402000, 20, 405000}, - {nr_band::n38, delta_freq_raster::kHz100, 514000, 20, 524000, 514000, 20, 524000}, - {nr_band::n39, delta_freq_raster::kHz100, 376000, 20, 384000, 376000, 20, 384000}, - {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}, - {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}, - {nr_band::n50, delta_freq_raster::kHz100, 286400, 20, 303400, 286400, 20, 303400}, - {nr_band::n51, delta_freq_raster::kHz100, 285400, 20, 286400, 285400, 20, 286400}, - {nr_band::n53, delta_freq_raster::kHz100, 496700, 20, 499000, 496700, 20, 499000}, - {nr_band::n65, delta_freq_raster::kHz100, 384000, 20, 402000, 422000, 20, 440000}, - {nr_band::n66, delta_freq_raster::kHz100, 342000, 20, 356000, 422000, 20, 440000}, - {nr_band::n67, delta_freq_raster::kHz100, 0, 0, 0, 147600, 20, 151600}, - {nr_band::n70, delta_freq_raster::kHz100, 339000, 20, 342000, 399000, 20, 404000}, - {nr_band::n71, delta_freq_raster::kHz100, 132600, 20, 139600, 123400, 20, 130400}, - {nr_band::n74, delta_freq_raster::kHz100, 285400, 20, 294000, 295000, 20, 303600}, - {nr_band::n75, delta_freq_raster::kHz100, 0, 0, 0, 286400, 20, 303400}, - {nr_band::n76, delta_freq_raster::kHz100, 0, 0, 0, 285400, 20, 286400}, - {nr_band::n77, delta_freq_raster::kHz15, 620000, 1, 680000, 620000, 1, 680000}, - {nr_band::n77, delta_freq_raster::kHz30, 620000, 2, 680000, 620000, 2, 680000}, - {nr_band::n78, delta_freq_raster::kHz15, 620000, 1, 653333, 620000, 1, 653333}, - {nr_band::n78, delta_freq_raster::kHz30, 620000, 2, 653332, 620000, 2, 653332}, - {nr_band::n79, delta_freq_raster::kHz15, 693334, 1, 733333, 693334, 1, 733333}, - {nr_band::n79, delta_freq_raster::kHz30, 693334, 2, 733332, 693334, 2, 733332}, - {nr_band::n80, delta_freq_raster::kHz100, 342000, 20, 357000, 0, 0, 0}, - {nr_band::n81, delta_freq_raster::kHz100, 176000, 20, 183000, 0, 0, 0}, - {nr_band::n82, delta_freq_raster::kHz100, 166400, 20, 172400, 0, 0, 0}, - {nr_band::n83, delta_freq_raster::kHz100, 140600, 20, 149600, 0, 0, 0}, - {nr_band::n84, delta_freq_raster::kHz100, 384000, 20, 396000, 0, 0, 0}, - {nr_band::n85, delta_freq_raster::kHz100, 139600, 20, 143200, 145600, 20, 149200}, - {nr_band::n86, delta_freq_raster::kHz100, 342000, 20, 356000, 0, 0, 0}, - {nr_band::n89, delta_freq_raster::kHz100, 164800, 20, 169800, 0, 0, 0}, - {nr_band::n90, delta_freq_raster::kHz15, 499200, 3, 537999, 499200, 3, 537999}, - {nr_band::n90, delta_freq_raster::kHz30, 499200, 6, 537996, 499200, 6, 537996}, - {nr_band::n90, delta_freq_raster::kHz100, 499200, 20, 538000, 499200, 20, 538000}, - {nr_band::n91, delta_freq_raster::kHz100, 166400, 20, 172400, 285400, 20, 286400}, - {nr_band::n92, delta_freq_raster::kHz100, 166400, 20, 172400, 286400, 20, 303400}, - {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}, - {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}, - {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}, - {nr_band::n255, delta_freq_raster::kHz100, 305000, 20, 311800, 305000, 20, 311800}, - {nr_band::n256, delta_freq_raster::kHz100, 434000, 20, 440000, 434000, 20, 440000} +// 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; +static constexpr std::array nr_band_table = {{ + // 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}, + {nr_band::n5, delta_freq_raster::kHz100, 164800, 20, 169800, 173800, 20, 178800}, + {nr_band::n7, delta_freq_raster::kHz100, 500000, 20, 514000, 524000, 20, 538000}, + {nr_band::n8, delta_freq_raster::kHz100, 176000, 20, 183000, 185000, 20, 192000}, + {nr_band::n12, delta_freq_raster::kHz100, 139800, 20, 143200, 145800, 20, 149200}, + {nr_band::n13, delta_freq_raster::kHz100, 155400, 20, 157400, 149200, 20, 151200}, + {nr_band::n14, delta_freq_raster::kHz100, 157600, 20, 159600, 151600, 20, 153600}, + {nr_band::n18, delta_freq_raster::kHz100, 163000, 20, 166000, 172000, 20, 175000}, + {nr_band::n20, delta_freq_raster::kHz100, 166400, 20, 172400, 158200, 20, 164200}, + {nr_band::n25, delta_freq_raster::kHz100, 370000, 20, 383000, 386000, 20, 399000}, + {nr_band::n24, delta_freq_raster::kHz100, 325300, 20, 332100, 305000, 20, 311800}, + {nr_band::n26, delta_freq_raster::kHz100, 162800, 20, 169800, 171800, 20, 178800}, + {nr_band::n28, delta_freq_raster::kHz100, 140600, 20, 149600, 151600, 20, 160600}, + {nr_band::n28, delta_freq_raster::kHz100, 144608, 0, 144608, 155608, 0, 155608}, + {nr_band::n29, delta_freq_raster::kHz100, 0, 0, 0, 143400, 20, 145600}, + {nr_band::n30, delta_freq_raster::kHz100, 461000, 20, 463000, 470000, 20, 472000}, + {nr_band::n34, delta_freq_raster::kHz100, 402000, 20, 405000, 402000, 20, 405000}, + {nr_band::n38, delta_freq_raster::kHz100, 514000, 20, 524000, 514000, 20, 524000}, + {nr_band::n39, delta_freq_raster::kHz100, 376000, 20, 384000, 376000, 20, 384000}, + {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}, + {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}, + {nr_band::n50, delta_freq_raster::kHz100, 286400, 20, 303400, 286400, 20, 303400}, + {nr_band::n51, delta_freq_raster::kHz100, 285400, 20, 286400, 285400, 20, 286400}, + {nr_band::n53, delta_freq_raster::kHz100, 496700, 20, 499000, 496700, 20, 499000}, + {nr_band::n65, delta_freq_raster::kHz100, 384000, 20, 402000, 422000, 20, 440000}, + {nr_band::n66, delta_freq_raster::kHz100, 342000, 20, 356000, 422000, 20, 440000}, + {nr_band::n67, delta_freq_raster::kHz100, 0, 0, 0, 147600, 20, 151600}, + {nr_band::n70, delta_freq_raster::kHz100, 339000, 20, 342000, 399000, 20, 404000}, + {nr_band::n71, delta_freq_raster::kHz100, 132600, 20, 139600, 123400, 20, 130400}, + {nr_band::n74, delta_freq_raster::kHz100, 285400, 20, 294000, 295000, 20, 303600}, + {nr_band::n75, delta_freq_raster::kHz100, 0, 0, 0, 286400, 20, 303400}, + {nr_band::n76, delta_freq_raster::kHz100, 0, 0, 0, 285400, 20, 286400}, + {nr_band::n77, delta_freq_raster::kHz15, 620000, 1, 680000, 620000, 1, 680000}, + {nr_band::n77, delta_freq_raster::kHz30, 620000, 2, 680000, 620000, 2, 680000}, + {nr_band::n78, delta_freq_raster::kHz15, 620000, 1, 653333, 620000, 1, 653333}, + {nr_band::n78, delta_freq_raster::kHz30, 620000, 2, 653332, 620000, 2, 653332}, + {nr_band::n79, delta_freq_raster::kHz15, 693334, 1, 733333, 693334, 1, 733333}, + {nr_band::n79, delta_freq_raster::kHz30, 693334, 2, 733332, 693334, 2, 733332}, + {nr_band::n80, delta_freq_raster::kHz100, 342000, 20, 357000, 0, 0, 0}, + {nr_band::n81, delta_freq_raster::kHz100, 176000, 20, 183000, 0, 0, 0}, + {nr_band::n82, delta_freq_raster::kHz100, 166400, 20, 172400, 0, 0, 0}, + {nr_band::n83, delta_freq_raster::kHz100, 140600, 20, 149600, 0, 0, 0}, + {nr_band::n84, delta_freq_raster::kHz100, 384000, 20, 396000, 0, 0, 0}, + {nr_band::n85, delta_freq_raster::kHz100, 139600, 20, 143200, 145600, 20, 149200}, + {nr_band::n86, delta_freq_raster::kHz100, 342000, 20, 356000, 0, 0, 0}, + {nr_band::n89, delta_freq_raster::kHz100, 164800, 20, 169800, 0, 0, 0}, + {nr_band::n90, delta_freq_raster::kHz15, 499200, 3, 537999, 499200, 3, 537999}, + {nr_band::n90, delta_freq_raster::kHz30, 499200, 6, 537996, 499200, 6, 537996}, + {nr_band::n90, delta_freq_raster::kHz100, 499200, 20, 538000, 499200, 20, 538000}, + {nr_band::n91, delta_freq_raster::kHz100, 166400, 20, 172400, 285400, 20, 286400}, + {nr_band::n92, delta_freq_raster::kHz100, 166400, 20, 172400, 286400, 20, 303400}, + {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}, + {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}, + {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}, + {nr_band::n255, delta_freq_raster::kHz100, 305000, 20, 311800, 305000, 20, 311800}, + {nr_band::n256, delta_freq_raster::kHz100, 434000, 20, 440000, 434000, 20, 440000}, + {nr_band::n257, delta_freq_raster::kHz60, 2054166, 1, 2104165, 2054166, 1, 2104165}, + {nr_band::n257, delta_freq_raster::kHz120, 2054167, 2, 2104165, 2054167, 2, 2104165}, + {nr_band::n258, delta_freq_raster::kHz60, 2016667, 1, 2070832, 2016667, 1, 2070832}, + {nr_band::n258, delta_freq_raster::kHz120, 2016667, 2, 2070831, 2016667, 2, 2070831}, + {nr_band::n259, delta_freq_raster::kHz60, 2270833, 1, 2337499, 2270833, 1, 2337499}, + {nr_band::n259, delta_freq_raster::kHz120, 2270833, 2, 2337499, 2270833, 2, 2337499}, + {nr_band::n260, delta_freq_raster::kHz60, 2229166, 1, 2279165, 2229166, 1, 2279165}, + {nr_band::n260, delta_freq_raster::kHz120, 2229167, 2, 2279165, 2229167, 2, 2279165}, + {nr_band::n261, delta_freq_raster::kHz60, 2070833, 1, 2084999, 2070833, 1, 2084999}, + {nr_band::n261, delta_freq_raster::kHz120, 2070833, 2, 2084999, 2070833, 2, 2084999}, + {nr_band::n262, delta_freq_raster::kHz60, 2399166, 1, 2415832, 2399166, 1, 2415832}, + {nr_band::n262, delta_freq_raster::kHz120, 2399167, 2, 2415831, 2399167, 2, 2415831}, // clang-format on }}; -// NR operating band in FR1 with related Duplex Mode. See TS 38.101-1 Table 5.2-1. +// NR operating band with related Duplex Mode. See TS 38.101-1 Table 5.2-1 for FR1 and Table 5.2-2 for FR2. struct nr_operating_band { nr_band band; duplex_mode duplex; }; -static const uint32_t nof_nr_operating_band_fr1 = 62; -static constexpr std::array nr_operating_bands_fr1 = {{ +static const uint32_t nof_nr_operating_band = 68; +static constexpr std::array nr_operating_bands = {{ // clang-format off {nr_band::n1, duplex_mode::FDD}, {nr_band::n2, duplex_mode::FDD}, @@ -199,7 +212,13 @@ static constexpr std::array nr_ope {nr_band::n102, duplex_mode::TDD}, {nr_band::n104, duplex_mode::TDD}, {nr_band::n255, duplex_mode::FDD}, - {nr_band::n256, duplex_mode::FDD} + {nr_band::n256, duplex_mode::FDD}, + {nr_band::n257, duplex_mode::TDD}, + {nr_band::n258, duplex_mode::TDD}, + {nr_band::n259, duplex_mode::TDD}, + {nr_band::n260, duplex_mode::TDD}, + {nr_band::n261, duplex_mode::TDD}, + {nr_band::n262, duplex_mode::TDD} // clang-format on }}; @@ -210,10 +229,10 @@ struct nr_band_ssb_scs_case { subcarrier_spacing scs; ssb_pattern_case pattern; }; -// NR FR1 operating bands with corresponding SSB Subcarrier Spacing and SSB pattern case, as per Table 5.4.3.3-1, -// TS 38.104, Rel. 17, version 17.8.0. -static const uint32_t nof_nr_ssb_bands_fr1 = 60; -static constexpr std::array nr_ssb_band_scs_case_table_fr1 = {{ +// NR operating bands with corresponding SSB Subcarrier Spacing and SSB pattern case, as per Table 5.4.3.3-1 for FR1 and +// Table 5.4.3.3-1 for FR2, TS 38.104, Rel. 17, version 17.8.0. +static const uint32_t nof_nr_ssb_bands = 72; +static constexpr std::array nr_ssb_band_scs_case_table = {{ // clang-format off {nr_band::n1, subcarrier_spacing::kHz15, ssb_pattern_case::A}, {nr_band::n2, subcarrier_spacing::kHz15, ssb_pattern_case::A}, @@ -275,6 +294,18 @@ static constexpr std::array nr_ssb_b {nr_band::n104, subcarrier_spacing::kHz30, ssb_pattern_case::C}, {nr_band::n255, subcarrier_spacing::kHz15, ssb_pattern_case::A}, {nr_band::n256, subcarrier_spacing::kHz15, ssb_pattern_case::A}, + {nr_band::n257, subcarrier_spacing::kHz120, ssb_pattern_case::D}, + {nr_band::n257, subcarrier_spacing::kHz240, ssb_pattern_case::E}, + {nr_band::n258, subcarrier_spacing::kHz120, ssb_pattern_case::D}, + {nr_band::n258, subcarrier_spacing::kHz240, ssb_pattern_case::E}, + {nr_band::n259, subcarrier_spacing::kHz120, ssb_pattern_case::D}, + {nr_band::n259, subcarrier_spacing::kHz240, ssb_pattern_case::E}, + {nr_band::n260, subcarrier_spacing::kHz120, ssb_pattern_case::D}, + {nr_band::n260, subcarrier_spacing::kHz240, ssb_pattern_case::E}, + {nr_band::n261, subcarrier_spacing::kHz120, ssb_pattern_case::D}, + {nr_band::n261, subcarrier_spacing::kHz240, ssb_pattern_case::E}, + {nr_band::n262, subcarrier_spacing::kHz120, ssb_pattern_case::D}, + {nr_band::n262, subcarrier_spacing::kHz240, ssb_pattern_case::E}, // clang-format on }}; @@ -308,46 +339,66 @@ static constexpr std::array nr_fr_params = {{ // clang-format on }}; -struct n_rb_per_scs { - bs_channel_bandwidth_fr1 bw; - unsigned n_rb_15kHz; - unsigned n_rb_30kHz; - unsigned n_rb_60kHz; +struct n_rb_per_scs_fr1 { + bs_channel_bandwidth bw; + unsigned n_rb_15kHz; + unsigned n_rb_30kHz; + unsigned n_rb_60kHz; }; // This implements Table 5.3.2-1 in TS 38.104. Value N_RB = 0 represent N/A. -static const std::array tx_bw_config_fr1 = {{ +static const std::array tx_bw_config_fr1 = {{ // clang-format off // BW = 5MHz. - {bs_channel_bandwidth_fr1::MHz5, 25, 11, 0}, + {bs_channel_bandwidth::MHz5, 25, 11, 0}, // BW = 10MHz. - {bs_channel_bandwidth_fr1::MHz10, 52, 24, 11}, + {bs_channel_bandwidth::MHz10, 52, 24, 11}, // BW = 15MHz. - {bs_channel_bandwidth_fr1::MHz15, 79, 38, 18}, + {bs_channel_bandwidth::MHz15, 79, 38, 18}, // BW = 20MHz. - {bs_channel_bandwidth_fr1::MHz20, 106, 51, 24}, + {bs_channel_bandwidth::MHz20, 106, 51, 24}, // BW = 25MHz. - {bs_channel_bandwidth_fr1::MHz25, 133, 65, 31}, + {bs_channel_bandwidth::MHz25, 133, 65, 31}, // BW = 30MHz. - {bs_channel_bandwidth_fr1::MHz30, 160, 78, 38}, + {bs_channel_bandwidth::MHz30, 160, 78, 38}, // BW = 35MHz. - {bs_channel_bandwidth_fr1::MHz35, 188, 92, 44}, + {bs_channel_bandwidth::MHz35, 188, 92, 44}, // BW = 40MHz. - {bs_channel_bandwidth_fr1::MHz40, 216, 106, 51}, + {bs_channel_bandwidth::MHz40, 216, 106, 51}, // BW = 45MHz. - {bs_channel_bandwidth_fr1::MHz45, 242, 119, 58}, + {bs_channel_bandwidth::MHz45, 242, 119, 58}, // BW = 50MHz. - {bs_channel_bandwidth_fr1::MHz50, 270, 133, 65}, + {bs_channel_bandwidth::MHz50, 270, 133, 65}, // BW = 60MHz. - {bs_channel_bandwidth_fr1::MHz60, 0, 162, 79}, + {bs_channel_bandwidth::MHz60, 0, 162, 79}, // BW = 70MHz. - {bs_channel_bandwidth_fr1::MHz70, 0, 189, 93}, + {bs_channel_bandwidth::MHz70, 0, 189, 93}, // BW = 80MHz. - {bs_channel_bandwidth_fr1::MHz80, 0, 217, 107}, + {bs_channel_bandwidth::MHz80, 0, 217, 107}, // BW = 90MHz. - {bs_channel_bandwidth_fr1::MHz90, 0, 245, 121}, + {bs_channel_bandwidth::MHz90, 0, 245, 121}, // BW = 100MHz. - {bs_channel_bandwidth_fr1::MHz100, 0, 273, 135} + {bs_channel_bandwidth::MHz100, 0, 273, 135} + // clang-format on +}}; + +struct n_rb_per_scs_fr2 { + bs_channel_bandwidth bw; + unsigned n_rb_60kHz; + unsigned n_rb_120kHz; +}; + +// This implements Table 5.3.2-2 in TS 38.104. Value N_RB = 0 represent N/A. +static const std::array tx_bw_config_fr2 = {{ + // clang-format off + // BW = 50MHz. + {bs_channel_bandwidth::MHz50, 66, 32}, + // BW = 100MHz. + {bs_channel_bandwidth::MHz100, 132, 66}, + // BW = 200MHz. + {bs_channel_bandwidth::MHz200, 264, 132}, + // BW = 400MHz. + {bs_channel_bandwidth::MHz400, 0, 264}, // clang-format on }}; @@ -361,13 +412,13 @@ static nr_band_raster fetch_band_raster(nr_band band, std::optional validate_band_n28(uint32_t arfcn, bs_channel_bandwidth_fr1 bw) +static error_type validate_band_n28(uint32_t arfcn, bs_channel_bandwidth bw) { const nr_band_raster band_raster = fetch_band_raster(nr_band::n28, {}); if (band_raster.band == srsran::nr_band::invalid) { @@ -420,7 +471,7 @@ static error_type validate_band_n28(uint32_t arfcn, bs_channel_band // 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_fr1::MHz40 and arfcn == dl_arfnc_40MHz) { + if (bw == srsran::bs_channel_bandwidth::MHz40 and arfcn == dl_arfnc_40MHz) { return error_type{}; } @@ -433,7 +484,7 @@ static error_type validate_band_n28(uint32_t arfcn, bs_channel_band // Validates band n46, whose valid ARFCN values depend on the channel BW, as per Table 5.4.2.3-1, TS 38.104, // version 17.8.0. -static error_type validate_band_n46(uint32_t arfcn, bs_channel_bandwidth_fr1 bw) +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 = { @@ -471,27 +522,27 @@ static error_type validate_band_n46(uint32_t arfcn, bs_channel_band const char* error_msg = {"Only a restricted set of DL-ARFCN values are allowed in band n46"}; switch (bw) { - case bs_channel_bandwidth_fr1::MHz10: { + case bs_channel_bandwidth::MHz10: { return dl_arfcn_exist(span(n46_b_10_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz20: { + case bs_channel_bandwidth::MHz20: { return dl_arfcn_exist(span(n46_b_20_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz40: { + case bs_channel_bandwidth::MHz40: { return dl_arfcn_exist(span(n46_b_40_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz60: { + case bs_channel_bandwidth::MHz60: { return dl_arfcn_exist(span(n46_b_60_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz80: { + case bs_channel_bandwidth::MHz80: { return dl_arfcn_exist(span(n46_b_80_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz100: { + case bs_channel_bandwidth::MHz100: { return dl_arfcn_exist(span(n46_b_100_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } @@ -502,7 +553,7 @@ static error_type validate_band_n46(uint32_t arfcn, bs_channel_band // Validates band n66, whose valid ARFCN values depend on the channel BW, as per Table 5.4.2.3-1, TS 38.104, // version 17.8.0. -static error_type validate_band_n96(uint32_t arfcn, bs_channel_bandwidth_fr1 bw) +static error_type validate_band_n96(uint32_t arfcn, bs_channel_bandwidth bw) { const std::array b_20_dlarfnc = { // clang-format off @@ -551,23 +602,23 @@ static error_type validate_band_n96(uint32_t arfcn, bs_channel_band const char* error_msg = {"Only a restricted set of DL-ARFCN values are allowed in band n96"}; switch (bw) { - case bs_channel_bandwidth_fr1::MHz20: { + case bs_channel_bandwidth::MHz20: { return dl_arfcn_exist(span(b_20_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz40: { + case bs_channel_bandwidth::MHz40: { return dl_arfcn_exist(span(b_40_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz60: { + case bs_channel_bandwidth::MHz60: { return dl_arfcn_exist(span(b_60_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz80: { + case bs_channel_bandwidth::MHz80: { return dl_arfcn_exist(span(b_80_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz100: { + case bs_channel_bandwidth::MHz100: { return dl_arfcn_exist(span(b_100_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } @@ -578,7 +629,7 @@ static error_type validate_band_n96(uint32_t arfcn, bs_channel_band // Validates band n102, whose valid ARFCN values depend on the channel BW, as per Table 5.4.2.3-1, TS 38.104, // version 17.8.0. -static error_type validate_band_n102(uint32_t arfcn, bs_channel_bandwidth_fr1 bw) +static error_type validate_band_n102(uint32_t arfcn, bs_channel_bandwidth bw) { const std::array b_20_dlarfnc = { // clang-format off @@ -611,23 +662,23 @@ static error_type validate_band_n102(uint32_t arfcn, bs_channel_ban const char* error_msg = {"Only a restricted set of DL-ARFCN values are allowed in band n102"}; switch (bw) { - case bs_channel_bandwidth_fr1::MHz20: { + case bs_channel_bandwidth::MHz20: { return dl_arfcn_exist(span(b_20_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz40: { + case bs_channel_bandwidth::MHz40: { return dl_arfcn_exist(span(b_40_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz60: { + case bs_channel_bandwidth::MHz60: { return dl_arfcn_exist(span(b_60_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz80: { + case bs_channel_bandwidth::MHz80: { return dl_arfcn_exist(span(b_80_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } - case bs_channel_bandwidth_fr1::MHz100: { + case bs_channel_bandwidth::MHz100: { return dl_arfcn_exist(span(b_100_dlarfnc), arfcn) ? error_type{} : make_unexpected(fmt::format(error_msg)); } @@ -675,7 +726,7 @@ nr_band srsran::band_helper::get_band_from_dl_arfcn(uint32_t arfcn) return nr_band::n28; } - for (const nr_band_raster& band : nr_band_table_fr1) { + for (const nr_band_raster& band : nr_band_table) { // Check given ARFCN is between the first and last possible ARFCN. if (arfcn >= band.dl_nref_first and arfcn <= band.dl_nref_last and ((arfcn - band.dl_nref_first) % band.dl_nref_step) == 0) { @@ -685,10 +736,10 @@ nr_band srsran::band_helper::get_band_from_dl_arfcn(uint32_t arfcn) return nr_band::invalid; } -error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_band band, - uint32_t arfcn, - subcarrier_spacing scs, - bs_channel_bandwidth_fr1 bw) +error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_band band, + uint32_t arfcn, + subcarrier_spacing scs, + bs_channel_bandwidth bw) { // Validates first the bands with non-standard ARFCN values. if (band == nr_band::n28) { @@ -724,7 +775,12 @@ error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_ban band_delta_freq_raster = scs == subcarrier_spacing::kHz15 ? delta_freq_raster::kHz15 : delta_freq_raster::kHz30; } - for (const nr_band_raster& raster_band : nr_band_table_fr1) { + // Update Delta freq raster based on SCS for FR2 bands. + if (get_freq_range(band) == frequency_range::FR2) { + band_delta_freq_raster = (scs == subcarrier_spacing::kHz60) ? delta_freq_raster::kHz60 : delta_freq_raster::kHz120; + } + + 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 >= raster_band.dl_nref_first and arfcn <= raster_band.dl_nref_last and ((arfcn - raster_band.dl_nref_first) % raster_band.dl_nref_step) == 0) { @@ -737,7 +793,7 @@ error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_ban raster_band.dl_nref_step)); } } - return make_unexpected(fmt::format("Band is not valid")); + 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) @@ -758,7 +814,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_fr1) { + for (const nr_band_raster& b_it : nr_band_table) { if (b_it.band == get_band_from_dl_arfcn(dl_arfcn)) { 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); @@ -802,7 +858,7 @@ bool srsran::band_helper::is_band_40mhz_min_ch_bw_equivalent(nr_band band) ssb_pattern_case srsran::band_helper::get_ssb_pattern(nr_band band, subcarrier_spacing scs) { // Look for the given band and SCS. - for (const nr_band_ssb_scs_case& ssb_scs_case : nr_ssb_band_scs_case_table_fr1) { + for (const nr_band_ssb_scs_case& ssb_scs_case : nr_ssb_band_scs_case_table) { // As bands are in ascending order, do not waste more time if the current band is bigger. if (ssb_scs_case.band > band) { return ssb_pattern_case::invalid; @@ -845,7 +901,7 @@ subcarrier_spacing srsran::band_helper::get_most_suitable_ssb_scs(nr_band band, subcarrier_spacing lowest_scs = subcarrier_spacing::invalid; // Look for the given band and SCS - for (const nr_band_ssb_scs_case& ssb_case : nr_ssb_band_scs_case_table_fr1) { + for (const nr_band_ssb_scs_case& ssb_case : nr_ssb_band_scs_case_table) { // Check if band and SCS match. if (ssb_case.band == band) { // If the SCS match with common, then that's the most suitable. @@ -872,7 +928,7 @@ subcarrier_spacing srsran::band_helper::get_most_suitable_ssb_scs(nr_band band, duplex_mode srsran::band_helper::get_duplex_mode(nr_band band) { // Look for the given band. - for (const nr_operating_band& b : nr_operating_bands_fr1) { + for (const nr_operating_band& b : nr_operating_bands) { // Check if band and SCS match! if (b.band == band) { return b.duplex; @@ -955,15 +1011,32 @@ srsran::band_helper::get_f_ref_from_abs_freq_point_a(double abs_freq_point_a, ui return abs_freq_point_a + static_cast(delta_point_a_f_ref * scs_to_khz(scs) * KHZ_TO_HZ); } -unsigned srsran::band_helper::get_n_rbs_from_bw(bs_channel_bandwidth_fr1 bw, subcarrier_spacing scs, frequency_range fr) +unsigned srsran::band_helper::get_n_rbs_from_bw(bs_channel_bandwidth bw, subcarrier_spacing scs, frequency_range fr) { + // Search on the table \ref tx_bw_config_fr2 for the BS channel bandwidth and return the N_RB corresponding to SCS. + if (fr == frequency_range::FR2) { + // Return an invalid value in case the input parameters are not valid. + if ((scs < subcarrier_spacing::kHz60) || (scs > subcarrier_spacing::kHz120)) { + return 0; + } + + for (unsigned bw_idx = 0; bw_idx != tx_bw_config_fr2.size(); ++bw_idx) { + if (tx_bw_config_fr2[bw_idx].bw == bw) { + if (scs == subcarrier_spacing::kHz60) { + return tx_bw_config_fr2[bw_idx].n_rb_60kHz; + } + return tx_bw_config_fr2[bw_idx].n_rb_120kHz; + } + } + } + // Return an invalid value in case the input parameters are not valid. - if (fr != frequency_range::FR1 or scs > subcarrier_spacing::kHz60) { + if (scs > subcarrier_spacing::kHz60) { return 0; } // Search on the table \ref tx_bw_config_fr1 for the BS channel bandwidth and return the N_RB corresponding to SCS. - for (unsigned bw_idx = 0; bw_idx < tx_bw_config_fr1.size(); ++bw_idx) { + for (unsigned bw_idx = 0; bw_idx != tx_bw_config_fr1.size(); ++bw_idx) { if (tx_bw_config_fr1[bw_idx].bw == bw) { if (scs == subcarrier_spacing::kHz15) { return tx_bw_config_fr1[bw_idx].n_rb_15kHz; @@ -1085,6 +1158,16 @@ min_channel_bandwidth srsran::band_helper::get_min_channel_bw(nr_band nr_band, s return min_channel_bandwidth::invalid; } } + case nr_band::n257: + case nr_band::n258: + case nr_band::n259: + case nr_band::n260: + case nr_band::n261: + if ((scs == subcarrier_spacing::kHz60) || (scs == subcarrier_spacing::kHz120)) { + return min_channel_bandwidth::MHz50; + } else { + return min_channel_bandwidth::invalid; + } default: return min_channel_bandwidth::invalid; } @@ -1411,10 +1494,10 @@ std::optional srsran::band_helper::get_ssb_arfcn(unsigned return {}; } -error_type srsran::band_helper::is_ssb_arfcn_valid_given_band(uint32_t ssb_arfcn, - nr_band band, - subcarrier_spacing ssb_scs, - bs_channel_bandwidth_fr1 bw) +error_type srsran::band_helper::is_ssb_arfcn_valid_given_band(uint32_t ssb_arfcn, + nr_band band, + subcarrier_spacing ssb_scs, + bs_channel_bandwidth bw) { // Convert the ARFCN to GSCN. std::optional gscn = band_helper::get_gscn_from_ss_ref(nr_arfcn_to_freq(ssb_arfcn)); diff --git a/lib/ran/ssb_gscn.cpp b/lib/ran/ssb_gscn.cpp index 3972c69b79..c593d0d04c 100644 --- a/lib/ran/ssb_gscn.cpp +++ b/lib/ran/ssb_gscn.cpp @@ -122,7 +122,7 @@ static const std::array ssb_gscn_raster_ta // Helper that validates the GSCN of bands with irregular or special rasters. static error_type -validate_irregular_gscn_rasters(unsigned gscn, nr_band band, subcarrier_spacing ssb_scs, bs_channel_bandwidth_fr1 bw) +validate_irregular_gscn_rasters(unsigned gscn, nr_band band, subcarrier_spacing ssb_scs, bs_channel_bandwidth bw) { bool is_gscn_valid = false; @@ -144,7 +144,7 @@ validate_irregular_gscn_rasters(unsigned gscn, nr_band band, subcarrier_spacing const unsigned n79_large_bw_gscn_first = 8480U; const unsigned n79_large_bw_gscn_step = 16U; const unsigned n79_large_bw_gscn_last = 8880U; - if (bw < bs_channel_bandwidth_fr1::MHz40) { + if (bw < bs_channel_bandwidth::MHz40) { is_gscn_valid = gscn >= n79_narrow_bw_gscn_first and gscn <= n79_narrow_bw_gscn_last; } else { is_gscn_valid = gscn >= n79_large_bw_gscn_first and gscn <= n79_large_bw_gscn_last and @@ -155,7 +155,7 @@ validate_irregular_gscn_rasters(unsigned gscn, nr_band band, subcarrier_spacing const unsigned n90_narrow_bw_gscn_last = 6718U; const unsigned n90_large_bw_gscn_first = 6246U; const unsigned n90_large_bw_gscn_last = 6717U; - if (bw < bs_channel_bandwidth_fr1::MHz10) { + if (bw < bs_channel_bandwidth::MHz10) { is_gscn_valid = gscn >= n90_narrow_bw_gscn_first and gscn <= n90_narrow_bw_gscn_last; } else { is_gscn_valid = gscn >= n90_large_bw_gscn_first and gscn <= n90_large_bw_gscn_last; @@ -171,10 +171,10 @@ validate_irregular_gscn_rasters(unsigned gscn, nr_band band, subcarrier_spacing : make_unexpected(fmt::format("GSCN {} is not valid for band {} with SSB SCS {}", gscn, band, ssb_scs)); } -error_type srsran::band_helper::is_gscn_valid_given_band(unsigned gscn, - nr_band band, - subcarrier_spacing ssb_scs, - bs_channel_bandwidth_fr1 bw) +error_type srsran::band_helper::is_gscn_valid_given_band(unsigned gscn, + nr_band band, + subcarrier_spacing ssb_scs, + bs_channel_bandwidth bw) { // Search for the GSCN in the table of regular rasters, first. for (const ssb_gscn_raster& raster : ssb_gscn_raster_table_fr1) { diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 6b2adc4b06..3e876f30d7 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -1125,7 +1125,7 @@ static cell_config_builder_params generate_custom_cell_config_builder_params(dup params.dl_arfcn = dplx_mode == duplex_mode::FDD ? 530000 : 520002; params.band = band_helper::get_band_from_dl_arfcn(params.dl_arfcn); params.channel_bw_mhz = - dplx_mode == duplex_mode::FDD ? srsran::bs_channel_bandwidth_fr1::MHz20 : bs_channel_bandwidth_fr1::MHz100; + dplx_mode == duplex_mode::FDD ? srsran::bs_channel_bandwidth::MHz20 : bs_channel_bandwidth::MHz100; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; diff --git a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp index 78a009dfc8..d6ce4d6b09 100644 --- a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp +++ b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp @@ -24,13 +24,13 @@ using namespace srsran; // Random generator. static std::mt19937 rgen(0); -static unsigned nof_repetitions = 10000; -static bool silent = false; -static std::string method = "bfp"; -static std::string impl_type = "auto"; -static unsigned nof_ports = 1; -static bs_channel_bandwidth_fr1 bw = srsran::bs_channel_bandwidth_fr1::MHz20; -static subcarrier_spacing scs = subcarrier_spacing::kHz30; +static unsigned nof_repetitions = 10000; +static bool silent = false; +static std::string method = "bfp"; +static std::string impl_type = "auto"; +static unsigned nof_ports = 1; +static bs_channel_bandwidth bw = srsran::bs_channel_bandwidth::MHz20; +static subcarrier_spacing scs = subcarrier_spacing::kHz30; static void usage(const char* prog) { @@ -47,44 +47,44 @@ static void usage(const char* prog) static bool validate_bw(unsigned bandwidth) { switch (bandwidth) { - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz5): - bw = bs_channel_bandwidth_fr1::MHz5; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz5): + bw = bs_channel_bandwidth::MHz5; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz10): - bw = bs_channel_bandwidth_fr1::MHz10; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz10): + bw = bs_channel_bandwidth::MHz10; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz15): - bw = bs_channel_bandwidth_fr1::MHz15; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz15): + bw = bs_channel_bandwidth::MHz15; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz20): - bw = bs_channel_bandwidth_fr1::MHz20; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz20): + bw = bs_channel_bandwidth::MHz20; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz25): - bw = bs_channel_bandwidth_fr1::MHz25; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz25): + bw = bs_channel_bandwidth::MHz25; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz30): - bw = bs_channel_bandwidth_fr1::MHz30; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz30): + bw = bs_channel_bandwidth::MHz30; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz40): - bw = bs_channel_bandwidth_fr1::MHz40; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz40): + bw = bs_channel_bandwidth::MHz40; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz50): - bw = bs_channel_bandwidth_fr1::MHz50; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz50): + bw = bs_channel_bandwidth::MHz50; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz60): - bw = bs_channel_bandwidth_fr1::MHz60; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz60): + bw = bs_channel_bandwidth::MHz60; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz70): - bw = bs_channel_bandwidth_fr1::MHz70; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz70): + bw = bs_channel_bandwidth::MHz70; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz80): - bw = bs_channel_bandwidth_fr1::MHz80; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz80): + bw = bs_channel_bandwidth::MHz80; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz90): - bw = bs_channel_bandwidth_fr1::MHz90; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz90): + bw = bs_channel_bandwidth::MHz90; break; - case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth_fr1::MHz100): - bw = bs_channel_bandwidth_fr1::MHz100; + case bs_channel_bandwidth_to_MHz(bs_channel_bandwidth::MHz100): + bw = bs_channel_bandwidth::MHz100; break; default: return false; diff --git a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp index 07b92aa621..db4fc63dda 100644 --- a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp @@ -244,7 +244,7 @@ void benchmark_tdd(benchmarker& bm, const bench_params& params) cell_config_builder_params builder_params{}; builder_params.dl_arfcn = 520002; builder_params.band = nr_band::n41; - builder_params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz100; + builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz100; builder_params.scs_common = subcarrier_spacing::kHz30; builder_params.tdd_ul_dl_cfg_common = tdd_ul_dl_config_common{builder_params.scs_common, {10, 7, 8, 2, 0}}; builder_params.nof_dl_ports = 4; diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index a6b7620a77..4a8daf6eb7 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -71,27 +71,27 @@ namespace { /// User-defined test parameters. struct test_parameters { - bool silent = false; - srslog::basic_levels log_level = srslog::basic_levels::info; - std::string log_filename = "stdout"; - bool is_prach_control_plane_enabled = true; - bool is_downlink_broadcast_enabled = false; - bool ignore_ecpri_payload_size_field = false; - std::string data_compr_method = "bfp"; - unsigned data_bitwidth = 9; - std::string prach_compr_method = "bfp"; - unsigned prach_bitwidth = 9; - bool is_downlink_static_comp_hdr_enabled = false; - bool is_uplink_static_comp_hdr_enabled = false; - bool is_downlink_parallelized = true; - units::bytes mtu = units::bytes(9000); - std::vector prach_port_id = {4, 5}; - std::vector dl_port_id = {0, 1, 2, 3}; - std::vector ul_port_id = {0, 1}; - bs_channel_bandwidth_fr1 bw = srsran::bs_channel_bandwidth_fr1::MHz20; - subcarrier_spacing scs = subcarrier_spacing::kHz30; - std::string tdd_pattern_str = "7d2u"; - bool use_loopback_receiver = false; + bool silent = false; + srslog::basic_levels log_level = srslog::basic_levels::info; + std::string log_filename = "stdout"; + bool is_prach_control_plane_enabled = true; + bool is_downlink_broadcast_enabled = false; + bool ignore_ecpri_payload_size_field = false; + std::string data_compr_method = "bfp"; + unsigned data_bitwidth = 9; + std::string prach_compr_method = "bfp"; + unsigned prach_bitwidth = 9; + bool is_downlink_static_comp_hdr_enabled = false; + bool is_uplink_static_comp_hdr_enabled = false; + bool is_downlink_parallelized = true; + units::bytes mtu = units::bytes(9000); + std::vector prach_port_id = {4, 5}; + std::vector dl_port_id = {0, 1, 2, 3}; + std::vector ul_port_id = {0, 1}; + bs_channel_bandwidth bw = srsran::bs_channel_bandwidth::MHz20; + subcarrier_spacing scs = subcarrier_spacing::kHz30; + std::string tdd_pattern_str = "7d2u"; + bool use_loopback_receiver = false; }; /// Dummy Radio Unit error notifier. diff --git a/tests/integrationtests/ofh/ru_emulator_appconfig.h b/tests/integrationtests/ofh/ru_emulator_appconfig.h index 621ff2c616..65ff6a2432 100644 --- a/tests/integrationtests/ofh/ru_emulator_appconfig.h +++ b/tests/integrationtests/ofh/ru_emulator_appconfig.h @@ -30,7 +30,7 @@ struct ru_emulator_ofh_appconfig { /// RU Uplink ports. std::vector ru_ul_port_id = {0, 1}; /// RU emulator operating bandwidth. - bs_channel_bandwidth_fr1 bandwidth = srsran::bs_channel_bandwidth_fr1::MHz100; + bs_channel_bandwidth bandwidth = srsran::bs_channel_bandwidth::MHz100; /// Uplink compression method. std::string ul_compr_method = "bfp"; /// Uplink compression bitwidth. diff --git a/tests/unittests/ran/band_helper_test.cpp b/tests/unittests/ran/band_helper_test.cpp index c6a576e6f7..c9f2512359 100644 --- a/tests/unittests/ran/band_helper_test.cpp +++ b/tests/unittests/ran/band_helper_test.cpp @@ -438,146 +438,157 @@ TEST(test_get_f_req_from_f_req_point_a, scs_kHz60) TEST(test_get_n_rbs_from_bw, scs_15kHz) { ASSERT_EQ( - 25, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth_fr1::MHz5, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz10, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz15, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz20, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz25, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz30, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz35, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz40, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz45, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz50, subcarrier_spacing::kHz15, frequency_range::FR1)); + 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_fr1::MHz60, subcarrier_spacing::kHz15, frequency_range::FR1)); + 0, band_helper::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_fr1::MHz5, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz10, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz15, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz20, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz25, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz30, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz35, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz40, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz45, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz50, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz60, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz70, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz80, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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_fr1::MHz90, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ(273, - band_helper::get_n_rbs_from_bw( - bs_channel_bandwidth_fr1::MHz100, subcarrier_spacing::kHz30, frequency_range::FR1)); + 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)); } TEST(test_get_n_rbs_from_bw, scs_60kHz) { ASSERT_EQ( - 0, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth_fr1::MHz5, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz10, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz15, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz20, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz25, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz30, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz35, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz40, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz45, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz50, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz60, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz70, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz80, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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_fr1::MHz90, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ(135, - band_helper::get_n_rbs_from_bw( - bs_channel_bandwidth_fr1::MHz100, subcarrier_spacing::kHz60, frequency_range::FR1)); + 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)); +} + +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)); +} + +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)); } TEST(test_get_n_rbs_from_bw, invalid_cases) { - ASSERT_EQ(0, - band_helper::get_n_rbs_from_bw( - bs_channel_bandwidth_fr1::MHz100, subcarrier_spacing::kHz60, frequency_range::FR2)); - ASSERT_EQ(0, - band_helper::get_n_rbs_from_bw( - bs_channel_bandwidth_fr1::MHz100, subcarrier_spacing::kHz120, frequency_range::FR1)); + 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)); } TEST(test_get_min_channel_bw, invalid_cases) @@ -618,6 +629,19 @@ TEST(test_get_min_channel_bw, invalid_cases) 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)); } TEST(test_is_valid_ssb_arfcn, mixed_bands) diff --git a/tests/unittests/ran/ssb_gscn_test.cpp b/tests/unittests/ran/ssb_gscn_test.cpp index c6c68b4c09..268cbf9be4 100644 --- a/tests/unittests/ran/ssb_gscn_test.cpp +++ b/tests/unittests/ran/ssb_gscn_test.cpp @@ -114,30 +114,30 @@ TEST(test_is_gscn_valid_given_band, mixed_bands) ASSERT_FALSE(band_helper::is_gscn_valid_given_band(9447U, nr_band::n48, subcarrier_spacing::kHz15).has_value()); ASSERT_TRUE(band_helper::is_gscn_valid_given_band(7911U, nr_band::n78, subcarrier_spacing::kHz30).has_value()); ASSERT_FALSE(band_helper::is_gscn_valid_given_band(7700U, nr_band::n78, subcarrier_spacing::kHz30).has_value()); - ASSERT_TRUE(band_helper::is_gscn_valid_given_band( - 8720U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth_fr1::MHz40) - .has_value()); - ASSERT_FALSE(band_helper::is_gscn_valid_given_band( - 8716U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth_fr1::MHz40) - .has_value()); - ASSERT_TRUE(band_helper::is_gscn_valid_given_band( - 8716U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth_fr1::MHz10) - .has_value()); - ASSERT_FALSE(band_helper::is_gscn_valid_given_band( - 8885U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth_fr1::MHz10) - .has_value()); - ASSERT_TRUE(band_helper::is_gscn_valid_given_band( - 6717U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth_fr1::MHz10) - .has_value()); - ASSERT_FALSE(band_helper::is_gscn_valid_given_band( - 6718U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth_fr1::MHz10) - .has_value()); - ASSERT_TRUE(band_helper::is_gscn_valid_given_band( - 6718U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth_fr1::MHz5) - .has_value()); - ASSERT_FALSE(band_helper::is_gscn_valid_given_band( - 6244U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth_fr1::MHz5) - .has_value()); + ASSERT_TRUE( + band_helper::is_gscn_valid_given_band(8720U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_FALSE( + band_helper::is_gscn_valid_given_band(8716U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_TRUE( + band_helper::is_gscn_valid_given_band(8716U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth::MHz10) + .has_value()); + ASSERT_FALSE( + band_helper::is_gscn_valid_given_band(8885U, nr_band::n79, subcarrier_spacing::kHz30, bs_channel_bandwidth::MHz10) + .has_value()); + ASSERT_TRUE( + band_helper::is_gscn_valid_given_band(6717U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth::MHz10) + .has_value()); + ASSERT_FALSE( + band_helper::is_gscn_valid_given_band(6718U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth::MHz10) + .has_value()); + ASSERT_TRUE( + band_helper::is_gscn_valid_given_band(6718U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth::MHz5) + .has_value()); + ASSERT_FALSE( + band_helper::is_gscn_valid_given_band(6244U, nr_band::n90, subcarrier_spacing::kHz15, bs_channel_bandwidth::MHz5) + .has_value()); ASSERT_TRUE(band_helper::is_gscn_valid_given_band(6554U, nr_band::n90, subcarrier_spacing::kHz30).has_value()); ASSERT_FALSE(band_helper::is_gscn_valid_given_band(6250U, nr_band::n90, subcarrier_spacing::kHz30).has_value()); ASSERT_TRUE(band_helper::is_gscn_valid_given_band(10062U, nr_band::n96, subcarrier_spacing::kHz30).has_value()); diff --git a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp index 0dd642c216..dc6d864dca 100644 --- a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp @@ -134,9 +134,9 @@ class base_paging_sched_tester } sched_cell_configuration_request_message - create_custom_cell_config_request(duplex_mode duplx_mode, - subcarrier_spacing scs = srsran::subcarrier_spacing::kHz30, - bs_channel_bandwidth_fr1 carrier_bw = srsran::bs_channel_bandwidth_fr1::MHz20) const + create_custom_cell_config_request(duplex_mode duplx_mode, + subcarrier_spacing scs = srsran::subcarrier_spacing::kHz30, + bs_channel_bandwidth carrier_bw = srsran::bs_channel_bandwidth::MHz20) const { cell_config_builder_params cell_cfg{}; if (duplx_mode == duplex_mode::TDD) { @@ -312,7 +312,7 @@ TEST_F(paging_sched_special_case_tester, successfully_allocated_paging_grant_5mh const uint16_t drx_cycle_in_nof_rf = 128; auto sched_cell_cfg = create_custom_cell_config_request( - srsran::duplex_mode::FDD, subcarrier_spacing::kHz15, bs_channel_bandwidth_fr1::MHz5); + srsran::duplex_mode::FDD, subcarrier_spacing::kHz15, bs_channel_bandwidth::MHz5); // Shuffle between SearchSpace#0 and SearchSpace#1. const auto ss_id = to_search_space_id(get_random_uint(0, 1)); diff --git a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp index a4f5a48301..aa9db5c3a9 100644 --- a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp @@ -38,9 +38,8 @@ void PrintTo(const prach_test_params& value, ::std::ostream* os) static sched_cell_configuration_request_message make_custom_sched_cell_configuration_request(const prach_test_params test_params) { - cell_config_builder_params params = {.scs_common = test_params.scs, - .channel_bw_mhz = srsran::bs_channel_bandwidth_fr1::MHz20, - .band = test_params.band}; + cell_config_builder_params params = { + .scs_common = test_params.scs, .channel_bw_mhz = srsran::bs_channel_bandwidth::MHz20, .band = test_params.band}; // For TDD, set DL ARFCN according to the band. if (not band_helper::is_paired_spectrum(test_params.band)) { params.dl_arfcn = 520002; diff --git a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp index b5783a9b2b..2b84534245 100644 --- a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp @@ -103,7 +103,7 @@ class base_ra_scheduler_test builder_params.band = nr_band::n41; } if (t_params.scs == srsran::subcarrier_spacing::kHz30) { - builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth_fr1::MHz20; + builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth::MHz20; } sched_cell_configuration_request_message req = diff --git a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp index 336b8ecca1..c942fb2496 100644 --- a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp @@ -178,7 +178,7 @@ struct sib_test_bench { cell_cfg.band = init_bwp_scs == subcarrier_spacing::kHz15 ? nr_band::n50 : nr_band::n40; } cell_cfg.scs_common = init_bwp_scs; - cell_cfg.channel_bw_mhz = static_cast(carrier_bw_mhz); + cell_cfg.channel_bw_mhz = static_cast(carrier_bw_mhz); cell_cfg.coreset0_index = (pdcch_config_sib1 >> 4U) & 0b00001111U; cell_cfg.search_space0_index = pdcch_config_sib1 & 0b00001111U; @@ -211,7 +211,7 @@ struct sib_test_bench { cell_cfg.dl_arfcn = freq_arfcn; cell_cfg.scs_common = init_bwp_scs; cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); - cell_cfg.channel_bw_mhz = static_cast(carrier_bw_mhz); + cell_cfg.channel_bw_mhz = static_cast(carrier_bw_mhz); const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( cell_cfg.channel_bw_mhz, @@ -467,7 +467,7 @@ void test_sib_1_pdsch_collisions(unsigned freq_arfcn, subcarrier_spacing scs, ui srsran_assert(carrier_bw_mhz >= min_channel_bandwidth_to_MHz(min_ch_bw), "Invalid carrier BW"); const auto nof_rbs_bpw = - band_helper::get_n_rbs_from_bw(static_cast(carrier_bw_mhz), + band_helper::get_n_rbs_from_bw(static_cast(carrier_bw_mhz), scs, band_helper::get_freq_range(band_helper::get_band_from_dl_arfcn(freq_arfcn))); diff --git a/tests/unittests/scheduler/multi_cell_scheduler_test.cpp b/tests/unittests/scheduler/multi_cell_scheduler_test.cpp index 13c3ed2a8d..e0e8799d5e 100644 --- a/tests/unittests/scheduler/multi_cell_scheduler_test.cpp +++ b/tests/unittests/scheduler/multi_cell_scheduler_test.cpp @@ -33,7 +33,7 @@ class base_multi_cell_scheduler_tester : public scheduler_test_bench test_params.dplx_mode == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; params.dl_arfcn = test_params.dplx_mode == duplex_mode::FDD ? 530000 : 520002; params.band = band_helper::get_band_from_dl_arfcn(params.dl_arfcn); - params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + params.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index 0e135a1e2f..3f24623078 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -193,7 +193,7 @@ class scheduler_impl_tester cell_cfg.dl_arfcn = 474000; cell_cfg.scs_common = srsran::subcarrier_spacing::kHz30; cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); - cell_cfg.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + cell_cfg.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( cell_cfg.channel_bw_mhz, @@ -740,9 +740,9 @@ TEST_P(multiple_ue_sched_tester, when_scheduling_multiple_ue_in_small_bw_neither // Make custom cell configuration for TDD and FDD i.e. 10 Mhz for TDD and 5Mhz for FDD. auto builder_params = create_custom_cell_cfg_builder_params(params.duplx_mode); - builder_params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz5; + builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz5; if (params.duplx_mode == duplex_mode::TDD) { - builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth_fr1::MHz10; + builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth::MHz10; } builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); diff --git a/tests/unittests/scheduler/pdcch/pdcch_resource_allocator_test.cpp b/tests/unittests/scheduler/pdcch/pdcch_resource_allocator_test.cpp index 9f740fb4bb..645c853a13 100644 --- a/tests/unittests/scheduler/pdcch/pdcch_resource_allocator_test.cpp +++ b/tests/unittests/scheduler/pdcch/pdcch_resource_allocator_test.cpp @@ -37,7 +37,7 @@ const char* to_string(alloc_type a) return "invalid"; } -using cell_bw = bs_channel_bandwidth_fr1; +using cell_bw = bs_channel_bandwidth; namespace pdcch_test { @@ -485,7 +485,7 @@ struct multi_alloc_test_params { std::optional expected_ncce; }; - bs_channel_bandwidth_fr1 cell_bw; + bs_channel_bandwidth cell_bw; std::optional> ss2_nof_candidates; std::vector allocs; }; diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index 4e649dccd4..4794a3fb55 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -419,7 +419,7 @@ class scheduler_policy_partial_slot_tdd_test : public base_scheduler_policy_test builder_params.dl_arfcn = 465000; builder_params.scs_common = subcarrier_spacing::kHz30; builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); - builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth_fr1::MHz20; + builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( builder_params.channel_bw_mhz, diff --git a/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp b/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp index 169d9cb8bc..acc820cda4 100644 --- a/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp +++ b/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp @@ -29,12 +29,12 @@ class scheduler_ta_cmd_tester : public scheduler_test_bench, public ::testing::T params.scs_common = subcarrier_spacing::kHz30; params.dl_arfcn = 520002; params.band = nr_band::n41; - params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + params.channel_bw_mhz = bs_channel_bandwidth::MHz20; } else { params.scs_common = subcarrier_spacing::kHz15; params.dl_arfcn = 365000; params.band = nr_band::n3; - params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + params.channel_bw_mhz = bs_channel_bandwidth::MHz20; } const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); diff --git a/tests/unittests/scheduler/scheduler_tdd_test.cpp b/tests/unittests/scheduler/scheduler_tdd_test.cpp index 597e7d83ed..c51e8e0d7c 100644 --- a/tests/unittests/scheduler/scheduler_tdd_test.cpp +++ b/tests/unittests/scheduler/scheduler_tdd_test.cpp @@ -39,7 +39,7 @@ class base_scheduler_tdd_tester : public scheduler_test_bench params.scs_common = testparams.tdd_cfg.ref_scs; params.dl_arfcn = 520002; params.band = nr_band::n41; - params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + params.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; diff --git a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp index 601e56dcec..dc08ea6494 100644 --- a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp +++ b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp @@ -29,7 +29,7 @@ class base_scheduler_conres_test : public scheduler_test_bench builder_params.dl_arfcn = 520002; builder_params.scs_common = subcarrier_spacing::kHz30; builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); - builder_params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz10; + builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz10; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( builder_params.channel_bw_mhz, builder_params.scs_common, band_helper::get_freq_range(*builder_params.band)); static const uint8_t ss0_idx = 0; diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 88d3a9cfeb..35c307c1f5 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -24,7 +24,7 @@ class slice_scheduler_test []() { cell_config_builder_params params{}; params.scs_common = subcarrier_spacing::kHz30; - params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz100; + params.channel_bw_mhz = bs_channel_bandwidth::MHz100; params.dl_arfcn = 520000; params.band = nr_band::n41; return params; diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h index 104fe682a4..17cbea0307 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h @@ -29,7 +29,7 @@ inline sched_cell_configuration_request_message make_default_sched_cell_configuration_request_scs(subcarrier_spacing scs, bool tdd_mode = false) { cell_config_builder_params params{ - .scs_common = scs, .channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20, .nof_dl_ports = 1}; + .scs_common = scs, .channel_bw_mhz = bs_channel_bandwidth::MHz20, .nof_dl_ports = 1}; if (scs == subcarrier_spacing::kHz15) { // Band n5 for FDD, band n41 for TDD. params.dl_arfcn = tdd_mode ? 499200 : 530000; @@ -79,7 +79,7 @@ inline sched_cell_configuration_request_message make_custom_sched_cell_configura { 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_fr1::MHz10, + .channel_bw_mhz = bs_channel_bandwidth::MHz10, .dl_arfcn = is_tdd ? 520000U : 365000U}); req.ul_cfg_common.init_ul_bwp.pucch_cfg_common->pucch_resource_common = pucch_res_common; return req; diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index ee019ad695..49aad00ab0 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -42,7 +42,7 @@ static cell_config_builder_params test_builder_params(duplex_mode duplx_mode) builder_params.dl_arfcn = 474000; builder_params.scs_common = srsran::subcarrier_spacing::kHz30; builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); - builder_params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( builder_params.channel_bw_mhz, diff --git a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp index 5a7ec43ad4..d9865b3e2b 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp @@ -115,7 +115,7 @@ TEST_F(ue_configuration_test, search_spaces_pdcch_candidate_lists_does_not_surpa params.scs_common = subcarrier_spacing::kHz30; params.dl_arfcn = 520002; params.band = nr_band::n41; - params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz50; + params.channel_bw_mhz = bs_channel_bandwidth::MHz50; msg = test_helpers::make_default_sched_cell_configuration_request(params); ue_create_msg = test_helpers::create_default_sched_ue_creation_request(params); diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index ad6dc3cb65..143b951468 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -36,7 +36,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam cfg_builder_params.scs_common = GetParam() == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; cfg_builder_params.band = band_helper::get_band_from_dl_arfcn(cfg_builder_params.dl_arfcn); - cfg_builder_params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz20; + cfg_builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz20; auto* cfg = cfg_mng.add_cell(test_helpers::make_default_sched_cell_configuration_request(cfg_builder_params), metrics_ue_handler); srsran_assert(cfg != nullptr, "Cell configuration failed"); From ba5b4510a022084c18f70e6aeb2b364bd3184dd8 Mon Sep 17 00:00:00 2001 From: ninjab3s Date: Mon, 19 Aug 2024 11:06:06 +0200 Subject: [PATCH 282/407] ci: Update values for ZMQ tests on skinny-beast --- .gitlab/ci/e2e/retina_request_zmq_uesim.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab/ci/e2e/retina_request_zmq_uesim.yml b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml index 85edb577cb..134cbfba8a 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_uesim.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml @@ -15,8 +15,8 @@ requirements: arch: amd64 cpu: - requests: 2 - limits: 2 + requests: 4 + limits: 4 memory: requests: "4G" limits: "4G" @@ -41,8 +41,8 @@ requirements: arch: amd64 cpu: - requests: 16 - limits: 16 + requests: 20 + limits: 20 memory: requests: "48G" limits: "48G" @@ -63,8 +63,8 @@ requirements: arch: amd64 cpu: - requests: 1 - limits: 1 + requests: 4 + limits: 4 memory: requests: "8G" limits: "8G" From 375fa73f308b31c2900d5e68425c54cd763efc5b Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 14 Aug 2024 18:32:15 +0200 Subject: [PATCH 283/407] du: refactor ARFCN related variable and comments Signed-off-by: Carlo Galiotto --- .../flexible_du/du_high/du_high_config.h | 4 +- .../du_high/du_high_config_cli11_schema.cpp | 4 +- .../du_high/du_high_config_translators.cpp | 8 ++-- .../du_high/du_high_config_validator.cpp | 25 +++++----- .../du_high/du_high_config_yaml_writer.cpp | 2 +- .../du_high/du_high_wrapper_config_helper.cpp | 6 +-- .../split_8/ru_sdr_config_translator.cpp | 8 ++-- .../dynamic_du_unit_cli11_schema.cpp | 2 +- include/srsran/ran/band_helper.h | 44 ++++++++++------- include/srsran/ran/carrier_configuration.h | 5 +- .../scheduler/config/bwp_configuration.h | 3 +- .../config/cell_config_builder_params.h | 5 +- .../config/serving_cell_config_factory.h | 4 +- lib/du/du_cell_config_validation.cpp | 10 ++-- lib/du_low/du_low_wrapper_factory.cpp | 2 +- .../converters/asn1_rrc_config_helpers.cpp | 6 +-- .../du/procedures/f1ap_du_setup_procedure.cpp | 6 +-- lib/mac/mac_dl/mac_cell_processor.cpp | 8 ++-- lib/mac/mac_dl/ssb_assembler.cpp | 2 +- lib/ran/band_helper.cpp | 34 +++++++------- .../rrc_reestablishment_procedure.cpp | 2 +- .../common_scheduling/ssb_scheduler.cpp | 6 +-- lib/scheduler/config/cell_configuration.cpp | 2 +- .../config/serving_cell_config_factory.cpp | 47 +++++++++---------- .../benchmarks/du_high/du_high_benchmark.cpp | 6 +-- .../scheduler_multi_ue_benchmark.cpp | 2 +- .../du_ran_resource_manager_test.cpp | 11 ++--- .../paging_scheduler_test.cpp | 4 +- .../prach_scheduler_test.cpp | 2 +- .../common_scheduling/ra_scheduler_test.cpp | 2 +- .../common_scheduling/sib1_scheduler_test.cpp | 12 ++--- .../common_scheduling/ssb_scheduler_test.cpp | 6 +-- .../scheduler/multi_cell_scheduler_test.cpp | 6 +-- .../scheduler/multiple_ue_sched_test.cpp | 10 ++-- .../policy/scheduler_policy_test.cpp | 6 +-- .../scheduler/scheduler_ta_cmd_test.cpp | 6 +-- .../scheduler/scheduler_tdd_test.cpp | 4 +- .../scheduler_ue_fallback_mode_test.cpp | 6 +-- .../slicing/slice_scheduler_test.cpp | 2 +- .../scheduler/test_utils/config_generators.h | 3 +- .../uci_and_pucch/uci_test_utils.cpp | 2 +- .../scheduler/uci_and_pucch/uci_test_utils.h | 10 ++-- .../ue_scheduling/fallback_scheduler_test.cpp | 8 ++-- .../ue_scheduling/ue_configuration_test.cpp | 2 +- .../ue_scheduling/ue_grid_allocator_test.cpp | 4 +- 45 files changed, 186 insertions(+), 173 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 83ede6b479..849d02adbd 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -514,8 +514,8 @@ struct du_high_unit_base_cell_config { pci_t pci = 1; /// Sector Id (4-14 bits) that gets concatenated with gNB-Id to form the NR Cell Identity (NCI). std::optional sector_id; - /// Downlink arfcn. - unsigned dl_arfcn = 536020; + /// 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; /// 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 cc8bb5e366..4726ad6feb 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 @@ -1081,7 +1081,7 @@ static void configure_cli11_common_cell_args(CLI::App& app, du_high_unit_base_ce "(NCI). If not specified, a unique value for the DU is automatically derived") ->capture_default_str() ->check(CLI::Range(0U, (1U << 14) - 1U)); - add_option(app, "--dl_arfcn", cell_params.dl_arfcn, "Downlink ARFCN")->capture_default_str(); + add_option(app, "--dl_arfcn", cell_params.dl_f_ref_arfcn, "Downlink ARFCN")->capture_default_str(); add_auto_enum_option(app, "--band", cell_params.band, "NR band"); add_option_function( app, @@ -1706,7 +1706,7 @@ static void derive_cell_auto_params(du_high_unit_base_cell_config& cell_cfg) { // If NR band is not set, derive a valid one from the DL-ARFCN. if (not cell_cfg.band.has_value()) { - cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); + cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_f_ref_arfcn); } // If in TDD mode, and pattern was not set, generate a pattern DDDDDDXUUU. 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 46b2b7455d..4203bf884f 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 @@ -220,7 +220,7 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c param.pci = base_cell.pci; param.scs_common = base_cell.common_scs; param.channel_bw_mhz = base_cell.channel_bw_mhz; - param.dl_arfcn = base_cell.dl_arfcn; + param.dl_f_ref_arfcn = base_cell.dl_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; @@ -242,7 +242,7 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c std::optional ssb_freq_loc; if (base_cell.pdcch_cfg.common.coreset0_index.has_value()) { ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location_for_cset0_idx(base_cell.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location_for_cset0_idx(base_cell.dl_f_ref_arfcn, *param.band, nof_crbs, base_cell.common_scs, @@ -250,7 +250,7 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c param.search_space0_index, base_cell.pdcch_cfg.common.coreset0_index.value()); } else { - ssb_freq_loc = band_helper::get_ssb_coreset0_freq_location(base_cell.dl_arfcn, + ssb_freq_loc = band_helper::get_ssb_coreset0_freq_location(base_cell.dl_f_ref_arfcn, *param.band, nof_crbs, base_cell.common_scs, @@ -618,7 +618,7 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c "pointA:{} \n\t - k_SSB:{} \n\t - SSB arfcn:{} \n\t - Coreset index:{} \n\t - Searchspace index:{}", base_cell.pci, *param.band, - base_cell.dl_arfcn, + base_cell.dl_f_ref_arfcn, nof_crbs, to_string(base_cell.common_scs), to_string(out_cfg.back().ssb_cfg.scs), 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 ccef53ed15..7b2ba7a2fa 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 @@ -198,14 +198,14 @@ static bool validate_srb_unit_config(const std::map ret = band_helper::is_dl_arfcn_valid_given_band( - *config.band, config.dl_arfcn, config.common_scs, config.channel_bw_mhz); + *config.band, config.dl_f_ref_arfcn, config.common_scs, config.channel_bw_mhz); if (not ret.has_value()) { - fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_arfcn, band, ret.error()); + 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) { - fmt::print("Invalid DL ARFCN={}. Cause: Could not find a valid band.\n", config.dl_arfcn); + fmt::print("Invalid DL ARFCN={}. Cause: Could not find a valid band.\n", config.dl_f_ref_arfcn); return false; } } @@ -757,8 +758,8 @@ 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_arfcn), config.common_scs); + 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); 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), @@ -766,7 +767,7 @@ 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_arfcn); + 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)); @@ -838,11 +839,11 @@ static bool validate_cells_unit_config(span conf const auto& cell2 = *it2; // Check if both cells are on the same frequency. - if (cell1.cell.dl_arfcn == cell2.cell.dl_arfcn) { + if (cell1.cell.dl_f_ref_arfcn == cell2.cell.dl_f_ref_arfcn) { // Two cells on the same frequency should not have the same physical cell identifier. if (cell1.cell.pci == cell2.cell.pci) { fmt::print("Warning: two cells with the same DL ARFCN (i.e., {}) have the same PCI (i.e., {}).\n", - cell1.cell.dl_arfcn, + cell1.cell.dl_f_ref_arfcn, cell1.cell.pci); } if (cell1.cell.sector_id.has_value() and cell1.cell.sector_id == cell2.cell.sector_id and @@ -860,7 +861,7 @@ static bool validate_cells_unit_config(span conf "sequence index (i.e., {}).\n", cell1.cell.pci, cell2.cell.pci, - cell1.cell.dl_arfcn, + cell1.cell.dl_f_ref_arfcn, cell1.cell.prach_cfg.prach_root_sequence_index); } } diff --git a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp index 9fccac2cb3..7b71c8c328 100644 --- a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp @@ -559,7 +559,7 @@ static YAML::Node build_cell_entry(const du_high_unit_base_cell_config& config) YAML::Node node; node["pci"] = config.pci; - node["dl_arfcn"] = config.dl_arfcn; + node["dl_arfcn"] = config.dl_f_ref_arfcn; node["common_scs"] = scs_to_khz(config.common_scs); node["channel_bandwidth_MHz"] = bs_channel_bandwidth_to_MHz(config.channel_bw_mhz); node["nof_antennas_ul"] = config.nof_antennas_ul; diff --git a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp index 6a36ac0bc0..5427f26e22 100644 --- a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp +++ b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp @@ -33,11 +33,11 @@ void srsran::announce_du_high_cells(const du_high_unit_config& du_high_unit_cfg) cell.dl_carrier.carrier_bw_mhz, cell.dl_carrier.nof_ant, cell.ul_carrier.nof_ant, - cell.dl_carrier.arfcn, + cell.dl_carrier.arfcn_f_ref, srsran::nr_band_to_uint(cell.dl_carrier.band), - srsran::band_helper::nr_arfcn_to_freq(cell.dl_carrier.arfcn) / 1e6, + srsran::band_helper::nr_arfcn_to_freq(cell.dl_carrier.arfcn_f_ref) / 1e6, cell.dl_cfg_common.freq_info_dl.absolute_frequency_ssb, - srsran::band_helper::nr_arfcn_to_freq(cell.ul_carrier.arfcn) / 1e6); + srsran::band_helper::nr_arfcn_to_freq(cell.ul_carrier.arfcn_f_ref) / 1e6); } fmt::print("\n"); diff --git a/apps/units/flexible_du/split_8/ru_sdr_config_translator.cpp b/apps/units/flexible_du/split_8/ru_sdr_config_translator.cpp index 96bd17639a..bf216fb792 100644 --- a/apps/units/flexible_du/split_8/ru_sdr_config_translator.cpp +++ b/apps/units/flexible_du/split_8/ru_sdr_config_translator.cpp @@ -95,8 +95,8 @@ static lower_phy_configuration generate_low_phy_config(const du_cell_config& lower_phy_sector_description sector_config; sector_config.bandwidth_rb = band_helper::get_n_rbs_from_bw( MHz_to_bs_channel_bandwidth(config.dl_carrier.carrier_bw_mhz), config.scs_common, frequency_range::FR1); - sector_config.dl_freq_hz = band_helper::nr_arfcn_to_freq(config.dl_carrier.arfcn); - sector_config.ul_freq_hz = band_helper::nr_arfcn_to_freq(config.ul_carrier.arfcn); + sector_config.dl_freq_hz = band_helper::nr_arfcn_to_freq(config.dl_carrier.arfcn_f_ref); + sector_config.ul_freq_hz = band_helper::nr_arfcn_to_freq(config.ul_carrier.arfcn_f_ref); sector_config.nof_rx_ports = config.ul_carrier.nof_ant; sector_config.nof_tx_ports = config.dl_carrier.nof_ant; out_cfg.sectors.push_back(sector_config); @@ -178,8 +178,8 @@ static void generate_radio_config(radio_configuration::radio& out_cfg, radio_configuration::stream rx_stream_config; // Deduce center frequencies. - const double cell_tx_freq_Hz = band_helper::nr_arfcn_to_freq(cell.dl_carrier.arfcn); - const double cell_rx_freq_Hz = band_helper::nr_arfcn_to_freq(cell.ul_carrier.arfcn); + const double cell_tx_freq_Hz = band_helper::nr_arfcn_to_freq(cell.dl_carrier.arfcn_f_ref); + const double cell_rx_freq_Hz = band_helper::nr_arfcn_to_freq(cell.ul_carrier.arfcn_f_ref); // Correct actual RF center frequencies considering offset and PPM calibration. double center_tx_freq_cal_Hz = 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 3820f2f870..839eed479d 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 @@ -149,7 +149,7 @@ 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_arfcn); + 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/band_helper.h b/include/srsran/ran/band_helper.h index c057582227..6a84338b72 100644 --- a/include/srsran/ran/band_helper.h +++ b/include/srsran/ran/band_helper.h @@ -61,9 +61,9 @@ duplex_mode get_duplex_mode(nr_band band); /// \brief Gets the lowest band that includes a given Downlink ARFCN. /// \remark Some bands can be subset of others, e.g., band 2 is a subset of band 25. -/// \param[in] arfcn Given Downlink ARFCN. +/// \param[in] arfcn_f_ref Given Downlink ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. /// \return The band number if the ARFCN is bounded in a band, UINT16_MAX otherwise. -nr_band get_band_from_dl_arfcn(uint32_t arfcn); +nr_band get_band_from_dl_arfcn(uint32_t arfcn_f_ref); /// \brief Returns true if the band is used for shared spectrum channel access. /// \remark As per TS 38.104, Table 5.2-1, only bands where Note 3 or Note 4 apply. @@ -75,13 +75,13 @@ bool is_band_40mhz_min_ch_bw_equivalent(nr_band band); /// \brief Checks whether a Downlink ARFCN is valid for a given band. /// \param[in] band Given NR band. -/// \param[in] arfcn Given Downlink ARFCN. +/// \param[in] arfcn_f_ref Given Downlink ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. /// \param[in] scs is the subcarrier spacing of reference for \f$N_{RB}\f$, as per TS 38.104, Table 5.3.2-1. Only used /// for bands n41, n77, n78, n79. /// \param[in] bw Channel Bandwidth in MHz, which is required to validate some bands' ARFCN values. /// \return If the DL ARFCN is invalid for the band, a std::string value is returned with the reason. error_type is_dl_arfcn_valid_given_band(nr_band band, - uint32_t arfcn, + uint32_t arfcn_f_ref, subcarrier_spacing scs, bs_channel_bandwidth bw = bs_channel_bandwidth::MHz10); @@ -90,17 +90,23 @@ error_type is_dl_arfcn_valid_given_band(nr_band band, /// For paired spectrum (FDD) the function returns the respective ARFCN in the same band. /// For unparied spectrum (TDD) the function returns the same ARFCN. /// -/// \param[in] dl_arfcn The DL ARFCN. -/// \param[in] band NR Band. If not given, the band is derived from the dl_arfcn. -/// \return uint32_t the UL ARFCN. +/// \param[in] dl_arfcn The DL ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. +/// \param[in] band NR Band. If not given, the band is derived from the dl_f_ref_arfcn. +/// \return uint32_t the UL ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. uint32_t get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn, std::optional band); -/// \brief Return frequency of given NR-ARFCN in Hz as per TS38.104 5.4.2.1. +/// \brief Return frequency of given NR-ARFCN in Hz as per TS 38.104 5.4.2.1. +/// +/// Even though the NR-ARFCN-to-frequency mapping is defined for "F_REF" as per TS 38.104 5.4.2.1, this mapping can be +/// used also SSB frequency and Absolute Point A. /// \param[in] nr_arfcn Given NR-ARFCN. /// \return The frequency in Hz. double nr_arfcn_to_freq(uint32_t nr_arfcn); /// \brief Calculates NR-ARFCN of a given frequency as per TS38.104 5.4.2.1. +/// +/// Even though the frequency-to-NR-ARFCN mapping is defined for "F_REF" as per TS 38.104 5.4.2.1, this mapping can be +/// used also SSB frequency and Absolute Point A. /// \param[in] freq Given Frequency in Hz. /// \return The NR-AFCN. uint32_t freq_to_nr_arfcn(double freq); @@ -115,6 +121,9 @@ ssb_pattern_case get_ssb_pattern(nr_band band, subcarrier_spacing scs); /// \brief Returns the L_max length of the \c ssb-PositionsInBurst, as per TS 38.213, Section 4.1 and TS 38.331, /// \c ServingCellConfigCommon. +/// \param[in] band NR Band number. +/// \param[in] scs SSB Subcarrier spacing. +/// \param[in] nr_arfcn The DL ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. uint8_t get_ssb_l_max(nr_band band, subcarrier_spacing scs, uint32_t nr_arfcn); /// \brief Selects the most suitable SSB subcarrier spacing valid for this band. @@ -148,23 +157,23 @@ frequency_range get_freq_range(nr_band band); /// @return Absolute Point A frequency in Hz. double get_abs_freq_point_a_from_center_freq(uint32_t nof_prb, double center_freq); -/// \brief Compute the absolute frequency point A for a arfcn +/// \brief Compute the absolute frequency point A (as ARFCN) given the \c F_REF (as ARFCN). /// /// \param[in] band nr frequency band. /// \param[in] nof_prb Number of PRBs. -/// \param[in] arfcn Given ARFCN. -/// \return frequency point A in arfcn notation. -uint32_t get_abs_freq_point_a_arfcn(uint32_t nof_prb, uint32_t arfcn); +/// \param[in] arfcn_f_ref Given ARFCN of \c F_REF, as defined in TS 38.104, Section 5.4.2.1. +/// \return Absolute frequency point A in ARFCN notation. +uint32_t get_abs_freq_point_a_arfcn(uint32_t nof_prb, uint32_t arfcn_f_ref); /// \brief Compute the center frequency for a NR carrier from its bandwidth and the absolute pointA. /// The center frequency should point to the RB with index = ceil(Nrb / 2), where Nrb is the number of RBs of the cell. /// -/// \param nof_prb Carrier bandwidth in number of RB. -/// \param freq_point_a_arfcn Absolute Point A frequency ARFCN. -/// \return double Frequency in Hz. +/// \param[in] nof_prb Carrier bandwidth in number of RB. +/// \param[in] freq_point_a_arfcn Absolute Frequency Point A as ARFCN. +/// \return Frequency in Hz. double get_center_freq_from_abs_freq_point_a(uint32_t nof_prb, uint32_t freq_point_a_arfcn); -/// \brief Compute the Absolute frequency pointA for a NR carrier from the nof RBs, SCS and the RF reference frequency. +/// \brief Compute the Absolute frequency pointA for an NR carrier from the nof RBs, SCS and the RF reference frequency. /// /// The RF reference frequency is defined in TS 38.104, Section 5.4.2.1. /// Point A<\em> is defined in TS 38.211, Section 4.4.4.2. @@ -319,7 +328,8 @@ std::optional get_ssb_arfcn(unsigned dl_arfcn, ssb_offset_to_pointA offset_to_point_A, ssb_subcarrier_offset k_ssb); -/// \brief Validate the SSB ARFCN for a given band. +/// \brief Validate the SSB ARFCN for a given band, i.e., ARFCN value of the \f$SS_{ref}\f$, where \f$SS_{ref}\f$ is +/// defined in Section 5.4.3.1, TS 38.104. /// /// \remark The validity of the GSCN raster is based on the GSCN value, as per Section 5.4.3.1, TS 38.104. The ARFCN is /// considered valid if the corresponding \f$SS_{ref}\f$ maps to a valid GSCN value. diff --git a/include/srsran/ran/carrier_configuration.h b/include/srsran/ran/carrier_configuration.h index 4c86c99c6d..ab7dc11cde 100644 --- a/include/srsran/ran/carrier_configuration.h +++ b/include/srsran/ran/carrier_configuration.h @@ -20,8 +20,9 @@ namespace srsran { struct carrier_configuration { /// Width of this carrier in MHz. Values: 5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 200, 400. uint16_t carrier_bw_mhz; - /// NR Absolute Radio Frequency Channel Number (NR-ARFCN) point A in kHz. Values: (450000..52600000). - uint32_t arfcn; + /// NR Absolute Radio Frequency Channel Number (NR-ARFCN) of "F_REF", which is the RF reference frequency, as per + /// TS 38.104, Section 5.4.2.1 ("F_REF" maps to the central frequency of the band). + uint32_t arfcn_f_ref; /// NR operating band<\em>, as per Table 5.2-1 and 5.2-2. TS 38.104. nr_band band; /// Number of antennas. Values: (0..65355). diff --git a/include/srsran/scheduler/config/bwp_configuration.h b/include/srsran/scheduler/config/bwp_configuration.h index e35b1231df..dd61988bb1 100644 --- a/include/srsran/scheduler/config/bwp_configuration.h +++ b/include/srsran/scheduler/config/bwp_configuration.h @@ -182,7 +182,8 @@ struct freq_band_indicator { /// \brief This class provides basic parameters of a downlink carrier and transmission. /// \remark See TS 38.331, "FrequencyInfoDL" and "FrequencyInfoDL-SIB". struct frequency_info_dl { - /// Absolute frequency (as ARFCN) of the SSB. + /// \brief Absolute frequency of the SSB as ARFCN. This is the ARFCN of the SS_ref (or SSB central frequency). + /// SS_ref is defined is per TS 38.104, Section 5.4.3.1 and 5.4.3.2. unsigned absolute_frequency_ssb; /// Absolute frequency (in ARFCN) of the reference resource block (common RB0). unsigned absolute_freq_point_a; diff --git a/include/srsran/scheduler/config/cell_config_builder_params.h b/include/srsran/scheduler/config/cell_config_builder_params.h index b1513be875..b4d4c30b16 100644 --- a/include/srsran/scheduler/config/cell_config_builder_params.h +++ b/include/srsran/scheduler/config/cell_config_builder_params.h @@ -28,8 +28,9 @@ struct cell_config_builder_params { subcarrier_spacing scs_common = subcarrier_spacing::kHz15; /// BS Channel Bandwidth, as per TS 38.104, Section 5.3.1. bs_channel_bandwidth channel_bw_mhz = bs_channel_bandwidth::MHz10; - /// This ARFCN represents "f_ref" for DL, as per TS 38.211, Section 5.4.2.1. - unsigned dl_arfcn = 365000; + /// 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; /// 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/include/srsran/scheduler/config/serving_cell_config_factory.h b/include/srsran/scheduler/config/serving_cell_config_factory.h index 7ee8d8d2bd..82a2bf53cf 100644 --- a/include/srsran/scheduler/config/serving_cell_config_factory.h +++ b/include/srsran/scheduler/config/serving_cell_config_factory.h @@ -24,7 +24,9 @@ namespace config_helpers { struct cell_config_builder_params_extended : public cell_config_builder_params { cell_config_builder_params_extended(const cell_config_builder_params& source = {}); - std::optional ssb_arfcn; /// Absolute frequency of the SSB. + /// \brief Absolute frequency of the SSB as ARFCN. This is the ARFCN of the \c SS_ref (or SSB central frequency). + /// \c SS_ref is defined is per TS 38.104, Section 5.4.3.1 and 5.4.3.2. + std::optional ssb_arfcn; unsigned cell_nof_crbs; subcarrier_spacing ssb_scs; }; diff --git a/lib/du/du_cell_config_validation.cpp b/lib/du/du_cell_config_validation.cpp index 5a59dd3cbb..32c0d856e1 100644 --- a/lib/du/du_cell_config_validation.cpp +++ b/lib/du/du_cell_config_validation.cpp @@ -436,13 +436,13 @@ static check_outcome check_ssb_configuration(const du_cell_config& cell_cfg) ssb_pattern_case ssb_case = band_helper::get_ssb_pattern(cell_cfg.dl_carrier.band, ssb_cfg.scs); uint8_t ssb_bitmap = static_cast(ssb_cfg.ssb_bitmap) << static_cast(56U); bool is_paired = band_helper::is_paired_spectrum(cell_cfg.dl_carrier.band); - uint8_t L_max = ssb_get_L_max(ssb_cfg.scs, cell_cfg.dl_carrier.arfcn, cell_cfg.dl_carrier.band); - double cutoff_freq_mhz_case_a_b_c = band_helper::nr_arfcn_to_freq(cell_cfg.dl_carrier.arfcn) / 1e6; - double cutoff_freq_mhz_case_c_unpaired = band_helper::nr_arfcn_to_freq(cell_cfg.dl_carrier.arfcn) / 1e6; + uint8_t L_max = ssb_get_L_max(ssb_cfg.scs, cell_cfg.dl_carrier.arfcn_f_ref, cell_cfg.dl_carrier.band); + double cutoff_freq_mhz_case_a_b_c = band_helper::nr_arfcn_to_freq(cell_cfg.dl_carrier.arfcn_f_ref) / 1e6; + double cutoff_freq_mhz_case_c_unpaired = band_helper::nr_arfcn_to_freq(cell_cfg.dl_carrier.arfcn_f_ref) / 1e6; // Check whether the SSB beam bitmap and L_max are compatible with SSB case and DL band. if (ssb_case == ssb_pattern_case::C and not is_paired) { - if (cell_cfg.dl_carrier.arfcn <= CUTOFF_FREQ_ARFCN_CASE_C_UNPAIRED) { + if (cell_cfg.dl_carrier.arfcn_f_ref <= CUTOFF_FREQ_ARFCN_CASE_C_UNPAIRED) { CHECK_EQ(L_max, 4, "For SSB case C and frequency <= {}MHz, L_max must be 4", cutoff_freq_mhz_case_c_unpaired); CHECK_TRUE((ssb_bitmap & 0b00001111) == 0, "For SSB case C and frequency <= {}MHz, only the 4 MSBs of SSB bitmap can be set", @@ -451,7 +451,7 @@ static check_outcome check_ssb_configuration(const du_cell_config& cell_cfg) CHECK_EQ(L_max, 8, "For SSB case C and frequency > {}MHz, L_max must be 8", cutoff_freq_mhz_case_c_unpaired); } } else { - if (cell_cfg.dl_carrier.arfcn <= CUTOFF_FREQ_ARFCN_CASE_A_B_C) { + if (cell_cfg.dl_carrier.arfcn_f_ref <= CUTOFF_FREQ_ARFCN_CASE_A_B_C) { CHECK_EQ(L_max, 4, "For SSB case A and B and frequency <= {}MHz, L_max must be 4", cutoff_freq_mhz_case_a_b_c); CHECK_TRUE((ssb_bitmap & 0b00001111) == 0, "For SSB case C and frequency <= {}MHz, only the 4 MSBs of SSB bitmap can be set", diff --git a/lib/du_low/du_low_wrapper_factory.cpp b/lib/du_low/du_low_wrapper_factory.cpp index aa09d61c29..03d7000708 100644 --- a/lib/du_low/du_low_wrapper_factory.cpp +++ b/lib/du_low/du_low_wrapper_factory.cpp @@ -55,7 +55,7 @@ static fapi::carrier_config generate_carrier_config_tlv(const du_cell_config& du 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))); + band_helper::get_freq_range(band_helper::get_band_from_dl_arfcn(du_cell.dl_carrier.arfcn_f_ref))); fapi::carrier_config fapi_config = {}; diff --git a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp index e2a65d7cc7..bf72e7d111 100644 --- a/lib/du_manager/converters/asn1_rrc_config_helpers.cpp +++ b/lib/du_manager/converters/asn1_rrc_config_helpers.cpp @@ -3151,10 +3151,8 @@ bool srsran::srs_du::calculate_reconfig_with_sync_diff(asn1::rrc_nr::recfg_with_ // As per \c ssb-PositionsInBurst, in \c ServingCellConfigCommon, TS 38.331, the length of \c ssb-PositionsInBurst // needs to be set according to TS 38.213, Section 4.1. out.sp_cell_cfg_common.ssb_positions_in_burst_present = true; - const uint8_t l_max = - band_helper::get_ssb_l_max(du_cell_cfg.dl_carrier.band, - du_cell_cfg.ssb_cfg.scs, - static_cast(du_cell_cfg.dl_cfg_common.freq_info_dl.absolute_freq_point_a)); + const uint8_t l_max = band_helper::get_ssb_l_max( + du_cell_cfg.dl_carrier.band, du_cell_cfg.ssb_cfg.scs, static_cast(du_cell_cfg.dl_carrier.arfcn_f_ref)); srsran_assert(l_max == 4U or l_max == 8U or l_max == 64U, "L_max value {} not valid", l_max); if (l_max == 4U) { out.sp_cell_cfg_common.ssb_positions_in_burst.set_short_bitmap().from_number( diff --git a/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp index 44adf0a9dd..a1a87a89e2 100644 --- a/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp @@ -122,7 +122,7 @@ void f1ap_du_setup_procedure::send_f1_setup_request() f1ap_cell.served_cell_info.five_gs_tac.from_number(cell_cfg.tac); if (cell_cfg.duplx_mode == duplex_mode::TDD) { tdd_info_s& tdd = f1ap_cell.served_cell_info.nr_mode_info.set_tdd(); - tdd.nr_freq_info.nr_arfcn = cell_cfg.dl_carrier.arfcn; + tdd.nr_freq_info.nr_arfcn = cell_cfg.dl_carrier.arfcn_f_ref; tdd.nr_freq_info.freq_band_list_nr.resize(1); tdd.nr_freq_info.freq_band_list_nr[0].freq_band_ind_nr = nr_band_to_uint(cell_cfg.dl_carrier.band); @@ -133,10 +133,10 @@ void f1ap_du_setup_procedure::send_f1_setup_request() srsran_assert(res, "Invalid number of CRBs for DL carrier BW"); } else { fdd_info_s& fdd = f1ap_cell.served_cell_info.nr_mode_info.set_fdd(); - fdd.dl_nr_freq_info.nr_arfcn = cell_cfg.dl_carrier.arfcn; + fdd.dl_nr_freq_info.nr_arfcn = cell_cfg.dl_carrier.arfcn_f_ref; fdd.dl_nr_freq_info.freq_band_list_nr.resize(1); fdd.dl_nr_freq_info.freq_band_list_nr[0].freq_band_ind_nr = nr_band_to_uint(cell_cfg.dl_carrier.band); - fdd.ul_nr_freq_info.nr_arfcn = cell_cfg.ul_carrier->arfcn; + fdd.ul_nr_freq_info.nr_arfcn = cell_cfg.ul_carrier->arfcn_f_ref; fdd.ul_nr_freq_info.freq_band_list_nr.resize(1); fdd.ul_nr_freq_info.freq_band_list_nr[0].freq_band_ind_nr = nr_band_to_uint(cell_cfg.ul_carrier->band); diff --git a/lib/mac/mac_dl/mac_cell_processor.cpp b/lib/mac/mac_dl/mac_cell_processor.cpp index 786037af80..b03ed8c625 100644 --- a/lib/mac/mac_dl/mac_cell_processor.cpp +++ b/lib/mac/mac_dl/mac_cell_processor.cpp @@ -34,10 +34,10 @@ mac_cell_processor::mac_cell_processor(const mac_cell_creation_request& cell_cfg ctrl_exec(ctrl_exec_), phy_cell(phy_notifier_), 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))), + 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))), 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/mac/mac_dl/ssb_assembler.cpp b/lib/mac/mac_dl/ssb_assembler.cpp index 8163470e08..c0480cfa23 100644 --- a/lib/mac/mac_dl/ssb_assembler.cpp +++ b/lib/mac/mac_dl/ssb_assembler.cpp @@ -23,7 +23,7 @@ ssb_assembler::ssb_assembler(const mac_cell_creation_request& cell_cfg) : cell_barred(cell_cfg.cell_barred), intra_f_resel(cell_cfg.intra_freq_resel), ssb_case(band_helper::get_ssb_pattern(cell_cfg.dl_carrier.band, ssb_cfg.scs)), - L_max(ssb_get_L_max(ssb_cfg.scs, cell_cfg.dl_carrier.arfcn, cell_cfg.dl_carrier.band)) + L_max(ssb_get_L_max(ssb_cfg.scs, cell_cfg.dl_carrier.arfcn_f_ref, cell_cfg.dl_carrier.band)) { } diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index 908c57ac4c..d68a5b9018 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -718,18 +718,18 @@ static error_type validate_band_n90(uint32_t arfcn, subcarrier_spac //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -nr_band srsran::band_helper::get_band_from_dl_arfcn(uint32_t arfcn) +nr_band srsran::band_helper::get_band_from_dl_arfcn(uint32_t arfcn_f_ref) { // As per Table 5.4.2.3-1, TS 38.104, v17.8.0, band n28 has an additional ARFCN value outside the interval of step 20. const uint32_t arfcn_n28 = 155608U; - if (arfcn == arfcn_n28) { + if (arfcn_f_ref == arfcn_n28) { return nr_band::n28; } for (const nr_band_raster& band : nr_band_table) { // Check given ARFCN is between the first and last possible ARFCN. - if (arfcn >= band.dl_nref_first and arfcn <= band.dl_nref_last and - ((arfcn - band.dl_nref_first) % band.dl_nref_step) == 0) { + if (arfcn_f_ref >= band.dl_nref_first and arfcn_f_ref <= band.dl_nref_last and + ((arfcn_f_ref - band.dl_nref_first) % band.dl_nref_step) == 0) { return band.band; } } @@ -737,29 +737,29 @@ nr_band srsran::band_helper::get_band_from_dl_arfcn(uint32_t arfcn) } error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_band band, - uint32_t arfcn, + uint32_t arfcn_f_ref, subcarrier_spacing scs, bs_channel_bandwidth bw) { // Validates first the bands with non-standard ARFCN values. if (band == nr_band::n28) { - return validate_band_n28(arfcn, bw); + return validate_band_n28(arfcn_f_ref, bw); } if (band == nr_band::n46) { - return validate_band_n46(arfcn, bw); + return validate_band_n46(arfcn_f_ref, bw); } if (band == nr_band::n90) { - return validate_band_n90(arfcn, scs); + return validate_band_n90(arfcn_f_ref, scs); } if (band == nr_band::n96) { - return validate_band_n96(arfcn, bw); + return validate_band_n96(arfcn_f_ref, bw); } if (band == nr_band::n102) { - return validate_band_n102(arfcn, bw); + return validate_band_n102(arfcn_f_ref, bw); } // NOTE: This function restricts the choice of ARFCN for bands n41, n77, n78, and n79. As per Section 5.4.2.3, @@ -782,8 +782,8 @@ error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_ban 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 >= raster_band.dl_nref_first and arfcn <= raster_band.dl_nref_last and - ((arfcn - raster_band.dl_nref_first) % raster_band.dl_nref_step) == 0) { + if (arfcn_f_ref >= raster_band.dl_nref_first and arfcn_f_ref <= raster_band.dl_nref_last and + ((arfcn_f_ref - raster_band.dl_nref_first) % raster_band.dl_nref_step) == 0) { return {}; } return make_unexpected( @@ -967,9 +967,9 @@ double srsran::band_helper::get_abs_freq_point_a_from_center_freq(uint32_t nof_p return center_freq - static_cast(nof_prb / 2 * scs_to_khz(subcarrier_spacing::kHz15) * KHZ_TO_HZ * NRE); } -uint32_t srsran::band_helper::get_abs_freq_point_a_arfcn(uint32_t nof_prb, uint32_t arfcn) +uint32_t srsran::band_helper::get_abs_freq_point_a_arfcn(uint32_t nof_prb, uint32_t arfcn_f_ref) { - return freq_to_nr_arfcn(get_abs_freq_point_a_from_center_freq(nof_prb, nr_arfcn_to_freq(arfcn))); + return freq_to_nr_arfcn(get_abs_freq_point_a_from_center_freq(nof_prb, nr_arfcn_to_freq(arfcn_f_ref))); } double srsran::band_helper::get_center_freq_from_abs_freq_point_a(uint32_t nof_prb, uint32_t freq_point_a_arfcn) @@ -1254,7 +1254,7 @@ srsran::band_helper::get_ssb_coreset0_freq_location(unsigned dl_arfcn, std::optional result; - // Get f_ref, point_A from dl_arfcn, band and bandwidth. + // Get f_ref, point_A from dl_f_ref_arfcn, band and bandwidth. ssb_freq_position_generator du_cfg{dl_arfcn, band, n_rbs, scs_common, scs_ssb}; // Iterate over different SSB candidates and select the valid CORESET#0 index with the narrowest bandwidth. @@ -1320,7 +1320,7 @@ srsran::band_helper::get_ssb_coreset0_freq_location_for_cset0_idx(unsigned std::optional result; - // Get f_ref, point_A from dl_arfcn, band and bandwidth. + // Get f_ref, point_A from dl_f_ref_arfcn, band and bandwidth. ssb_freq_position_generator du_cfg{dl_arfcn, band, n_rbs, scs_common, scs_ssb}; // Get the maximum Coreset0 index that can be used for the Tables 13-[1-6], TS 38.213. @@ -1482,7 +1482,7 @@ std::optional srsran::band_helper::get_ssb_arfcn(unsigned srsran_assert(scs_ssb < subcarrier_spacing::kHz60, "Only 15kHz and 30kHz currently supported for SSB subcarrier spacing"); - // Get f_ref, point_A from dl_arfcn, band and bandwidth. + // Get f_ref, point_A from dl_f_ref_arfcn, band and bandwidth. ssb_freq_position_generator du_cfg{dl_arfcn, band, n_rbs, scs_common, scs_ssb}; ssb_freq_location ssb = du_cfg.get_next_ssb_location(); while (ssb.is_valid) { diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp index 65781fdfc4..19e9cde949 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp @@ -237,7 +237,7 @@ void rrc_reestablishment_procedure::transfer_reestablishment_context_and_update_ uint32_t ssb_arfcn = context.cfg.meas_timings.begin()->freq_and_timing.value().carrier_freq; cu_cp_ue_notifier.update_security_context(old_ue_reest_context.sec_context); cu_cp_ue_notifier.perform_horizontal_key_derivation(context.cell.pci, ssb_arfcn); - logger.log_debug("Refreshed keys horizontally. pci={} ssb-arfcn={}", context.cell.pci, ssb_arfcn); + logger.log_debug("Refreshed keys horizontally. pci={} ssb-arfcn_f_ref={}", context.cell.pci, ssb_arfcn); } void rrc_reestablishment_procedure::create_srb1() diff --git a/lib/scheduler/common_scheduling/ssb_scheduler.cpp b/lib/scheduler/common_scheduling/ssb_scheduler.cpp index e610dc1233..1dfbbd6875 100644 --- a/lib/scheduler/common_scheduling/ssb_scheduler.cpp +++ b/lib/scheduler/common_scheduling/ssb_scheduler.cpp @@ -25,7 +25,7 @@ ssb_scheduler::ssb_scheduler(const cell_configuration& cfg_) : void ssb_scheduler::run_slot(cell_resource_allocator& res_alloc, const slot_point& sl_point) { // Only FR1 are supported in this implementation. - const uint32_t freq_arfcn = cell_cfg.dl_carrier.arfcn; + const uint32_t freq_arfcn = cell_cfg.dl_carrier.arfcn_f_ref; srsran_assert(freq_arfcn < static_cast(FR1_MAX_FREQUENCY_ARFCN), "Frenquencies in the range FR2 not supported"); @@ -90,7 +90,7 @@ void ssb_scheduler::ssb_alloc_case_A_C(ssb_information_list& ssb_list, // The OFDM symbols allocations for Case A and case C are identical; the only difference is the cutoff frequency, // which is 3GHz for case A and C paired, but 1.88GHz for case C unpaired. // For frequency lower than cutoff, SSB is allocated in slot 0 and 1 only. - if (cell_cfg.dl_carrier.arfcn <= freq_arfcn_cut_off and slot_idx > 1) { + if (cell_cfg.dl_carrier.arfcn_f_ref <= freq_arfcn_cut_off and slot_idx > 1) { return; } @@ -129,7 +129,7 @@ void ssb_scheduler::ssb_alloc_case_B(ssb_information_list& ssb_list, const slot_ uint32_t slot_idx = sl_point_mod.to_uint(); // For frequency lower than cutoff, SSB is allocated in slot 0 and 1 only. - if (cell_cfg.dl_carrier.arfcn <= CUTOFF_FREQ_ARFCN_CASE_A_B_C and slot_idx > 1) { + if (cell_cfg.dl_carrier.arfcn_f_ref <= CUTOFF_FREQ_ARFCN_CASE_A_B_C and slot_idx > 1) { return; } diff --git a/lib/scheduler/config/cell_configuration.cpp b/lib/scheduler/config/cell_configuration.cpp index 8a9c92ce6c..59abcda1de 100644 --- a/lib/scheduler/config/cell_configuration.cpp +++ b/lib/scheduler/config/cell_configuration.cpp @@ -41,7 +41,7 @@ cell_configuration::cell_configuration(const scheduler_expert_config& ssb_case(band_helper::get_ssb_pattern(msg.dl_carrier.band, msg.ssb_config.scs)), paired_spectrum(band_helper::is_paired_spectrum(msg.dl_carrier.band)), band(msg.dl_carrier.band), - L_max(ssb_get_L_max(msg.ssb_config.scs, msg.dl_carrier.arfcn, msg.dl_carrier.band)), + L_max(ssb_get_L_max(msg.ssb_config.scs, msg.dl_carrier.arfcn_f_ref, msg.dl_carrier.band)), ntn_cs_koffset(msg.ntn_cs_koffset) { if (tdd_cfg_common.has_value()) { diff --git a/lib/scheduler/config/serving_cell_config_factory.cpp b/lib/scheduler/config/serving_cell_config_factory.cpp index 28c7a4b496..9e6690d75b 100644 --- a/lib/scheduler/config/serving_cell_config_factory.cpp +++ b/lib/scheduler/config/serving_cell_config_factory.cpp @@ -31,7 +31,7 @@ cell_config_builder_params_extended::cell_config_builder_params_extended(const c cell_config_builder_params(source) { if (not band.has_value()) { - band = band_helper::get_band_from_dl_arfcn(dl_arfcn); + band = band_helper::get_band_from_dl_arfcn(dl_f_ref_arfcn); } cell_nof_crbs = band_helper::get_n_rbs_from_bw(channel_bw_mhz, scs_common, band_helper::get_freq_range(band.value())); @@ -60,10 +60,10 @@ cell_config_builder_params_extended::cell_config_builder_params_extended(const c std::optional ssb_freq_loc; if (coreset0_index.has_value()) { ssb_freq_loc = band_helper::get_ssb_coreset0_freq_location_for_cset0_idx( - dl_arfcn, *band, cell_nof_crbs, scs_common, ssb_scs, search_space0_index, coreset0_index.value()); + dl_f_ref_arfcn, *band, cell_nof_crbs, scs_common, ssb_scs, search_space0_index, coreset0_index.value()); } else { ssb_freq_loc = band_helper::get_ssb_coreset0_freq_location( - dl_arfcn, *band, cell_nof_crbs, scs_common, ssb_scs, search_space0_index, max_coreset0_duration); + dl_f_ref_arfcn, *band, cell_nof_crbs, scs_common, ssb_scs, search_space0_index, max_coreset0_duration); } if (!ssb_freq_loc.has_value()) { report_error("Unable to derive a valid SSB pointA and k_SSB for cell id ({}).\n", pci); @@ -75,7 +75,7 @@ cell_config_builder_params_extended::cell_config_builder_params_extended(const c // Compute and store final SSB position based on (selected) values. ssb_arfcn = band_helper::get_ssb_arfcn( - dl_arfcn, *band, cell_nof_crbs, scs_common, ssb_scs, offset_to_point_a.value(), k_ssb.value()); + dl_f_ref_arfcn, *band, cell_nof_crbs, scs_common, ssb_scs, offset_to_point_a.value(), k_ssb.value()); srsran_assert(ssb_arfcn.has_value(), "Unable to derive SSB location correctly"); } @@ -86,11 +86,11 @@ static carrier_configuration make_default_carrier_configuration(const cell_confi cfg.carrier_bw_mhz = bs_channel_bandwidth_to_MHz(params.channel_bw_mhz); cfg.band = params.band.value(); if (is_dl) { - cfg.arfcn = params.dl_arfcn; - cfg.nof_ant = params.nof_dl_ports; + cfg.arfcn_f_ref = params.dl_f_ref_arfcn; + cfg.nof_ant = params.nof_dl_ports; } else { - cfg.arfcn = band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_arfcn, cfg.band); - cfg.nof_ant = 1; + 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); srsran_assert(cfg.carrier_bw_mhz >= min_channel_bandwidth_to_MHz(min_channel_bw), @@ -254,9 +254,13 @@ srsran::config_helpers::make_default_dl_config_common(const cell_config_builder_ cfg.freq_info_dl.scs_carrier_list.back().carrier_bandwidth = params.cell_nof_crbs; cfg.freq_info_dl.absolute_frequency_ssb = params.ssb_arfcn.value(); - const double dl_f_ref = band_helper::get_abs_freq_point_a_from_f_ref( - band_helper::nr_arfcn_to_freq(params.dl_arfcn), params.cell_nof_crbs, params.scs_common); - cfg.freq_info_dl.absolute_freq_point_a = band_helper::freq_to_nr_arfcn(dl_f_ref); + + // \c params.dl_f_ref_arfcn refers to the ARFCN of the DL f_ref, as per TS 38.104, Section 5.4.2.1. + const double dl_absolute_freq_point_a = band_helper::get_abs_freq_point_a_from_f_ref( + band_helper::nr_arfcn_to_freq(params.dl_f_ref_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, + // Section 4.4.4.2. + cfg.freq_info_dl.absolute_freq_point_a = band_helper::freq_to_nr_arfcn(dl_absolute_freq_point_a); // Configure initial DL BWP. cfg.init_dl_bwp.generic_params = make_default_init_bwp(params); @@ -330,23 +334,16 @@ 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_arfcn, params.band); - // This is f_ref frequency for UL, expressed in Hz and obtained from the corresponding ARFCN. - - const frequency_range freq_range = band_helper::get_freq_range(params.band.value()); - const duplex_mode duplex = band_helper::get_duplex_mode(params.band.value()); - - const unsigned nof_crbs = band_helper::get_n_rbs_from_bw(params.channel_bw_mhz, params.scs_common, freq_range); - - const double ul_f_ref = band_helper::get_abs_freq_point_a_from_f_ref( - band_helper::nr_arfcn_to_freq(ul_arfcn), nof_crbs, params.scs_common); - // absolute_freq_point_a needs to be expressed as in ARFCN, as per \c absoluteFrequencyPointA definition in 38.211, + 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, // Section 4.4.4.2. - cfg.freq_info_ul.absolute_freq_point_a = band_helper::freq_to_nr_arfcn(ul_f_ref); + cfg.freq_info_ul.absolute_freq_point_a = band_helper::freq_to_nr_arfcn(ul_absolute_freq_point_a); cfg.freq_info_ul.scs_carrier_list.resize(1); cfg.freq_info_ul.scs_carrier_list[0].scs = params.scs_common; cfg.freq_info_ul.scs_carrier_list[0].offset_to_carrier = 0; - cfg.freq_info_ul.scs_carrier_list[0].carrier_bandwidth = nof_crbs; + cfg.freq_info_ul.scs_carrier_list[0].carrier_bandwidth = params.cell_nof_crbs; cfg.freq_info_ul.freq_band_list.emplace_back(); cfg.freq_info_ul.freq_band_list.back().band = *params.band; cfg.init_ul_bwp.generic_params = make_default_init_bwp(params); @@ -365,6 +362,8 @@ srsran::config_helpers::make_default_ul_config_common(const cell_config_builder_ // Although this is not specified in the TS, from our tests, the UE expects Msg1-SCS to be given when using short // PRACH Preambles formats. With long formats, we can set Msg1-SCS as \c invalid, in which case the UE derives the // PRACH SCS from \c prach-ConfigurationIndex in RACH-ConfigGeneric. + const frequency_range freq_range = band_helper::get_freq_range(params.band.value()); + const duplex_mode duplex = band_helper::get_duplex_mode(params.band.value()); cfg.init_ul_bwp.rach_cfg_common->msg1_scs = is_long_preamble(prach_configuration_get( freq_range, duplex, cfg.init_ul_bwp.rach_cfg_common->rach_cfg_generic.prach_config_index) diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 3e876f30d7..4e2d1305b0 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -1122,15 +1122,15 @@ static cell_config_builder_params generate_custom_cell_config_builder_params(dup { cell_config_builder_params params{}; params.scs_common = dplx_mode == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; - params.dl_arfcn = dplx_mode == duplex_mode::FDD ? 530000 : 520002; - params.band = band_helper::get_band_from_dl_arfcn(params.dl_arfcn); + params.dl_f_ref_arfcn = dplx_mode == duplex_mode::FDD ? 530000 : 520002; + params.band = band_helper::get_band_from_dl_arfcn(params.dl_f_ref_arfcn); params.channel_bw_mhz = dplx_mode == duplex_mode::FDD ? srsran::bs_channel_bandwidth::MHz20 : bs_channel_bandwidth::MHz100; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(params.dl_f_ref_arfcn, *params.band, nof_crbs, params.scs_common, diff --git a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp index db4fc63dda..39939aff50 100644 --- a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp @@ -242,7 +242,7 @@ void benchmark_tdd(benchmarker& bm, const bench_params& params) sched_cfg.ue.max_pdcch_alloc_attempts_per_slot = params.max_dl_grants_per_slot; cell_config_builder_params builder_params{}; - builder_params.dl_arfcn = 520002; + builder_params.dl_f_ref_arfcn = 520002; builder_params.band = nr_band::n41; builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz100; builder_params.scs_common = subcarrier_spacing::kHz30; diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 8652c989a6..5dc52893f7 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -156,10 +156,9 @@ class du_ran_resource_manager_tester : public du_ran_resource_manager_tester_bas public ::testing::TestWithParam { protected: - explicit du_ran_resource_manager_tester(cell_config_builder_params params_ = {.dl_arfcn = GetParam().duplx_mode == - duplex_mode::FDD - ? 365000U - : 520002U}) : + explicit du_ran_resource_manager_tester( + cell_config_builder_params params_ = {.dl_f_ref_arfcn = GetParam().duplx_mode == duplex_mode::FDD ? 365000U + : 520002U}) : du_ran_resource_manager_tester_base(params_, config_helpers::make_default_du_cell_config(params_)) { srsran_assert(default_ue_cell_cfg.csi_meas_cfg.has_value() and @@ -607,7 +606,7 @@ class du_ran_res_mng_pucch_cnt_tester : public du_ran_resource_manager_tester_ba public ::testing::TestWithParam { protected: - explicit du_ran_res_mng_pucch_cnt_tester(cell_config_builder_params params_ = {.dl_arfcn = 520002U}) : + explicit du_ran_res_mng_pucch_cnt_tester(cell_config_builder_params params_ = {.dl_f_ref_arfcn = 520002U}) : du_ran_resource_manager_tester_base(params_, make_custom_du_cell_config_for_pucch_cnt(GetParam(), params_), GetParam().max_allowed_pucch_grants) @@ -713,7 +712,7 @@ class du_ran_res_mng_pucch_cnt_sr_only_tester : public du_ran_resource_manager_t public ::testing::TestWithParam { protected: - explicit du_ran_res_mng_pucch_cnt_sr_only_tester(cell_config_builder_params params_ = {.dl_arfcn = 520002U, + explicit du_ran_res_mng_pucch_cnt_sr_only_tester(cell_config_builder_params params_ = {.dl_f_ref_arfcn = 520002U, .csi_rs_enabled = false}) : du_ran_resource_manager_tester_base(params_, make_custom_du_cell_config_for_pucch_cnt(GetParam(), params_), diff --git a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp index dc6d864dca..0a5e942e59 100644 --- a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp @@ -141,9 +141,9 @@ class base_paging_sched_tester cell_config_builder_params cell_cfg{}; if (duplx_mode == duplex_mode::TDD) { // Band 40. - cell_cfg.dl_arfcn = 465000; + cell_cfg.dl_f_ref_arfcn = 465000; cell_cfg.scs_common = scs; - cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); + cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_f_ref_arfcn); cell_cfg.channel_bw_mhz = carrier_bw; } return test_helpers::make_default_sched_cell_configuration_request(cell_cfg); diff --git a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp index aa9db5c3a9..406756dac4 100644 --- a/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/prach_scheduler_test.cpp @@ -42,7 +42,7 @@ make_custom_sched_cell_configuration_request(const prach_test_params test_params .scs_common = test_params.scs, .channel_bw_mhz = srsran::bs_channel_bandwidth::MHz20, .band = test_params.band}; // For TDD, set DL ARFCN according to the band. if (not band_helper::is_paired_spectrum(test_params.band)) { - params.dl_arfcn = 520002; + params.dl_f_ref_arfcn = 520002; } sched_cell_configuration_request_message sched_req = test_helpers::make_default_sched_cell_configuration_request(params); diff --git a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp index 2b84534245..bfeb5d7c08 100644 --- a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp @@ -99,7 +99,7 @@ class base_ra_scheduler_test cell_config_builder_params builder_params{}; builder_params.scs_common = t_params.scs; if (dplx_mode == srsran::duplex_mode::TDD) { - builder_params.dl_arfcn = 520000; + builder_params.dl_f_ref_arfcn = 520000; builder_params.band = nr_band::n41; } if (t_params.scs == srsran::subcarrier_spacing::kHz30) { diff --git a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp index c942fb2496..d4e227f1d8 100644 --- a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp @@ -170,11 +170,11 @@ struct sib_test_bench { { cell_config_builder_params cell_cfg{}; if (duplx_mode == srsran::duplex_mode::FDD) { - cell_cfg.dl_arfcn = init_bwp_scs == subcarrier_spacing::kHz15 ? 536020 : 176300; - cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); + cell_cfg.dl_f_ref_arfcn = init_bwp_scs == subcarrier_spacing::kHz15 ? 536020 : 176300; + cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_f_ref_arfcn); } else { // Random ARFCN that must be in FR1 and > 3GHz. - cell_cfg.dl_arfcn = init_bwp_scs == subcarrier_spacing::kHz15 ? 286400 : 465000; + cell_cfg.dl_f_ref_arfcn = init_bwp_scs == subcarrier_spacing::kHz15 ? 286400 : 465000; cell_cfg.band = init_bwp_scs == subcarrier_spacing::kHz15 ? nr_band::n50 : nr_band::n40; } cell_cfg.scs_common = init_bwp_scs; @@ -208,9 +208,9 @@ struct sib_test_bench { uint16_t carrier_bw_mhz) { cell_config_builder_params cell_cfg{}; - cell_cfg.dl_arfcn = freq_arfcn; + cell_cfg.dl_f_ref_arfcn = freq_arfcn; cell_cfg.scs_common = init_bwp_scs; - cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); + cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_f_ref_arfcn); cell_cfg.channel_bw_mhz = static_cast(carrier_bw_mhz); const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( @@ -219,7 +219,7 @@ struct sib_test_bench { cell_cfg.band.has_value() ? band_helper::get_freq_range(cell_cfg.band.value()) : frequency_range::FR1); std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(cell_cfg.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(cell_cfg.dl_f_ref_arfcn, *cell_cfg.band, nof_crbs, cell_cfg.scs_common, diff --git a/tests/unittests/scheduler/common_scheduling/ssb_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/ssb_scheduler_test.cpp index d1e17b1c35..1989664c28 100644 --- a/tests/unittests/scheduler/common_scheduling/ssb_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/ssb_scheduler_test.cpp @@ -101,7 +101,7 @@ struct ssb_test_bench { uint8_t k_ssb) { sched_cell_configuration_request_message msg = test_helpers::make_default_sched_cell_configuration_request(); - msg.dl_carrier.arfcn = freq_arfcn; + msg.dl_carrier.arfcn_f_ref = freq_arfcn; msg.dl_carrier.band = band_helper::get_band_from_dl_arfcn(freq_arfcn); msg.dl_cfg_common.freq_info_dl.offset_to_point_a = offset_to_point_A; msg.dl_cfg_common.init_dl_bwp.generic_params.scs = init_bwp_scs; @@ -197,7 +197,7 @@ void test_ssb_case_A_C(const slot_point& slot_tx, // For frequencies lower than the cutoff, there should only be at most 4 SSB opportunities (4 left-most bits in // in_burst_bitmap). - if (cell_cfg.dl_carrier.arfcn <= freq_cutoff) { + if (cell_cfg.dl_carrier.arfcn_f_ref <= freq_cutoff) { TESTASSERT((cell_cfg.ssb_cfg.ssb_bitmap & 0b00001111) == 0, TEST_HARQ_ASSERT_MSG(slot_tx.to_uint(), ssb_cfg.ssb_period, cell_cfg.ssb_case)); } @@ -279,7 +279,7 @@ void test_ssb_case_B(const slot_point& slot_tx, // For frequencies lower than the cutoff, there should only be at most 4 SSB opportunities (4 left-most bits in // in_burst_bitmap). - if (cell_cfg.dl_carrier.arfcn <= CUTOFF_FREQ_ARFCN_CASE_A_B_C) { + if (cell_cfg.dl_carrier.arfcn_f_ref <= CUTOFF_FREQ_ARFCN_CASE_A_B_C) { TESTASSERT((in_burst_bitmap & 0b00001111) == 0, TEST_HARQ_ASSERT_MSG(slot_tx.to_uint(), ssb_cfg.ssb_period, cell_cfg.ssb_case)); } diff --git a/tests/unittests/scheduler/multi_cell_scheduler_test.cpp b/tests/unittests/scheduler/multi_cell_scheduler_test.cpp index e0e8799d5e..596bc74fd0 100644 --- a/tests/unittests/scheduler/multi_cell_scheduler_test.cpp +++ b/tests/unittests/scheduler/multi_cell_scheduler_test.cpp @@ -31,14 +31,14 @@ class base_multi_cell_scheduler_tester : public scheduler_test_bench cell_config_builder_params params{}; params.scs_common = test_params.dplx_mode == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; - params.dl_arfcn = test_params.dplx_mode == duplex_mode::FDD ? 530000 : 520002; - params.band = band_helper::get_band_from_dl_arfcn(params.dl_arfcn); + params.dl_f_ref_arfcn = test_params.dplx_mode == duplex_mode::FDD ? 530000 : 520002; + params.band = band_helper::get_band_from_dl_arfcn(params.dl_f_ref_arfcn); params.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(params.dl_f_ref_arfcn, *params.band, nof_crbs, params.scs_common, diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index 3f24623078..2c5df389f0 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -190,9 +190,9 @@ class scheduler_impl_tester cell_config_builder_params cell_cfg{}; if (mode == duplex_mode::TDD) { // Band 40. - cell_cfg.dl_arfcn = 474000; + cell_cfg.dl_f_ref_arfcn = 474000; cell_cfg.scs_common = srsran::subcarrier_spacing::kHz30; - cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_arfcn); + cell_cfg.band = band_helper::get_band_from_dl_arfcn(cell_cfg.dl_f_ref_arfcn); cell_cfg.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( @@ -201,7 +201,7 @@ class scheduler_impl_tester cell_cfg.band.has_value() ? band_helper::get_freq_range(cell_cfg.band.value()) : frequency_range::FR1); std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(cell_cfg.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(cell_cfg.dl_f_ref_arfcn, *cell_cfg.band, nof_crbs, cell_cfg.scs_common, @@ -744,7 +744,7 @@ TEST_P(multiple_ue_sched_tester, when_scheduling_multiple_ue_in_small_bw_neither if (params.duplx_mode == duplex_mode::TDD) { builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth::MHz10; } - builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); + builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_f_ref_arfcn); const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( builder_params.channel_bw_mhz, @@ -753,7 +753,7 @@ TEST_P(multiple_ue_sched_tester, when_scheduling_multiple_ue_in_small_bw_neither : frequency_range::FR1); std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(builder_params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(builder_params.dl_f_ref_arfcn, *builder_params.band, nof_crbs, builder_params.scs_common, diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index 4794a3fb55..aa697e77d7 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -416,9 +416,9 @@ class scheduler_policy_partial_slot_tdd_test : public base_scheduler_policy_test base_scheduler_policy_test(GetParam(), config_helpers::make_default_scheduler_expert_config(), []() { cell_config_builder_params builder_params{}; // Band 40. - builder_params.dl_arfcn = 465000; + builder_params.dl_f_ref_arfcn = 465000; builder_params.scs_common = subcarrier_spacing::kHz30; - builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); + builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_f_ref_arfcn); builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( @@ -428,7 +428,7 @@ class scheduler_policy_partial_slot_tdd_test : public base_scheduler_policy_test : frequency_range::FR1); std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(builder_params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(builder_params.dl_f_ref_arfcn, *builder_params.band, nof_crbs, builder_params.scs_common, diff --git a/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp b/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp index acc820cda4..e649178a6f 100644 --- a/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp +++ b/tests/unittests/scheduler/scheduler_ta_cmd_test.cpp @@ -27,12 +27,12 @@ class scheduler_ta_cmd_tester : public scheduler_test_bench, public ::testing::T this->add_cell([this, duplex_mode = GetParam()]() { if (duplex_mode == duplex_mode::TDD) { params.scs_common = subcarrier_spacing::kHz30; - params.dl_arfcn = 520002; + params.dl_f_ref_arfcn = 520002; params.band = nr_band::n41; params.channel_bw_mhz = bs_channel_bandwidth::MHz20; } else { params.scs_common = subcarrier_spacing::kHz15; - params.dl_arfcn = 365000; + params.dl_f_ref_arfcn = 365000; params.band = nr_band::n3; params.channel_bw_mhz = bs_channel_bandwidth::MHz20; } @@ -40,7 +40,7 @@ class scheduler_ta_cmd_tester : public scheduler_test_bench, public ::testing::T params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(params.dl_f_ref_arfcn, *params.band, nof_crbs, params.scs_common, diff --git a/tests/unittests/scheduler/scheduler_tdd_test.cpp b/tests/unittests/scheduler/scheduler_tdd_test.cpp index c51e8e0d7c..7a78585b03 100644 --- a/tests/unittests/scheduler/scheduler_tdd_test.cpp +++ b/tests/unittests/scheduler/scheduler_tdd_test.cpp @@ -37,14 +37,14 @@ class base_scheduler_tdd_tester : public scheduler_test_bench // Add Cell. this->add_cell([this, &testparams]() { params.scs_common = testparams.tdd_cfg.ref_scs; - params.dl_arfcn = 520002; + params.dl_f_ref_arfcn = 520002; params.band = nr_band::n41; params.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( params.channel_bw_mhz, params.scs_common, band_helper::get_freq_range(*params.band)); static const uint8_t ss0_idx = 0; std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(params.dl_f_ref_arfcn, *params.band, nof_crbs, params.scs_common, diff --git a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp index dc08ea6494..0bb860b8d3 100644 --- a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp +++ b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp @@ -26,15 +26,15 @@ class base_scheduler_conres_test : public scheduler_test_bench scheduler_test_bench(4, duplx_mode == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30) { if (duplx_mode == duplex_mode::TDD) { - builder_params.dl_arfcn = 520002; + builder_params.dl_f_ref_arfcn = 520002; builder_params.scs_common = subcarrier_spacing::kHz30; - builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); + builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_f_ref_arfcn); builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz10; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( builder_params.channel_bw_mhz, builder_params.scs_common, band_helper::get_freq_range(*builder_params.band)); static const uint8_t ss0_idx = 0; std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(builder_params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(builder_params.dl_f_ref_arfcn, *builder_params.band, nof_crbs, builder_params.scs_common, diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 35c307c1f5..89bdee2ac8 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -25,7 +25,7 @@ class slice_scheduler_test cell_config_builder_params params{}; params.scs_common = subcarrier_spacing::kHz30; params.channel_bw_mhz = bs_channel_bandwidth::MHz100; - params.dl_arfcn = 520000; + params.dl_f_ref_arfcn = 520000; params.band = nr_band::n41; return params; }(), diff --git a/tests/unittests/scheduler/test_utils/config_generators.h b/tests/unittests/scheduler/test_utils/config_generators.h index e63b81496b..c2e7a2b53d 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.h +++ b/tests/unittests/scheduler/test_utils/config_generators.h @@ -269,7 +269,8 @@ inline uplink_config make_test_ue_uplink_config(const config_helpers::cell_confi // the active DL BWP of a corresponding serving cell. // Inactive for format1_0." // Note2: Only k1 >= 4 supported. - nr_band band = params.band.has_value() ? params.band.value() : band_helper::get_band_from_dl_arfcn(params.dl_arfcn); + nr_band band = + params.band.has_value() ? params.band.value() : band_helper::get_band_from_dl_arfcn(params.dl_f_ref_arfcn); if (band_helper::get_duplex_mode(band) == duplex_mode::FDD) { pucch_cfg.dl_data_to_ul_ack = {params.min_k1}; } else { diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 85444c76ef..1ba6ff5b67 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -134,7 +134,7 @@ test_bench::test_bench(const test_bench_params& params, cell_config_builder_params cfg_params{}; cfg_params.csi_rs_enabled = true; cfg_params.scs_common = params.is_tdd ? subcarrier_spacing::kHz30 : subcarrier_spacing::kHz15; - cfg_params.dl_arfcn = params.is_tdd ? 520000U : 365000U; + cfg_params.dl_f_ref_arfcn = params.is_tdd ? 520000U : 365000U; sched_ue_creation_request_message ue_req = test_helpers::create_default_sched_ue_creation_request(cfg_params); ue_req.ue_index = main_ue_idx; diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h index 17cbea0307..59073bdadb 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h @@ -32,12 +32,12 @@ make_default_sched_cell_configuration_request_scs(subcarrier_spacing scs, bool t .scs_common = scs, .channel_bw_mhz = bs_channel_bandwidth::MHz20, .nof_dl_ports = 1}; if (scs == subcarrier_spacing::kHz15) { // Band n5 for FDD, band n41 for TDD. - params.dl_arfcn = tdd_mode ? 499200 : 530000; - params.band = band_helper::get_band_from_dl_arfcn(params.dl_arfcn); + params.dl_f_ref_arfcn = tdd_mode ? 499200 : 530000; + params.band = band_helper::get_band_from_dl_arfcn(params.dl_f_ref_arfcn); } else if (scs == subcarrier_spacing::kHz30) { // Band n5 for FDD, band n77 or n78 for TDD. - params.dl_arfcn = tdd_mode ? 630000 : 176000; - params.band = band_helper::get_band_from_dl_arfcn(params.dl_arfcn); + params.dl_f_ref_arfcn = tdd_mode ? 630000 : 176000; + params.band = band_helper::get_band_from_dl_arfcn(params.dl_f_ref_arfcn); } return sched_cell_configuration_request_message{test_helpers::make_default_sched_cell_configuration_request(params)}; } @@ -80,7 +80,7 @@ inline sched_cell_configuration_request_message make_custom_sched_cell_configura 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::MHz10, - .dl_arfcn = is_tdd ? 520000U : 365000U}); + .dl_f_ref_arfcn = is_tdd ? 520000U : 365000U}); req.ul_cfg_common.init_ul_bwp.pucch_cfg_common->pucch_resource_common = pucch_res_common; return req; } diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 49aad00ab0..af4a1b4924 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -39,9 +39,9 @@ static cell_config_builder_params test_builder_params(duplex_mode duplx_mode) cell_config_builder_params builder_params{}; if (duplx_mode == duplex_mode::TDD) { // Band 40. - builder_params.dl_arfcn = 474000; + builder_params.dl_f_ref_arfcn = 474000; builder_params.scs_common = srsran::subcarrier_spacing::kHz30; - builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); + builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_f_ref_arfcn); builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz20; const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( @@ -51,7 +51,7 @@ static cell_config_builder_params test_builder_params(duplex_mode duplx_mode) : frequency_range::FR1); std::optional ssb_freq_loc = - band_helper::get_ssb_coreset0_freq_location(builder_params.dl_arfcn, + band_helper::get_ssb_coreset0_freq_location(builder_params.dl_f_ref_arfcn, *builder_params.band, nof_crbs, builder_params.scs_common, @@ -62,7 +62,7 @@ static cell_config_builder_params test_builder_params(duplex_mode duplx_mode) builder_params.k_ssb = ssb_freq_loc->k_ssb; builder_params.coreset0_index = ssb_freq_loc->coreset0_idx; } else { - builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_arfcn); + builder_params.band = band_helper::get_band_from_dl_arfcn(builder_params.dl_f_ref_arfcn); } return builder_params; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp index d9865b3e2b..19d530cbdb 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp @@ -113,7 +113,7 @@ TEST_F(ue_configuration_test, search_spaces_pdcch_candidate_lists_does_not_surpa { cell_config_builder_params params{}; params.scs_common = subcarrier_spacing::kHz30; - params.dl_arfcn = 520002; + params.dl_f_ref_arfcn = 520002; params.band = nr_band::n41; params.channel_bw_mhz = bs_channel_bandwidth::MHz50; msg = test_helpers::make_default_sched_cell_configuration_request(params); diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 143b951468..d658c59cee 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -32,10 +32,10 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam scheduler_expert_config sched_cfg_ = config_helpers::make_default_scheduler_expert_config()) : sched_cfg(sched_cfg_), cell_cfg(*[this]() { - cfg_builder_params.dl_arfcn = GetParam() == duplex_mode::FDD ? 530000 : 520002; + cfg_builder_params.dl_f_ref_arfcn = GetParam() == duplex_mode::FDD ? 530000 : 520002; cfg_builder_params.scs_common = GetParam() == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; - cfg_builder_params.band = band_helper::get_band_from_dl_arfcn(cfg_builder_params.dl_arfcn); + cfg_builder_params.band = band_helper::get_band_from_dl_arfcn(cfg_builder_params.dl_f_ref_arfcn); cfg_builder_params.channel_bw_mhz = bs_channel_bandwidth::MHz20; auto* cfg = cfg_mng.add_cell(test_helpers::make_default_sched_cell_configuration_request(cfg_builder_params), metrics_ue_handler); From fc2e37bd66f0f8cdb5c7e6b237eb0cbcfe6f50ab Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 14 Aug 2024 18:47:29 +0200 Subject: [PATCH 284/407] du: fix nr-arfcn computation in f1ap procedure Signed-off-by: Carlo Galiotto --- .../du/procedures/f1ap_du_setup_procedure.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp index a1a87a89e2..a69f3d7657 100644 --- a/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp @@ -120,23 +120,28 @@ void f1ap_du_setup_procedure::send_f1_setup_request() f1ap_cell.served_cell_info.nr_cgi.nr_cell_id.from_number(cell_cfg.nr_cgi.nci.value()); f1ap_cell.served_cell_info.five_gs_tac_present = true; f1ap_cell.served_cell_info.five_gs_tac.from_number(cell_cfg.tac); + const unsigned nof_crbs = band_helper::get_n_rbs_from_bw( + MHz_to_bs_channel_bandwidth(cell_cfg.dl_carrier.carrier_bw_mhz), cell_cfg.scs_common, frequency_range::FR1); + const double absolute_freq_point_a = band_helper::get_abs_freq_point_a_from_f_ref( + band_helper::nr_arfcn_to_freq(cell_cfg.dl_carrier.arfcn_f_ref), nof_crbs, cell_cfg.scs_common); if (cell_cfg.duplx_mode == duplex_mode::TDD) { tdd_info_s& tdd = f1ap_cell.served_cell_info.nr_mode_info.set_tdd(); - tdd.nr_freq_info.nr_arfcn = cell_cfg.dl_carrier.arfcn_f_ref; + tdd.nr_freq_info.nr_arfcn = band_helper::freq_to_nr_arfcn(absolute_freq_point_a); tdd.nr_freq_info.freq_band_list_nr.resize(1); tdd.nr_freq_info.freq_band_list_nr[0].freq_band_ind_nr = nr_band_to_uint(cell_cfg.dl_carrier.band); tdd.tx_bw.nr_scs.value = (nr_scs_opts::options)to_numerology_value(cell_cfg.scs_common); - unsigned nof_crbs = band_helper::get_n_rbs_from_bw( - MHz_to_bs_channel_bandwidth(cell_cfg.dl_carrier.carrier_bw_mhz), cell_cfg.scs_common, frequency_range::FR1); + bool res = asn1::number_to_enum(tdd.tx_bw.nr_nrb, nof_crbs); srsran_assert(res, "Invalid number of CRBs for DL carrier BW"); } else { fdd_info_s& fdd = f1ap_cell.served_cell_info.nr_mode_info.set_fdd(); - fdd.dl_nr_freq_info.nr_arfcn = cell_cfg.dl_carrier.arfcn_f_ref; + fdd.dl_nr_freq_info.nr_arfcn = band_helper::freq_to_nr_arfcn(absolute_freq_point_a); fdd.dl_nr_freq_info.freq_band_list_nr.resize(1); fdd.dl_nr_freq_info.freq_band_list_nr[0].freq_band_ind_nr = nr_band_to_uint(cell_cfg.dl_carrier.band); - fdd.ul_nr_freq_info.nr_arfcn = cell_cfg.ul_carrier->arfcn_f_ref; + const double ul_absolute_freq_point_a = band_helper::get_abs_freq_point_a_from_f_ref( + band_helper::nr_arfcn_to_freq(cell_cfg.ul_carrier->arfcn_f_ref), nof_crbs, cell_cfg.scs_common); + fdd.ul_nr_freq_info.nr_arfcn = band_helper::freq_to_nr_arfcn(ul_absolute_freq_point_a); fdd.ul_nr_freq_info.freq_band_list_nr.resize(1); fdd.ul_nr_freq_info.freq_band_list_nr[0].freq_band_ind_nr = nr_band_to_uint(cell_cfg.ul_carrier->band); From e92697016a4aaf5776bae774f763105b721dd01b Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 19 Aug 2024 10:48:32 +0200 Subject: [PATCH 285/407] du: apply code-format patch Signed-off-by: Carlo Galiotto --- .../flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp | 2 +- tests/benchmarks/du_high/du_high_benchmark.cpp | 2 +- .../unittests/scheduler/common_scheduling/ra_scheduler_test.cpp | 2 +- .../scheduler/common_scheduling/sib1_scheduler_test.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 839eed479d..64aa68b409 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 @@ -148,7 +148,7 @@ 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; + 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; if (std::holds_alternative(parsed_cfg.ru_cfg)) { diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 4e2d1305b0..e273f6a8fc 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -1121,7 +1121,7 @@ class du_high_bench static cell_config_builder_params generate_custom_cell_config_builder_params(duplex_mode dplx_mode) { cell_config_builder_params params{}; - params.scs_common = dplx_mode == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; + params.scs_common = dplx_mode == duplex_mode::FDD ? subcarrier_spacing::kHz15 : subcarrier_spacing::kHz30; params.dl_f_ref_arfcn = dplx_mode == duplex_mode::FDD ? 530000 : 520002; params.band = band_helper::get_band_from_dl_arfcn(params.dl_f_ref_arfcn); params.channel_bw_mhz = diff --git a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp index bfeb5d7c08..f2b78c49d6 100644 --- a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp @@ -100,7 +100,7 @@ class base_ra_scheduler_test builder_params.scs_common = t_params.scs; if (dplx_mode == srsran::duplex_mode::TDD) { builder_params.dl_f_ref_arfcn = 520000; - builder_params.band = nr_band::n41; + builder_params.band = nr_band::n41; } if (t_params.scs == srsran::subcarrier_spacing::kHz30) { builder_params.channel_bw_mhz = srsran::bs_channel_bandwidth::MHz20; diff --git a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp index d4e227f1d8..17a10e7d65 100644 --- a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp @@ -175,7 +175,7 @@ struct sib_test_bench { } else { // Random ARFCN that must be in FR1 and > 3GHz. cell_cfg.dl_f_ref_arfcn = init_bwp_scs == subcarrier_spacing::kHz15 ? 286400 : 465000; - cell_cfg.band = init_bwp_scs == subcarrier_spacing::kHz15 ? nr_band::n50 : nr_band::n40; + cell_cfg.band = init_bwp_scs == subcarrier_spacing::kHz15 ? nr_band::n50 : nr_band::n40; } cell_cfg.scs_common = init_bwp_scs; cell_cfg.channel_bw_mhz = static_cast(carrier_bw_mhz); From 3fe99317a42620922688fe164d5db60a61b0a2c1 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 19 Aug 2024 11:28:43 +0200 Subject: [PATCH 286/407] ofh: fix memory read --- lib/ofh/compression/packing_utils_avx512.h | 3 ++- lib/ofh/compression/packing_utils_neon.h | 6 +++++- .../support/pdcch/pdcch_type0_css_occassions_test.cpp | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/ofh/compression/packing_utils_avx512.h b/lib/ofh/compression/packing_utils_avx512.h index 7726484bde..4b4bf6598f 100644 --- a/lib/ofh/compression/packing_utils_avx512.h +++ b/lib/ofh/compression/packing_utils_avx512.h @@ -145,7 +145,8 @@ inline void pack_prb_big_endian(span comp_prb_buffer, __m512i reg, unsi inline void avx512_unpack_prb_9b_be(span unpacked_iq_data, span packed_data) { // Load input, 27 bytes (fits in one AVX512 register). - __m512i packed_data_epi8 = _mm512_mask_loadu_epi8(_mm512_set1_epi64(0), 0x1fffffff, packed_data.data()); + static constexpr __mmask64 mask = (1UL << 27) - 1UL; + __m512i packed_data_epi8 = _mm512_maskz_loadu_epi8(mask, packed_data.data()); // Duplicate input words (it is required since below in the code every byte will be used twice: // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). diff --git a/lib/ofh/compression/packing_utils_neon.h b/lib/ofh/compression/packing_utils_neon.h index b457a59e4b..82a2c1a322 100644 --- a/lib/ofh/compression/packing_utils_neon.h +++ b/lib/ofh/compression/packing_utils_neon.h @@ -143,9 +143,13 @@ inline void pack_prb_big_endian(span comp_prb_buffer, int16x8x3_t regs, inline void unpack_prb_9b_big_endian(span unpacked_iq_data, span packed_data) { // Load input (we need two NEON register to load 27 bytes). + // The first 16 bytes are loaded directly. uint8x16x2_t packed_vec_u8x2; packed_vec_u8x2.val[0] = vld1q_u8(packed_data.data()); - packed_vec_u8x2.val[1] = vld1q_u8(packed_data.data() + 16); + // Load from 11th byte, which gives us the last 11 bytes plus 5 extra bytes without exceeding a read of 27 bytes. + packed_vec_u8x2.val[1] = vld1q_u8(packed_data.data() + 11); + // Discard the first 5 bytes. + packed_vec_u8x2.val[1] = vextq_u8(packed_vec_u8x2.val[1], vdupq_n_u8(0), 5); // Duplicate input words (it is required since below in the code every byte will be used twice: // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). diff --git a/tests/unittests/scheduler/support/pdcch/pdcch_type0_css_occassions_test.cpp b/tests/unittests/scheduler/support/pdcch/pdcch_type0_css_occassions_test.cpp index 030640eed5..a9f6bd102b 100644 --- a/tests/unittests/scheduler/support/pdcch/pdcch_type0_css_occassions_test.cpp +++ b/tests/unittests/scheduler/support/pdcch/pdcch_type0_css_occassions_test.cpp @@ -127,6 +127,6 @@ TEST_P(pdcch_type0_css_occasions_fixture, fr2) } } -INSTANTIATE_TEST_SUITE_P(OFHCompressionTestSuite, +INSTANTIATE_TEST_SUITE_P(pdcch_type0_css_occasions, pdcch_type0_css_occasions_fixture, ::testing::Combine(::testing::Range(0U, 17U), ::testing::Range(1U, 3U))); \ No newline at end of file From 94f72151242a9407a25b45f880d18fac300abb2f Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 14 Aug 2024 12:53:20 +0200 Subject: [PATCH 287/407] du_high_unit: add option to configure policy scheduler on a per-slice basis --- apps/units/flexible_du/du_high/du_high_config.h | 2 ++ .../du_high/du_high_config_cli11_schema.cpp | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 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 849d02adbd..ae852b7821 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -498,6 +498,8 @@ struct du_high_unit_cell_slice_sched_config { unsigned min_prb_policy_ratio = 0; /// Sets the maximum percentage of PRBs to be allocated to this group. unsigned max_prb_policy_ratio = 100; + /// Policy scheduler parameters for the slice. + policy_scheduler_expert_config slice_policy_sched_cfg = time_rr_scheduler_expert_config{}; }; /// Slice configuration for a cell. 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 4726ad6feb..3160cb23f6 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 @@ -547,8 +547,7 @@ static void configure_cli11_pf_scheduler_expert_args(CLI::App& app, time_pf_sche ->capture_default_str(); } -static void configure_cli11_policy_scheduler_expert_args(CLI::App& app, - du_high_unit_scheduler_expert_config& expert_params) +static void configure_cli11_policy_scheduler_expert_args(CLI::App& app, policy_scheduler_expert_config& expert_params) { static time_pf_scheduler_expert_config pf_sched_expert_cfg; CLI::App* pf_sched_cfg_subcmd = @@ -557,7 +556,7 @@ static void configure_cli11_policy_scheduler_expert_args(CLI::App& auto pf_sched_verify_callback = [&]() { CLI::App* pf_sched_sub_cmd = app.get_subcommand("pf_sched"); if (pf_sched_sub_cmd->count() != 0) { - expert_params.policy_sched_expert_cfg = pf_sched_expert_cfg; + expert_params = pf_sched_expert_cfg; } }; pf_sched_cfg_subcmd->parse_complete_callback(pf_sched_verify_callback); @@ -567,7 +566,7 @@ static void configure_cli11_scheduler_expert_args(CLI::App& app, du_high_unit_sc { CLI::App* policy_sched_cfg_subcmd = add_subcommand(app, "policy_sched_cfg", "Policy scheduler expert configuration")->configurable(); - configure_cli11_policy_scheduler_expert_args(*policy_sched_cfg_subcmd, expert_params); + configure_cli11_policy_scheduler_expert_args(*policy_sched_cfg_subcmd, expert_params.policy_sched_expert_cfg); } static void configure_cli11_ul_common_args(CLI::App& app, du_high_unit_ul_common_config& ul_common_params) @@ -1055,6 +1054,11 @@ static void configure_cli11_slicing_scheduling_args(CLI::App& "Maximum percentage of PRBs to be allocated to the slice") ->capture_default_str() ->check(CLI::Range(1U, 100U)); + + // Policy scheduler configuration. + CLI::App* policy_sched_cfg_subcmd = + add_subcommand(app, "policy_sched_cfg", "Policy scheduler configuration for the slice")->configurable(); + configure_cli11_policy_scheduler_expert_args(*policy_sched_cfg_subcmd, slice_sched_params.slice_policy_sched_cfg); } static void configure_cli11_slicing_args(CLI::App& app, du_high_unit_cell_slice_config& slice_params) From dbf988c42e3c8dab163b7f662d1a6a579e231058 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 14 Aug 2024 13:42:31 +0200 Subject: [PATCH 288/407] du_high_unit,sched: use policy scheduler configured for the slice --- .../units/flexible_du/du_high/du_high_config_translators.cpp | 1 + include/srsran/scheduler/config/slice_rrm_policy_config.h | 3 +++ lib/scheduler/slicing/slice_scheduler.cpp | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) 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 4203bf884f..dad4d59bd2 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 @@ -691,6 +691,7 @@ srsran::generate_du_slicing_rrm_policy_config(span rrm_policy_cfgs.back().rrc_member.plmn_id = plmn_identity::parse(plmn).value(); rrm_policy_cfgs.back().min_prb = (nof_cell_crbs * cfg.sched_cfg.min_prb_policy_ratio) / 100; rrm_policy_cfgs.back().max_prb = (nof_cell_crbs * cfg.sched_cfg.max_prb_policy_ratio) / 100; + rrm_policy_cfgs.back().policy_sched_cfg = cfg.sched_cfg.slice_policy_sched_cfg; } } return rrm_policy_cfgs; diff --git a/include/srsran/scheduler/config/slice_rrm_policy_config.h b/include/srsran/scheduler/config/slice_rrm_policy_config.h index e326a157c7..e6d8ec7080 100644 --- a/include/srsran/scheduler/config/slice_rrm_policy_config.h +++ b/include/srsran/scheduler/config/slice_rrm_policy_config.h @@ -10,6 +10,7 @@ #pragma once +#include "scheduler_expert_config.h" #include "srsran/ran/rrm.h" #include "srsran/ran/s_nssai.h" @@ -23,6 +24,8 @@ struct slice_rrm_policy_config { unsigned min_prb = 0; /// Sets the maximum number of PRBs to be allocated to this group. unsigned max_prb = MAX_NOF_PRBS; + /// Policy scheduler configuration for the slice. + policy_scheduler_expert_config policy_sched_cfg = time_rr_scheduler_expert_config{}; }; } // namespace srsran diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 9ddfbe7697..1e63c0366c 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -35,7 +35,10 @@ slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, const ue_r // Configured RRM policy members. for (const slice_rrm_policy_config& rrm : cell_cfg.rrm_policy_members) { slices.emplace_back(id_count, cell_cfg, rrm); - slices.back().policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); + // Set policy scheduler based on slice configuration. + scheduler_ue_expert_config slice_scheduler_ue_expert_cfg{cell_cfg.expert_cfg.ue}; + slice_scheduler_ue_expert_cfg.strategy_cfg = rrm.policy_sched_cfg; + slices.back().policy = create_scheduler_strategy(slice_scheduler_ue_expert_cfg); ++id_count; } } From 1fa59b24847c80a9cab3be0ce7d6a3fb8d45417e Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 19 Aug 2024 14:32:43 +0200 Subject: [PATCH 289/407] sched: fix condition for checking valid UE PDSCH alloc param candidate or not --- .../ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h b/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h index 2250c25d49..925a32a5cf 100644 --- a/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h +++ b/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h @@ -223,7 +223,7 @@ class ue_pdsch_alloc_param_candidate_searcher } // Check whether PDSCH Time Domain resource index is valid. - if (current.time_res >= (*current.ss_it)->pusch_time_domain_list.size()) { + if (current.time_res >= (*current.ss_it)->pdsch_time_domain_list.size()) { return false; } From b6a37b545834a37882f82dc1c59ffa0d386d1c2a Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 19 Aug 2024 13:41:21 +0200 Subject: [PATCH 290/407] apps: cosmetic change on application banner --- apps/services/application_message_banners.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/services/application_message_banners.h b/apps/services/application_message_banners.h index 2619030717..b7aff0b2b1 100644 --- a/apps/services/application_message_banners.h +++ b/apps/services/application_message_banners.h @@ -42,7 +42,7 @@ class application_message_banners static void log_build_info(srslog::basic_logger& logger) { // Log build info - logger.info("Built in {} mode using {})", get_build_mode(), get_build_info()); + logger.info("Built in {} mode using {}", get_build_mode(), get_build_info()); } }; From 65972332f2edf481e24d620cc4b76b73d3aef626 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 19 Aug 2024 11:07:41 +0200 Subject: [PATCH 291/407] gtpu,du: configurable GTP-U log level in DU --- apps/units/flexible_du/du_high/du_high_config.h | 1 + .../units/flexible_du/du_high/du_high_config_cli11_schema.cpp | 1 + apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp | 1 + apps/units/flexible_du/du_high/du_high_logger_registrator.h | 4 ++++ 4 files changed, 7 insertions(+) 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 ae852b7821..48821dfbbd 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -46,6 +46,7 @@ struct du_high_unit_logger_config { srslog::basic_levels rlc_level = srslog::basic_levels::warning; srslog::basic_levels f1ap_level = srslog::basic_levels::warning; srslog::basic_levels f1u_level = srslog::basic_levels::warning; + srslog::basic_levels gtpu_level = srslog::basic_levels::warning; srslog::basic_levels metrics_level = srslog::basic_levels::none; /// Maximum number of bytes to write when dumping hex arrays. 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 3160cb23f6..52eb637db3 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 @@ -60,6 +60,7 @@ static void configure_cli11_log_args(CLI::App& app, du_high_unit_logger_config& app_services::add_log_option(app, log_params.rlc_level, "--rlc_level", "RLC log level"); app_services::add_log_option(app, log_params.f1ap_level, "--f1ap_level", "F1AP log level"); app_services::add_log_option(app, log_params.f1u_level, "--f1u_level", "F1-U log level"); + app_services::add_log_option(app, log_params.gtpu_level, "--gtpu_level", "GTPU log level"); app_services::add_log_option(app, log_params.du_level, "--du_level", "Log level for the DU"); auto metric_level_check = [](const std::string& value) -> std::string { diff --git a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp index 7b71c8c328..5d359abca0 100644 --- a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp @@ -44,6 +44,7 @@ static void fill_du_high_log_section(YAML::Node node, const du_high_unit_logger_ node["rlc_level"] = srslog::basic_level_to_string(config.rlc_level); node["f1ap_level"] = srslog::basic_level_to_string(config.f1ap_level); node["f1u_level"] = srslog::basic_level_to_string(config.f1u_level); + node["gtpu_level"] = srslog::basic_level_to_string(config.gtpu_level); node["du_level"] = srslog::basic_level_to_string(config.du_level); node["hex_max_size"] = config.hex_max_size; node["broadcast_enabled"] = config.broadcast_enabled; diff --git a/apps/units/flexible_du/du_high/du_high_logger_registrator.h b/apps/units/flexible_du/du_high/du_high_logger_registrator.h index 4b026a6b34..7d31542697 100644 --- a/apps/units/flexible_du/du_high/du_high_logger_registrator.h +++ b/apps/units/flexible_du/du_high/du_high_logger_registrator.h @@ -40,6 +40,10 @@ inline void register_du_high_loggers(const du_high_unit_logger_config& log_cfg) auto& f1u_logger = srslog::fetch_basic_logger("DU-F1-U", false); f1u_logger.set_level(log_cfg.f1u_level); f1u_logger.set_hex_dump_max_size(log_cfg.hex_max_size); + + auto& gtpu_logger = srslog::fetch_basic_logger("GTPU", false); + gtpu_logger.set_level(log_cfg.gtpu_level); + gtpu_logger.set_hex_dump_max_size(log_cfg.hex_max_size); } } // namespace srsran From 972e2a434404653af41abf317bf55f0c4e353656 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 13 Aug 2024 16:34:31 +0200 Subject: [PATCH 292/407] f1ap-du: forward UE capabilities to DU manager during UE context modification --- include/srsran/f1ap/du/f1ap_du_ue_context_update.h | 2 ++ .../ran_resource_management/du_ran_resource_manager.h | 2 +- .../procedures/f1ap_du_ue_context_modification_procedure.cpp | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h index c6d817fecb..ac877004ab 100644 --- a/include/srsran/f1ap/du/f1ap_du_ue_context_update.h +++ b/include/srsran/f1ap/du/f1ap_du_ue_context_update.h @@ -64,6 +64,8 @@ struct f1ap_ue_context_update_request { /// \brief If a source cell group config is included, the gnb-DU shall generate a cell group configuration using /// full configuration. Otherwise, delta configuration is allowed, as per TS 38.473, 8.3.1.2. byte_buffer source_cell_group_cfg; + /// Container with the UE-CapabilityRAT-ContainerList, as per TS 38.331. + byte_buffer ue_cap_rat_list; }; /// \brief Response from DU manager to DU F1AP with the result of the UE context update. diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h index a4e19c4ab7..75e7fae87e 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager.h @@ -18,7 +18,7 @@ namespace srs_du { /// \brief Outcome report of an DU UE Resource allocation request. struct du_ue_resource_update_response { - /// \brief Defines whether the UE release is required due to an error during the update procedure. + /// \brief Defines whether the UE resource allocation failed during the config update procedure. /// If \c procedure_error doesn't contain any error string, then the UE resource update was successful. error_type procedure_error = {}; std::vector failed_drbs; diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index c0a880f63f..d63c0c61b5 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -86,6 +86,11 @@ void f1ap_du_ue_context_modification_procedure::create_du_request(const asn1::f1 for (const auto& drb : msg->drbs_to_be_released_list) { du_request.drbs_to_rem.push_back(get_drb_id(drb.value().drbs_to_be_released_item())); } + + if (msg->cu_to_du_rrc_info_present) { + // >> Pass UE capabilities. + du_request.ue_cap_rat_list = msg->cu_to_du_rrc_info.ue_cap_rat_container_list.copy(); + } } void f1ap_du_ue_context_modification_procedure::send_ue_context_modification_response() From ec0c42dc8f4139e1356e8e3e992c07bb80968a76 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 14 Aug 2024 10:57:39 +0200 Subject: [PATCH 293/407] du_manager: implementation of handler of UE NR capabilities --- .../ran_resource_management/CMakeLists.txt | 3 +- .../du_ran_resource_manager_impl.cpp | 6 +- .../du_ran_resource_manager_impl.h | 4 + .../ue_capability_manager.cpp | 115 ++++++++++++++++++ .../ue_capability_manager.h | 45 +++++++ 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 lib/du_manager/ran_resource_management/ue_capability_manager.cpp create mode 100644 lib/du_manager/ran_resource_management/ue_capability_manager.h diff --git a/lib/du_manager/ran_resource_management/CMakeLists.txt b/lib/du_manager/ran_resource_management/CMakeLists.txt index ff62eaf469..2924c2760c 100644 --- a/lib/du_manager/ran_resource_management/CMakeLists.txt +++ b/lib/du_manager/ran_resource_management/CMakeLists.txt @@ -10,5 +10,6 @@ add_library(du_resource_manager du_ran_resource_manager_impl.cpp du_pucch_resource_manager.cpp du_bearer_resource_manager.cpp - pucch_resource_generator.cpp) + pucch_resource_generator.cpp + ue_capability_manager.cpp) target_link_libraries(du_resource_manager du_manager_converters srsran_du_config_validators mac_configuration_helpers) diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index f0372ac0f0..ce8c4364df 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -45,7 +45,8 @@ du_ran_resource_manager_impl::du_ran_resource_manager_impl(span +srsran::srs_du::decode_ue_nr_cap_container(const byte_buffer& ue_cap_container) +{ + asn1::rrc_nr::ue_nr_cap_s ue_cap; + { + asn1::cbit_ref bref{ue_cap_container}; + if (ue_cap.unpack(bref) != asn1::SRSASN_SUCCESS) { + return make_unexpected(std::string("Couldn't unpack UE NR Capability RRC container")); + } + } + + ue_capability_summary ue_caps; + + // fill UE capability summary. + if (ue_cap.phy_params.phy_params_fr1_present) { + ue_caps.pdsch_qam256_supported = ue_cap.phy_params.phy_params_fr1.pdsch_256_qam_fr1_present; + } + for (const auto& band : ue_cap.rf_params.supported_band_list_nr) { + // TODO: save per-band capabilities. + ue_caps.pusch_qam256_supported |= band.pusch_256_qam_present; + } + + return ue_caps; +} + +ue_capability_manager::ue_capability_manager(const scheduler_expert_config& scheduler_cfg_, + srslog::basic_logger& logger_) : + scheduler_cfg(scheduler_cfg_), logger(logger_) +{ + (void)scheduler_cfg; +} + +void ue_capability_manager::update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list) +{ + if (not decode_ue_capability_list(ue_cap_rat_list)) { + // No updates. + return; + } + if (not ue_caps.has_value()) { + // No UE capabilities decoded. + return; + } + + serving_cell_config& pcell_cfg = ue_res_cfg.cell_group.cells[0].serv_cell_cfg; + + // Enable 256QAM for PDSCH, if supported. + if (ue_caps->pdsch_qam256_supported) { + // Set MCS index table 2 for PDSCH. See TS 38.214, Table 5.1.3.1-2. + if (pcell_cfg.init_dl_bwp.pdsch_cfg.has_value()) { + pcell_cfg.init_dl_bwp.pdsch_cfg->mcs_table = pdsch_mcs_table::qam256; + } + + if (pcell_cfg.csi_meas_cfg.has_value()) { + for (auto& csi_report_cfg : pcell_cfg.csi_meas_cfg.value().csi_report_cfg_list) { + if (ue_caps->pdsch_qam256_supported) { + // Enable CQI table 2. See TS 38.214, Table 5.2.2.1-3. + csi_report_cfg.cqi_table = cqi_table_t::table2; + } + } + } + } + + // Enable 256QAM for PUSCH, if supported. + if (ue_caps->pusch_qam256_supported) { + if (pcell_cfg.ul_config.has_value() and pcell_cfg.ul_config->init_ul_bwp.pusch_cfg.has_value()) { + pcell_cfg.ul_config->init_ul_bwp.pusch_cfg->mcs_table = pusch_mcs_table::qam256; + } + } +} + +bool ue_capability_manager::decode_ue_capability_list(const byte_buffer& ue_cap_rat_list) +{ + using namespace asn1::rrc_nr; + + ue_cap_rat_container_list_l asn1_cap_list; + { + asn1::cbit_ref bref{ue_cap_rat_list}; + if (asn1::unpack_dyn_seq_of(asn1_cap_list, bref, 0, 8) != asn1::SRSASN_SUCCESS) { + logger.error("Couldn't unpack UE Capability RAT Container List RRC container"); + return false; + } + } + + for (const ue_cap_rat_container_s& ue_cap_rat : asn1_cap_list) { + if (ue_cap_rat.rat_type.value != rat_type_opts::nr) { + logger.warning("Unsupported RAT type in UE Capability RAT Container List RRC container"); + continue; + } + expected asn1_cap = decode_ue_nr_cap_container(ue_cap_rat.ue_cap_rat_container); + if (not asn1_cap.has_value()) { + logger.warning("{}", asn1_cap.error()); + continue; + } + ue_caps = asn1_cap.value(); + return true; + } + + return false; +} diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.h b/lib/du_manager/ran_resource_management/ue_capability_manager.h new file mode 100644 index 0000000000..70f31b85cd --- /dev/null +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.h @@ -0,0 +1,45 @@ +/* + * + * 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 "du_ue_resource_config.h" + +namespace srsran { + +struct scheduler_expert_config; + +namespace srs_du { + +struct ue_capability_summary { + bool pdsch_qam256_supported = false; + bool pusch_qam256_supported = false; +}; + +expected decode_ue_nr_cap_container(const byte_buffer& ue_cap_container); + +class ue_capability_manager +{ +public: + explicit ue_capability_manager(const scheduler_expert_config& scheduler_cfg, srslog::basic_logger& logger_); + + void update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list); + +private: + bool decode_ue_capability_list(const byte_buffer& ue_cap_rat_list); + + const scheduler_expert_config& scheduler_cfg; + srslog::basic_logger& logger; + + std::optional ue_caps; +}; + +} // namespace srs_du +} // namespace srsran \ No newline at end of file From f98bddaa5340ead3e5dddf29c2551d52dfa81515 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 14 Aug 2024 13:40:10 +0200 Subject: [PATCH 294/407] du-high: refactor du_high_config --- .../du_high/du_high_wrapper_config_helper.cpp | 30 ++++----- .../srsran/du_high/du_high_configuration.h | 42 +++++++------ lib/du/du_high_wrapper_factory.cpp | 6 +- lib/du/du_wrapper_factory.cpp | 2 +- lib/du_high/du_high_impl.cpp | 10 +-- .../benchmarks/du_high/du_high_benchmark.cpp | 63 +++++++++---------- .../du_high/du_high_many_cells_test.cpp | 10 +-- .../integrationtests/du_high/paging_test.cpp | 4 +- .../test_utils/du_high_env_simulator.cpp | 39 ++++++------ .../du_high_cu/cu_du_test.cpp | 16 ++--- .../du_high_cu/du_high_cu_test_simulator.cpp | 27 ++++---- 11 files changed, 124 insertions(+), 125 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp index 5427f26e22..e496477a1e 100644 --- a/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp +++ b/apps/units/flexible_du/du_high/du_high_wrapper_config_helper.cpp @@ -145,22 +145,22 @@ srsran::fill_du_high_wrapper_config(du_high_wrapper_config& out_cfg, { // DU-high configuration. srs_du::du_high_configuration& du_hi_cfg = out_cfg.du_hi; - du_hi_cfg.cells = generate_du_cell_config(du_high_unit_cfg); - du_hi_cfg.exec_mapper = &execution_mapper; - du_hi_cfg.f1c_client = &f1c_client_handler; - du_hi_cfg.f1u_gw = &f1u_gw; - du_hi_cfg.phy_adapter = nullptr; - du_hi_cfg.timers = &timer_mng; - du_hi_cfg.srbs = generate_du_srb_config(du_high_unit_cfg); - du_hi_cfg.qos = generate_du_qos_config(du_high_unit_cfg); - du_hi_cfg.mac_p = &mac_p; - du_hi_cfg.rlc_p = &rlc_p; - du_hi_cfg.gnb_du_id = static_cast((static_cast(du_high_unit_cfg.gnb_du_id) + du_idx)); - du_hi_cfg.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.gnb_du_id); - du_hi_cfg.mac_cfg = generate_mac_expert_config(du_high_unit_cfg); + du_hi_cfg.ran.gnb_du_id = static_cast((static_cast(du_high_unit_cfg.gnb_du_id) + du_idx)); + du_hi_cfg.ran.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.ran.gnb_du_id); + du_hi_cfg.ran.cells = generate_du_cell_config(du_high_unit_cfg); + du_hi_cfg.ran.srbs = generate_du_srb_config(du_high_unit_cfg); + du_hi_cfg.ran.qos = generate_du_qos_config(du_high_unit_cfg); + du_hi_cfg.ran.mac_cfg = generate_mac_expert_config(du_high_unit_cfg); // Assign different initial C-RNTIs to different DUs. - du_hi_cfg.mac_cfg.initial_crnti = to_rnti(0x4601 + (0x1000 * du_idx)); - du_hi_cfg.sched_cfg = generate_scheduler_expert_config(du_high_unit_cfg); + du_hi_cfg.ran.mac_cfg.initial_crnti = to_rnti(0x4601 + (0x1000 * du_idx)); + du_hi_cfg.ran.sched_cfg = generate_scheduler_expert_config(du_high_unit_cfg); + du_hi_cfg.exec_mapper = &execution_mapper; + du_hi_cfg.f1c_client = &f1c_client_handler; + du_hi_cfg.f1u_gw = &f1u_gw; + du_hi_cfg.phy_adapter = nullptr; + du_hi_cfg.timers = &timer_mng; + du_hi_cfg.mac_p = &mac_p; + du_hi_cfg.rlc_p = &rlc_p; if (du_high_unit_cfg.e2_cfg.enable_du_e2) { // Connect E2 agent to RLC metric source. diff --git a/include/srsran/du_high/du_high_configuration.h b/include/srsran/du_high/du_high_configuration.h index c74e15cb6f..8750f09d9d 100644 --- a/include/srsran/du_high/du_high_configuration.h +++ b/include/srsran/du_high/du_high_configuration.h @@ -29,29 +29,33 @@ namespace srs_du { class f1u_du_gateway; -/// Configuration passed to DU-High. -struct du_high_configuration { - du_high_executor_mapper* exec_mapper = nullptr; - f1c_connection_client* f1c_client = nullptr; - f1u_du_gateway* f1u_gw = nullptr; - mac_result_notifier* phy_adapter = nullptr; - timer_manager* timers = nullptr; - scheduler_metrics_notifier* sched_ue_metrics_notifier = nullptr; - rlc_metrics_notifier* rlc_metrics_notif = nullptr; - e2_connection_client* e2_client = nullptr; - e2_du_metrics_interface* e2_du_metric_iface = nullptr; - std::string gnb_du_name; - gnb_du_id_t gnb_du_id; - transport_layer_address du_bind_addr; +/// RAN-specific parameters of the DU-high. +struct du_high_ran_config { + std::string gnb_du_name = "srsdu"; + gnb_du_id_t gnb_du_id = gnb_du_id_t::min; std::vector cells; std::map srbs; - std::map qos; // 5QI as key + std::map qos; mac_expert_config mac_cfg; scheduler_expert_config sched_cfg; - mac_pcap* mac_p = nullptr; - rlc_pcap* rlc_p = nullptr; - du_test_config test_cfg; - e2ap_configuration e2ap_config; +}; + +/// Configuration passed to DU-High. +struct du_high_configuration { + du_high_ran_config ran; + du_high_executor_mapper* exec_mapper = nullptr; + f1c_connection_client* f1c_client = nullptr; + f1u_du_gateway* f1u_gw = nullptr; + mac_result_notifier* phy_adapter = nullptr; + timer_manager* timers = nullptr; + scheduler_metrics_notifier* sched_ue_metrics_notifier = nullptr; + rlc_metrics_notifier* rlc_metrics_notif = nullptr; + e2_connection_client* e2_client = nullptr; + e2_du_metrics_interface* e2_du_metric_iface = nullptr; + mac_pcap* mac_p = nullptr; + rlc_pcap* rlc_p = nullptr; + du_test_config test_cfg; + e2ap_configuration e2ap_config; }; } // namespace srs_du diff --git a/lib/du/du_high_wrapper_factory.cpp b/lib/du/du_high_wrapper_factory.cpp index 4dbd1c56ac..7b6a3dc4e1 100644 --- a/lib/du/du_high_wrapper_factory.cpp +++ b/lib/du/du_high_wrapper_factory.cpp @@ -43,16 +43,16 @@ build_fapi_adaptors(const du_cell_config& du_cell, du_high_wrapper_sector_depend std::unique_ptr srsran::make_du_high_wrapper(const du_high_wrapper_config& config, du_high_wrapper_dependencies&& wrapper_dependencies) { - srsran_assert(config.du_hi.cells.size() == wrapper_dependencies.sectors.size(), + srsran_assert(config.du_hi.ran.cells.size() == wrapper_dependencies.sectors.size(), "DU high number of cells '{}' does not match number sectors '{}' in wrapper dependencies", - config.du_hi.cells.size(), + config.du_hi.ran.cells.size(), wrapper_dependencies.sectors.size()); du_high_wrapper_impl_dependencies dependencies; for (unsigned i = 0, e = wrapper_dependencies.sectors.size(); i != e; ++i) { dependencies.du_high_adaptor.push_back( - build_fapi_adaptors(config.du_hi.cells[i], wrapper_dependencies.sectors[i], i)); + build_fapi_adaptors(config.du_hi.ran.cells[i], wrapper_dependencies.sectors[i], i)); } auto& logger = srslog::fetch_basic_logger("DU"); diff --git a/lib/du/du_wrapper_factory.cpp b/lib/du/du_wrapper_factory.cpp index 7c2458cf53..78dc8efc54 100644 --- a/lib/du/du_wrapper_factory.cpp +++ b/lib/du/du_wrapper_factory.cpp @@ -20,7 +20,7 @@ std::unique_ptr srsran::make_du_wrapper(const du_wrapper_config& du_ du_wrapper_impl_dependencies dependencies; // Create DU low. - dependencies.du_lo = make_du_low_wrapper(du_cfg.du_low_cfg, du_cfg.du_high_cfg.du_hi.cells); + dependencies.du_lo = make_du_low_wrapper(du_cfg.du_low_cfg, du_cfg.du_high_cfg.du_hi.ran.cells); // Create DU high wrapper. du_high_wrapper_dependencies high_wrapper_dependencies; diff --git a/lib/du_high/du_high_impl.cpp b/lib/du_high/du_high_impl.cpp index 0cf40b6d4d..2a3194a53e 100644 --- a/lib/du_high/du_high_impl.cpp +++ b/lib/du_high/du_high_impl.cpp @@ -111,9 +111,9 @@ du_high_impl::du_high_impl(const du_high_configuration& config_) : cfg.exec_mapper->cell_mapper(), cfg.exec_mapper->du_control_executor(), *cfg.phy_adapter, - cfg.mac_cfg, + cfg.ran.mac_cfg, *cfg.mac_p, - cfg.sched_cfg, + cfg.ran.sched_cfg, cfg.sched_ue_metrics_notifier ? *cfg.sched_ue_metrics_notifier : *metrics_notifier}, cfg.test_cfg); f1ap = create_du_high_f1ap(*cfg.f1c_client, @@ -123,17 +123,17 @@ du_high_impl::du_high_impl(const du_high_configuration& config_) : adapters->f1ap_paging_notifier, cfg.test_cfg); - expected f1u_bind_string = config_.f1u_gw->get_du_bind_address(cfg.gnb_du_id); + expected f1u_bind_string = config_.f1u_gw->get_du_bind_address(cfg.ran.gnb_du_id); assert(f1u_bind_string.has_value()); transport_layer_address f1u_bind_addr = transport_layer_address::create_from_string(f1u_bind_string.value()); du_manager = create_du_manager(du_manager_params{ - {cfg.gnb_du_name, cfg.gnb_du_id, 1, f1u_bind_addr, cfg.cells, cfg.srbs, cfg.qos}, + {cfg.ran.gnb_du_name, cfg.ran.gnb_du_id, 1, f1u_bind_addr, cfg.ran.cells, cfg.ran.srbs, cfg.ran.qos}, {timers, cfg.exec_mapper->du_control_executor(), cfg.exec_mapper->ue_mapper(), cfg.exec_mapper->cell_mapper()}, {*f1ap, *f1ap}, {*config_.f1u_gw}, {mac->get_ue_control_info_handler(), *f1ap, *f1ap, *cfg.rlc_p, cfg.rlc_metrics_notif}, - {mac->get_cell_manager(), mac->get_ue_configurator(), cfg.sched_cfg}}); + {mac->get_cell_manager(), mac->get_ue_configurator(), cfg.ran.sched_cfg}}); // Connect Layer<->DU manager adapters. adapters->connect(*du_manager, *mac); diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index e273f6a8fc..f2fe6dc3e8 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -609,36 +609,35 @@ class du_high_bench report_fatal_error_if_not(bsr_mac_subpdu.append(lbsr_buff_sz), "Failed to allocate PDU"); // Instantiate a DU-high object. - cfg.gnb_du_id = (gnb_du_id_t)1; - cfg.gnb_du_name = fmt::format("srsgnb{}", cfg.gnb_du_id); - cfg.du_bind_addr = transport_layer_address::create_from_string(fmt::format("127.0.0.{}", cfg.gnb_du_id)); - cfg.exec_mapper = &workers.du_high_exec_mapper; - cfg.f1c_client = &sim_cu_cp; - cfg.f1u_gw = &sim_cu_up; - cfg.phy_adapter = &sim_phy; - cfg.timers = &timers; - cfg.cells = {config_helpers::make_default_du_cell_config(params)}; - cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); - cfg.sched_cfg.ue.strategy_cfg = strategy_cfg; - cfg.sched_cfg.ue.pdsch_nof_rbs = {1, max_nof_rbs_per_dl_grant}; - cfg.mac_cfg = mac_expert_config{.configs = {{10000, 10000, 10000}}}; - cfg.qos = config_helpers::make_default_du_qos_config_list(/* warn_on_drop */ true, 1000); - cfg.mac_p = &mac_pcap; - cfg.rlc_p = &rlc_pcap; - cfg.sched_ue_metrics_notifier = &metrics_handler; + cfg.ran.gnb_du_id = (gnb_du_id_t)1; + cfg.ran.gnb_du_name = fmt::format("srsgnb{}", cfg.ran.gnb_du_id); + cfg.exec_mapper = &workers.du_high_exec_mapper; + cfg.f1c_client = &sim_cu_cp; + cfg.f1u_gw = &sim_cu_up; + cfg.phy_adapter = &sim_phy; + cfg.timers = &timers; + cfg.ran.cells = {config_helpers::make_default_du_cell_config(params)}; + cfg.ran.sched_cfg = config_helpers::make_default_scheduler_expert_config(); + cfg.ran.sched_cfg.ue.strategy_cfg = strategy_cfg; + cfg.ran.sched_cfg.ue.pdsch_nof_rbs = {1, max_nof_rbs_per_dl_grant}; + cfg.ran.mac_cfg = mac_expert_config{.configs = {{10000, 10000, 10000}}}; + cfg.ran.qos = config_helpers::make_default_du_qos_config_list(/* warn_on_drop */ true, 1000); + cfg.mac_p = &mac_pcap; + cfg.rlc_p = &rlc_pcap; + cfg.sched_ue_metrics_notifier = &metrics_handler; // Increase nof. PUCCH resources to accommodate more UEs. - cfg.cells[0].pucch_cfg.nof_sr_resources = 30; - cfg.cells[0].pucch_cfg.nof_csi_resources = 30; - cfg.cells[0].pucch_cfg.nof_ue_pucch_f2_res_harq = 8; - cfg.cells[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 8; - cfg.cells[0].pucch_cfg.nof_cell_harq_pucch_res_sets = 4; - auto& f1_params = cfg.cells[0].pucch_cfg.f0_or_f1_params.emplace(); - f1_params.nof_cyc_shifts = srsran::nof_cyclic_shifts::six; - f1_params.occ_supported = true; - cfg.sched_cfg.ue.max_pucchs_per_slot = 61; - cfg.sched_cfg.ue.max_puschs_per_slot = 61; - cfg.sched_cfg.ue.max_ul_grants_per_slot = 64; + cfg.ran.cells[0].pucch_cfg.nof_sr_resources = 30; + cfg.ran.cells[0].pucch_cfg.nof_csi_resources = 30; + cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f2_res_harq = 8; + cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 8; + cfg.ran.cells[0].pucch_cfg.nof_cell_harq_pucch_res_sets = 4; + auto& f1_params = cfg.ran.cells[0].pucch_cfg.f0_or_f1_params.emplace(); + f1_params.nof_cyc_shifts = srsran::nof_cyclic_shifts::six; + f1_params.occ_supported = true; + cfg.ran.sched_cfg.ue.max_pucchs_per_slot = 61; + cfg.ran.sched_cfg.ue.max_puschs_per_slot = 61; + cfg.ran.sched_cfg.ue.max_ul_grants_per_slot = 64; du_hi = std::make_unique(cfg); @@ -755,8 +754,8 @@ class du_high_bench // Wait until it's a full UL slot to send Msg3. auto next_ul_slot = [this]() { - return not cfg.cells[to_du_cell_index(0)].tdd_ul_dl_cfg_common.has_value() or - not is_tdd_full_ul_slot(cfg.cells[to_du_cell_index(0)].tdd_ul_dl_cfg_common.value(), + return not cfg.ran.cells[to_du_cell_index(0)].tdd_ul_dl_cfg_common.has_value() or + not is_tdd_full_ul_slot(cfg.ran.cells[to_du_cell_index(0)].tdd_ul_dl_cfg_common.value(), slot_point(next_sl_tx - tx_rx_delay - 1).slot_index()); }; report_fatal_error_if_not(run_slot_until(next_ul_slot), "No slot for Msg3 was detected"); @@ -1212,10 +1211,10 @@ void benchmark_dl_ul_only_rlc_um(benchmarker& bm, bench.sim_phy.metrics.slot_count, bench.sim_phy.metrics.nof_dl_grants, bench.sim_phy.metrics.nof_dl_grants / (double)bench.sim_phy.metrics.slot_dl_count, - bench.sim_phy.metrics.dl_mbps(bench.cfg.cells[0].scs_common), + bench.sim_phy.metrics.dl_mbps(bench.cfg.ran.cells[0].scs_common), bench.sim_phy.metrics.nof_ul_grants, bench.sim_phy.metrics.nof_ul_grants / (double)bench.sim_phy.metrics.slot_ul_count, - bench.sim_phy.metrics.ul_mbps(bench.cfg.cells[0].scs_common)); + bench.sim_phy.metrics.ul_mbps(bench.cfg.ran.cells[0].scs_common)); } /// \brief Configure main thread priority and affinity to avoid interference from other processes (including stressors). diff --git a/tests/integrationtests/du_high/du_high_many_cells_test.cpp b/tests/integrationtests/du_high/du_high_many_cells_test.cpp index dfd3e96d8c..faac9bf8fe 100644 --- a/tests/integrationtests/du_high/du_high_many_cells_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_cells_test.cpp @@ -90,7 +90,7 @@ TEST_P(du_high_many_cells_tester, // Ensure the F1AP Initial UL RRC message is correct. ASSERT_EQ(cu_notifier.last_f1ap_msgs.size(), 1); ASSERT_TRUE(test_helpers::is_init_ul_rrc_msg_transfer_valid( - cu_notifier.last_f1ap_msgs.back(), rnti, du_high_cfg.cells[i].nr_cgi)); + cu_notifier.last_f1ap_msgs.back(), rnti, du_high_cfg.ran.cells[i].nr_cgi)); } } @@ -129,7 +129,7 @@ TEST_P(du_high_many_cells_tester, when_ue_created_in_multiple_cells_then_traffic // condition to stop experiment. auto stop_condition = [this, &bytes_sched_per_cell]() { - for (unsigned c = 0; c != du_high_cfg.cells.size(); ++c) { + for (unsigned c = 0; c != du_high_cfg.ran.cells.size(); ++c) { if (bytes_sched_per_cell[c] < nof_pdcp_pdus * pdcp_pdu_size) { // one of the cells still didn't send all the pending traffic. return false; @@ -139,7 +139,7 @@ TEST_P(du_high_many_cells_tester, when_ue_created_in_multiple_cells_then_traffic }; // check if a PDSCH was scheduled. auto pdsch_grant_scheduled = [this]() { - for (unsigned i = 0; i != du_high_cfg.cells.size(); ++i) { + for (unsigned i = 0; i != du_high_cfg.ran.cells.size(); ++i) { if (phy.cells[i].last_dl_data.has_value() and not phy.cells[i].last_dl_data.value().ue_pdus.empty()) { return true; } @@ -149,7 +149,7 @@ TEST_P(du_high_many_cells_tester, when_ue_created_in_multiple_cells_then_traffic std::vector largest_pdu_per_cell(GetParam().nof_cells, 0); while (not stop_condition() and this->run_until([pdsch_grant_scheduled]() { return pdsch_grant_scheduled(); })) { - for (unsigned c = 0; c != du_high_cfg.cells.size(); ++c) { + for (unsigned c = 0; c != du_high_cfg.ran.cells.size(); ++c) { auto& phy_cell = phy.cells[c]; if (not phy_cell.last_dl_data.has_value()) { continue; @@ -177,7 +177,7 @@ TEST_P(du_high_many_cells_tester, when_ue_created_in_multiple_cells_then_traffic ASSERT_TRUE(stop_condition()) << "Experiment did not finish when all cells transmitted pending traffic"; // Cells should schedule equally large MAC PDUs - for (unsigned c = 1; c != du_high_cfg.cells.size(); ++c) { + for (unsigned c = 1; c != du_high_cfg.ran.cells.size(); ++c) { ASSERT_EQ(largest_pdu_per_cell[c], largest_pdu_per_cell[0]) << fmt::format("cells {} and {} cannot schedule equally large PDUs", 0, c); } diff --git a/tests/integrationtests/du_high/paging_test.cpp b/tests/integrationtests/du_high/paging_test.cpp index 241f620d2b..4b390036c2 100644 --- a/tests/integrationtests/du_high/paging_test.cpp +++ b/tests/integrationtests/du_high/paging_test.cpp @@ -60,8 +60,8 @@ TEST_F(paging_tester, when_paging_message_is_received_its_relayed_to_ue) // Receive F1AP paging message. cu_notifier.last_f1ap_msgs.clear(); - ASSERT_TRUE(not this->du_high_cfg.cells.empty()); - const auto du_cell_cfg = this->du_high_cfg.cells[0]; + ASSERT_TRUE(not this->du_high_cfg.ran.cells.empty()); + const auto du_cell_cfg = this->du_high_cfg.ran.cells[0]; this->du_hi->get_f1ap_message_handler().handle_message(generate_paging_message(five_g_tmsi, du_cell_cfg.nr_cgi)); // Flag indicating whether UE is Paged or not. bool ue_is_paged{false}; diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index c5ab17d670..036f668d63 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -156,32 +156,29 @@ du_high_env_simulator::du_high_env_simulator(du_high_env_sim_params params) : init_loggers(); du_high_configuration cfg{}; - cfg.exec_mapper = &workers.exec_mapper; - cfg.f1c_client = &cu_notifier; - cfg.f1u_gw = &cu_up_sim; - cfg.phy_adapter = &phy; - cfg.timers = &timers; - cfg.gnb_du_id = gnb_du_id_t::min; - cfg.gnb_du_name = "srsdu"; - cfg.du_bind_addr = transport_layer_address::create_from_string("127.0.0.1"); - cfg.sched_cfg.log_broadcast_messages = false; - - cfg.cells.reserve(params.nof_cells); + cfg.exec_mapper = &workers.exec_mapper; + cfg.f1c_client = &cu_notifier; + cfg.f1u_gw = &cu_up_sim; + cfg.phy_adapter = &phy; + cfg.timers = &timers; + cfg.ran.sched_cfg.log_broadcast_messages = false; + + cfg.ran.cells.reserve(params.nof_cells); cell_config_builder_params builder_params; for (unsigned i = 0; i < params.nof_cells; ++i) { builder_params.pci = (pci_t)i; - cfg.cells.push_back(config_helpers::make_default_du_cell_config(builder_params)); - cfg.cells.back().nr_cgi.nci = nr_cell_identity::create(i).value(); + cfg.ran.cells.push_back(config_helpers::make_default_du_cell_config(builder_params)); + cfg.ran.cells.back().nr_cgi.nci = nr_cell_identity::create(i).value(); if (params.pucch_cfg.has_value()) { - cfg.cells.back().pucch_cfg = params.pucch_cfg.value(); + cfg.ran.cells.back().pucch_cfg = params.pucch_cfg.value(); } } - cfg.qos = config_helpers::make_default_du_qos_config_list(/* warn_on_drop */ true, 0); - cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); - cfg.mac_cfg = mac_expert_config{.configs = {{10000, 10000, 10000}}}; - cfg.mac_p = &mac_pcap; - cfg.rlc_p = &rlc_pcap; + cfg.ran.qos = config_helpers::make_default_du_qos_config_list(/* warn_on_drop */ true, 0); + cfg.ran.sched_cfg = config_helpers::make_default_scheduler_expert_config(); + cfg.ran.mac_cfg = mac_expert_config{.configs = {{10000, 10000, 10000}}}; + cfg.mac_p = &mac_pcap; + cfg.rlc_p = &rlc_pcap; return cfg; }()), @@ -515,13 +512,13 @@ bool du_high_env_simulator::run_ue_context_release(rnti_t rnti, srb_id_t srb_id) void du_high_env_simulator::run_slot() { // Dispatch a slot indication to all cells in the L2 (fork work across cells). - for (unsigned i = 0; i != du_high_cfg.cells.size(); ++i) { + for (unsigned i = 0; i != du_high_cfg.ran.cells.size(); ++i) { du_hi->get_slot_handler(to_du_cell_index(i)).handle_slot_indication(next_slot); } // Wait for slot indication to be processed and the l2 results to be sent back to the l1 (join cell results, in this // case, with the join point being the test main thread). - for (unsigned i = 0; i != du_high_cfg.cells.size(); ++i) { + for (unsigned i = 0; i != du_high_cfg.ran.cells.size(); ++i) { const unsigned MAX_COUNT = 100000; for (unsigned count = 0; count < MAX_COUNT and phy.cells[i].last_slot_res != next_slot; ++count) { // Process tasks dispatched to the test main thread (e.g. L2 slot result) diff --git a/tests/integrationtests/du_high_cu/cu_du_test.cpp b/tests/integrationtests/du_high_cu/cu_du_test.cpp index aab94fc751..af9a2ac004 100644 --- a/tests/integrationtests/du_high_cu/cu_du_test.cpp +++ b/tests/integrationtests/du_high_cu/cu_du_test.cpp @@ -69,14 +69,14 @@ class cu_du_test : public ::testing::Test phy_dummy phy; srsran::srs_du::du_high_configuration du_cfg{}; - du_cfg.exec_mapper = &workers.exec_mapper; - du_cfg.f1c_client = &f1c_gw; - du_cfg.f1u_gw = &f1u_gw; - du_cfg.phy_adapter = &phy; - du_cfg.timers = &timers; - du_cfg.cells = {config_helpers::make_default_du_cell_config()}; - du_cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); - du_cfg.gnb_du_name = "test_du"; + du_cfg.exec_mapper = &workers.exec_mapper; + du_cfg.f1c_client = &f1c_gw; + du_cfg.f1u_gw = &f1u_gw; + du_cfg.phy_adapter = &phy; + du_cfg.timers = &timers; + du_cfg.ran.cells = {config_helpers::make_default_du_cell_config()}; + du_cfg.ran.sched_cfg = config_helpers::make_default_scheduler_expert_config(); + du_cfg.ran.gnb_du_name = "test_du"; // create DU object du_obj = make_du_high(std::move(du_cfg)); diff --git a/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp b/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp index a8173735c7..4949bcb4a5 100644 --- a/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp +++ b/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp @@ -149,20 +149,19 @@ void du_high_cu_test_simulator::start_dus() // Instantiate DU-high. srs_du::du_high_configuration& du_hi_cfg = du_ctxt.du_high_cfg; - du_hi_cfg.gnb_du_name = fmt::format("srsgnb{}", du_idx + 1); - du_hi_cfg.gnb_du_id = (gnb_du_id_t)(du_idx + 1); - du_hi_cfg.du_bind_addr = transport_layer_address::create_from_string(fmt::format("127.0.0.{}", du_idx + 1)); - du_hi_cfg.exec_mapper = workers.du_hi_exec_mappers[du_idx].get(); - du_hi_cfg.f1c_client = &f1c_gw; - du_hi_cfg.f1u_gw = nullptr; - du_hi_cfg.phy_adapter = &du_ctxt.phy; - du_hi_cfg.timers = &timers; - du_hi_cfg.sched_ue_metrics_notifier = &du_ctxt.ue_metrics_notifier; - du_hi_cfg.cells = cfg.dus[du_idx]; - du_hi_cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); - du_hi_cfg.mac_p = &du_ctxt.mac_pcap; - du_hi_cfg.rlc_p = &du_ctxt.rlc_pcap; - du_ctxt.du_high_inst = make_du_high(du_hi_cfg); + du_hi_cfg.ran.gnb_du_name = fmt::format("srsgnb{}", du_idx + 1); + du_hi_cfg.ran.gnb_du_id = (gnb_du_id_t)(du_idx + 1); + du_hi_cfg.exec_mapper = workers.du_hi_exec_mappers[du_idx].get(); + du_hi_cfg.f1c_client = &f1c_gw; + du_hi_cfg.f1u_gw = nullptr; + du_hi_cfg.phy_adapter = &du_ctxt.phy; + du_hi_cfg.timers = &timers; + du_hi_cfg.sched_ue_metrics_notifier = &du_ctxt.ue_metrics_notifier; + du_hi_cfg.ran.cells = cfg.dus[du_idx]; + du_hi_cfg.ran.sched_cfg = config_helpers::make_default_scheduler_expert_config(); + du_hi_cfg.mac_p = &du_ctxt.mac_pcap; + du_hi_cfg.rlc_p = &du_ctxt.rlc_pcap; + du_ctxt.du_high_inst = make_du_high(du_hi_cfg); du_ctxt.du_high_inst->start(); } From b74b5db3a0de855bf8333dd469aebc2777a8d27e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 14 Aug 2024 14:14:09 +0200 Subject: [PATCH 295/407] du-high: remove uneeded parameter of du_manager --- include/srsran/du_manager/du_manager_params.h | 1 - include/srsran/f1u/cu_up/f1u_gateway.h | 2 +- include/srsran/f1u/du/f1u_gateway.h | 4 ++-- .../f1u/local_connector/f1u_local_connector.h | 2 +- include/srsran/gateways/udp_network_gateway.h | 4 ++-- include/srsran/gtpu/ngu_gateway.h | 4 ++-- lib/du_high/du_high_impl.cpp | 6 +----- lib/du_manager/du_ue/du_bearer.cpp | 8 ++++++-- lib/f1u/cu_up/split_connector/f1u_split_connector.h | 2 +- lib/f1u/du/split_connector/f1u_split_connector.cpp | 2 +- lib/f1u/du/split_connector/f1u_split_connector.h | 4 ++-- lib/gateways/udp_network_gateway_impl.cpp | 4 ++-- lib/gateways/udp_network_gateway_impl.h | 4 ++-- lib/gtpu/ngu_gateway.cpp | 8 ++++---- tests/benchmarks/du_high/du_high_benchmark.cpp | 2 +- tests/test_doubles/f1ap/f1c_test_local_gateway.h | 2 +- tests/test_doubles/f1u/dummy_f1u_du_gateway.h | 2 +- .../du_manager/du_manager_test_helpers.cpp | 2 +- .../unittests/du_manager/du_manager_test_helpers.h | 2 +- .../unittests/du_manager/du_ue/ue_manager_test.cpp | 13 ++++++------- tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp | 11 +++++------ 21 files changed, 43 insertions(+), 46 deletions(-) diff --git a/include/srsran/du_manager/du_manager_params.h b/include/srsran/du_manager/du_manager_params.h index 61af623efd..3d1987d761 100644 --- a/include/srsran/du_manager/du_manager_params.h +++ b/include/srsran/du_manager/du_manager_params.h @@ -35,7 +35,6 @@ struct du_manager_params { std::string gnb_du_name; gnb_du_id_t gnb_du_id; uint8_t rrc_version; - transport_layer_address du_bind_addr; std::vector cells; std::map srbs; std::map qos; diff --git a/include/srsran/f1u/cu_up/f1u_gateway.h b/include/srsran/f1u/cu_up/f1u_gateway.h index 8d5ee29cd4..a5292699eb 100644 --- a/include/srsran/f1u/cu_up/f1u_gateway.h +++ b/include/srsran/f1u/cu_up/f1u_gateway.h @@ -72,7 +72,7 @@ class f1u_cu_up_udp_gateway : public f1u_cu_up_gateway f1u_cu_up_udp_gateway(f1u_cu_up_udp_gateway&&) = default; f1u_cu_up_udp_gateway& operator=(f1u_cu_up_udp_gateway&&) = default; - virtual std::optional get_bind_port() = 0; + virtual std::optional get_bind_port() const = 0; }; } // namespace srsran diff --git a/include/srsran/f1u/du/f1u_gateway.h b/include/srsran/f1u/du/f1u_gateway.h index 6ed37f1021..05fa298edf 100644 --- a/include/srsran/f1u/du/f1u_gateway.h +++ b/include/srsran/f1u/du/f1u_gateway.h @@ -58,7 +58,7 @@ class f1u_du_gateway : public srs_du::f1u_bearer_disconnector timer_factory timers, task_executor& ue_executor) = 0; - virtual expected get_du_bind_address(gnb_du_id_t gnb_du_id) = 0; + virtual expected get_du_bind_address(gnb_du_id_t gnb_du_id) const = 0; }; /// This class will be used to provide the interfaces to @@ -73,7 +73,7 @@ class f1u_du_udp_gateway : public f1u_du_gateway f1u_du_udp_gateway(f1u_du_udp_gateway&&) = default; f1u_du_udp_gateway& operator=(f1u_du_udp_gateway&&) = default; - virtual std::optional get_bind_port() = 0; + virtual std::optional get_bind_port() const = 0; }; } // namespace srsran::srs_du diff --git a/include/srsran/f1u/local_connector/f1u_local_connector.h b/include/srsran/f1u/local_connector/f1u_local_connector.h index 57a511c6cf..b2f684688a 100644 --- a/include/srsran/f1u/local_connector/f1u_local_connector.h +++ b/include/srsran/f1u/local_connector/f1u_local_connector.h @@ -199,7 +199,7 @@ class f1u_local_connector final : public srs_du::f1u_du_gateway, public f1u_cu_u void remove_du_bearer(const up_transport_layer_info& dl_up_tnl_info) override; - expected get_du_bind_address(gnb_du_id_t gnb_du_id) override + expected get_du_bind_address(gnb_du_id_t gnb_du_id) const override { return fmt::format("127.0.0.{}", 1 + static_cast(gnb_du_id)); } diff --git a/include/srsran/gateways/udp_network_gateway.h b/include/srsran/gateways/udp_network_gateway.h index ce80d70bde..50f7a8dc32 100644 --- a/include/srsran/gateways/udp_network_gateway.h +++ b/include/srsran/gateways/udp_network_gateway.h @@ -56,13 +56,13 @@ class udp_network_gateway_controller /// /// In case the gateway was configured to bind to port 0, i.e. the operating system shall pick a random free port, /// this function can be used to get the actual port number. - virtual std::optional get_bind_port() = 0; + virtual std::optional get_bind_port() const = 0; /// \brief Return the address to which the socket is bound. /// /// In case the gateway was configured to use a hostname, /// this function can be used to get the actual IP address in string form. - virtual bool get_bind_address(std::string& ip_address) = 0; + virtual bool get_bind_address(std::string& ip_address) const = 0; /// \brief Register the UDP gateway in the IO broker for automatic handling of notifications. virtual bool subscribe_to(io_broker& broker) = 0; diff --git a/include/srsran/gtpu/ngu_gateway.h b/include/srsran/gtpu/ngu_gateway.h index 820490cee9..7642a0bd25 100644 --- a/include/srsran/gtpu/ngu_gateway.h +++ b/include/srsran/gtpu/ngu_gateway.h @@ -35,12 +35,12 @@ class ngu_tnl_pdu_session : public udp_network_gateway_data_handler, public netw /// /// In case the gateway was configured to use a hostname, /// this function can be used to get the actual IP address in string form. - virtual bool get_bind_address(std::string& ip_address) = 0; + virtual bool get_bind_address(std::string& ip_address) const = 0; /// Get bind port currently being used by the NG-U TNL session for the reception of PDUs. /// \return If a UDP link is being used, returns the respective bind port. If the connection is local, it returns /// std::nullopt. - virtual std::optional get_bind_port() = 0; + virtual std::optional get_bind_port() const = 0; }; /// \brief This class is called by the CU-UP to instantiate new NG-U TNL PDU sessions. diff --git a/lib/du_high/du_high_impl.cpp b/lib/du_high/du_high_impl.cpp index 2a3194a53e..1a531db0b3 100644 --- a/lib/du_high/du_high_impl.cpp +++ b/lib/du_high/du_high_impl.cpp @@ -123,12 +123,8 @@ du_high_impl::du_high_impl(const du_high_configuration& config_) : adapters->f1ap_paging_notifier, cfg.test_cfg); - expected f1u_bind_string = config_.f1u_gw->get_du_bind_address(cfg.ran.gnb_du_id); - assert(f1u_bind_string.has_value()); - transport_layer_address f1u_bind_addr = transport_layer_address::create_from_string(f1u_bind_string.value()); - du_manager = create_du_manager(du_manager_params{ - {cfg.ran.gnb_du_name, cfg.ran.gnb_du_id, 1, f1u_bind_addr, cfg.ran.cells, cfg.ran.srbs, cfg.ran.qos}, + {cfg.ran.gnb_du_name, cfg.ran.gnb_du_id, 1, cfg.ran.cells, cfg.ran.srbs, cfg.ran.qos}, {timers, cfg.exec_mapper->du_control_executor(), cfg.exec_mapper->ue_mapper(), cfg.exec_mapper->cell_mapper()}, {*f1ap, *f1ap}, {*config_.f1u_gw}, diff --git a/lib/du_manager/du_ue/du_bearer.cpp b/lib/du_manager/du_ue/du_bearer.cpp index a8dcc2f8ef..d41860eb10 100644 --- a/lib/du_manager/du_ue/du_bearer.cpp +++ b/lib/du_manager/du_ue/du_bearer.cpp @@ -123,6 +123,11 @@ std::unique_ptr srsran::srs_du::create_drb(const drb_creation_info& d f1u_du_gateway& f1u_gw = drb_info.du_params.f1u.f1u_gw; gtpu_teid_pool& teid_pool = drb_info.teid_pool; + // > Get DL UP TNL bind address. + expected f1u_bind_string = f1u_gw.get_du_bind_address(drb_info.du_params.ran.gnb_du_id); + assert(f1u_bind_string.has_value()); + transport_layer_address f1u_bind_addr = transport_layer_address::create_from_string(f1u_bind_string.value()); + // > Setup DL UP TNL info. expected dl_teid = teid_pool.request_teid(); if (not dl_teid.has_value()) { @@ -130,8 +135,7 @@ std::unique_ptr srsran::srs_du::create_drb(const drb_creation_info& d return nullptr; } // Note: We are computing the DL GTP-TEID as a concatenation of the UE index and DRB-id. - std::array dluptnl_info_list = { - up_transport_layer_info{drb_info.du_params.ran.du_bind_addr, dl_teid.value()}}; + std::array dluptnl_info_list = {up_transport_layer_info{f1u_bind_addr, dl_teid.value()}}; // > Create DRB instance. std::unique_ptr drb = std::make_unique(); 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 70a2521c04..1b57dce6a0 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.h +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.h @@ -108,7 +108,7 @@ class f1u_split_connector final : public f1u_cu_up_udp_gateway f1u_cu_up_gateway* get_f1u_cu_up_gateway() { return this; } - std::optional get_bind_port() override { return udp_session->get_bind_port(); } + std::optional get_bind_port() const override { return udp_session->get_bind_port(); } std::unique_ptr create_cu_bearer(uint32_t ue_index, drb_id_t drb_id, diff --git a/lib/f1u/du/split_connector/f1u_split_connector.cpp b/lib/f1u/du/split_connector/f1u_split_connector.cpp index c1589ea6bf..7559fe5aa2 100644 --- a/lib/f1u/du/split_connector/f1u_split_connector.cpp +++ b/lib/f1u/du/split_connector/f1u_split_connector.cpp @@ -75,7 +75,7 @@ void f1u_split_connector::remove_du_bearer(const up_transport_layer_info& dl_up_ logger_du.debug("Removed CU F1-U bearer with UL GTP Tunnel={}.", dl_up_tnl_info); } -expected f1u_split_connector::get_du_bind_address(gnb_du_id_t gnb_du_id) +expected f1u_split_connector::get_du_bind_address(gnb_du_id_t gnb_du_id) const { std::string ip_address; if (not udp_session->get_bind_address(ip_address)) { diff --git a/lib/f1u/du/split_connector/f1u_split_connector.h b/lib/f1u/du/split_connector/f1u_split_connector.h index 3b0750c6af..bc26a03a51 100644 --- a/lib/f1u/du/split_connector/f1u_split_connector.h +++ b/lib/f1u/du/split_connector/f1u_split_connector.h @@ -184,7 +184,7 @@ class f1u_split_connector final : public f1u_du_udp_gateway f1u_du_gateway* get_f1u_du_gateway() { return this; } - std::optional get_bind_port() override { return udp_session->get_bind_port(); } + std::optional get_bind_port() const override { return udp_session->get_bind_port(); } std::unique_ptr create_du_bearer(uint32_t ue_index, drb_id_t drb_id, @@ -197,7 +197,7 @@ class f1u_split_connector final : public f1u_du_udp_gateway void remove_du_bearer(const up_transport_layer_info& dl_up_tnl_info) override; - expected get_du_bind_address(gnb_du_id_t gnb_du_id) override; + expected get_du_bind_address(gnb_du_id_t gnb_du_id) const override; private: srslog::basic_logger& logger_du; diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index 935cf827d0..6a74a59bc3 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -255,7 +255,7 @@ int udp_network_gateway_impl::get_socket_fd() return sock_fd.value(); } -std::optional udp_network_gateway_impl::get_bind_port() +std::optional udp_network_gateway_impl::get_bind_port() const { if (not sock_fd.is_open()) { logger.error("Socket of UDP network gateway not initialized."); @@ -288,7 +288,7 @@ std::optional udp_network_gateway_impl::get_bind_port() return gw_bind_port; } -bool udp_network_gateway_impl::get_bind_address(std::string& ip_address) +bool udp_network_gateway_impl::get_bind_address(std::string& ip_address) const { ip_address = "no address"; diff --git a/lib/gateways/udp_network_gateway_impl.h b/lib/gateways/udp_network_gateway_impl.h index 11d69f9271..b6c309ff9f 100644 --- a/lib/gateways/udp_network_gateway_impl.h +++ b/lib/gateways/udp_network_gateway_impl.h @@ -48,8 +48,8 @@ class udp_network_gateway_impl final : public udp_network_gateway bool create_and_bind() override; void receive() override; int get_socket_fd() override; - std::optional get_bind_port() override; - bool get_bind_address(std::string& ip_address) override; + std::optional get_bind_port() const override; + bool get_bind_address(std::string& ip_address) const override; // socket helpers bool set_non_blocking(); diff --git a/lib/gtpu/ngu_gateway.cpp b/lib/gtpu/ngu_gateway.cpp index b502a276e8..35d981649c 100644 --- a/lib/gtpu/ngu_gateway.cpp +++ b/lib/gtpu/ngu_gateway.cpp @@ -69,9 +69,9 @@ class udp_ngu_tnl_session final : public ngu_tnl_pdu_session data_notifier.on_new_pdu(std::move(pdu), src_addr); } - bool get_bind_address(std::string& ip_address) override { return udp_gw->get_bind_address(ip_address); } + bool get_bind_address(std::string& ip_address) const override { return udp_gw->get_bind_address(ip_address); } - std::optional get_bind_port() override { return udp_gw->get_bind_port(); } + std::optional get_bind_port() const override { return udp_gw->get_bind_port(); } private: network_gateway_data_notifier_with_src_addr& data_notifier; @@ -127,9 +127,9 @@ class no_core_ngu_tnl_pdu_session final : public ngu_tnl_pdu_session // Do nothing. } - std::optional get_bind_port() override { return std::nullopt; } + std::optional get_bind_port() const override { return std::nullopt; } - bool get_bind_address(std::string& ip_address) override { return false; } + bool get_bind_address(std::string& ip_address) const override { return false; } }; /// Implementation of the NG-U gateway for the case a local UPF stub is used. diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index f2fe6dc3e8..cabaaf5d08 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -372,7 +372,7 @@ class cu_up_simulator : public f1u_du_gateway void remove_du_bearer(const up_transport_layer_info& dl_tnl) override {} - expected get_du_bind_address(gnb_du_id_t gnb_du_id) override { return std::string("127.0.0.1"); } + expected get_du_bind_address(gnb_du_id_t gnb_du_id) const override { return std::string("127.0.0.1"); } }; /// \brief Instantiation of the DU-high workers and executors for the benchmark. diff --git a/tests/test_doubles/f1ap/f1c_test_local_gateway.h b/tests/test_doubles/f1ap/f1c_test_local_gateway.h index d67893c0a1..64864d7d99 100644 --- a/tests/test_doubles/f1ap/f1c_test_local_gateway.h +++ b/tests/test_doubles/f1ap/f1c_test_local_gateway.h @@ -122,7 +122,7 @@ class f1u_test_local_gateway : public srs_du::f1u_du_gateway void remove_du_bearer(const up_transport_layer_info& dl_up_tnl_info) override {} - expected get_du_bind_address(gnb_du_id_t du_index) override { return std::string("127.0.0.1"); } + expected get_du_bind_address(gnb_du_id_t du_index) const override { return std::string("127.0.0.1"); } }; } // namespace srsran diff --git a/tests/test_doubles/f1u/dummy_f1u_du_gateway.h b/tests/test_doubles/f1u/dummy_f1u_du_gateway.h index 07fcfd0d3e..526fda2d87 100644 --- a/tests/test_doubles/f1u/dummy_f1u_du_gateway.h +++ b/tests/test_doubles/f1u/dummy_f1u_du_gateway.h @@ -71,7 +71,7 @@ class cu_up_simulator : public f1u_du_gateway } } - expected get_du_bind_address(gnb_du_id_t du_index) override { return std::string("127.0.0.1"); } + expected get_du_bind_address(gnb_du_id_t du_index) const override { return std::string("127.0.0.1"); } }; } // namespace srs_du diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index ab50e8f5d5..df407f02b7 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -117,7 +117,7 @@ du_manager_test_bench::du_manager_test_bench(span cells) : du_mng_exec(worker), ue_exec_mapper(worker), cell_exec_mapper(worker), - params{{"srsgnb", (gnb_du_id_t)1, 1, transport_layer_address::create_from_string("127.0.0.1"), du_cells}, + params{{"srsgnb", (gnb_du_id_t)1, 1, du_cells}, {timers, du_mng_exec, ue_exec_mapper, cell_exec_mapper}, {f1ap, f1ap}, {f1u_gw}, diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index ff1b7b679d..4a760888d6 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -207,7 +207,7 @@ class f1u_gateway_dummy : public f1u_du_gateway f1u_bearers.erase(bearer_it); } - expected get_du_bind_address(gnb_du_id_t du_index) override { return std::string("127.0.0.1"); } + expected get_du_bind_address(gnb_du_id_t du_index) const override { return std::string("127.0.0.1"); } std::map> f1u_bearers; }; diff --git a/tests/unittests/du_manager/du_ue/ue_manager_test.cpp b/tests/unittests/du_manager/du_ue/ue_manager_test.cpp index 2b77864c3b..85473c5521 100644 --- a/tests/unittests/du_manager/du_ue/ue_manager_test.cpp +++ b/tests/unittests/du_manager/du_ue/ue_manager_test.cpp @@ -96,13 +96,12 @@ class du_ue_manager_tester : public ::testing::Test null_rlc_pcap rlc_pcap; dummy_ue_resource_configurator_factory cell_res_alloc; - du_manager_params params{ - {"srsgnb", (gnb_du_id_t)1, 1, transport_layer_address::create_from_string("127.0.0.1"), cells}, - {timers, worker, ue_execs, cell_execs}, - {f1ap_dummy, f1ap_dummy}, - {f1u_dummy}, - {mac_dummy, f1ap_dummy, f1ap_dummy, rlc_pcap}, - {mac_dummy, mac_dummy}}; + du_manager_params params{{"srsgnb", (gnb_du_id_t)1, 1, cells}, + {timers, worker, ue_execs, cell_execs}, + {f1ap_dummy, f1ap_dummy}, + {f1u_dummy}, + {mac_dummy, f1ap_dummy, f1ap_dummy, rlc_pcap}, + {mac_dummy, mac_dummy}}; du_ue_manager ue_mng{params, cell_res_alloc}; }; diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index 09e894aacd..03c8588be8 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -32,12 +32,11 @@ f1_setup_request_message srsran::srs_du::generate_f1_setup_request_message() { f1_setup_request_message request_msg = {}; du_manager_params::ran_params ran_params; - ran_params.gnb_du_name = "srsgnb"; - ran_params.gnb_du_id = (gnb_du_id_t)1; - ran_params.rrc_version = 1; - ran_params.du_bind_addr = transport_layer_address::create_from_string("127.0.0.1"); - du_cell_config cell = config_helpers::make_default_du_cell_config(); - ran_params.cells = {cell}; + ran_params.gnb_du_name = "srsgnb"; + ran_params.gnb_du_id = (gnb_du_id_t)1; + ran_params.rrc_version = 1; + du_cell_config cell = config_helpers::make_default_du_cell_config(); + ran_params.cells = {cell}; fill_f1_setup_request(request_msg, ran_params); return request_msg; From 85eaf83ada50d7ef711faafe9bb58b5193f4ea01 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 14 Aug 2024 16:01:38 +0200 Subject: [PATCH 296/407] du_manager: avoid reuse of the same ue_capability_manager instance for different UEs --- .../du_bearer_resource_manager.cpp | 13 -- .../du_ran_resource_manager_impl.cpp | 37 +++--- .../du_ran_resource_manager_impl.h | 12 +- .../ue_capability_manager.cpp | 118 +++++++++++++----- .../ue_capability_manager.h | 9 +- 5 files changed, 119 insertions(+), 70 deletions(-) diff --git a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp index 12062c60f2..298e49a8ad 100644 --- a/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_bearer_resource_manager.cpp @@ -15,19 +15,6 @@ using namespace srsran; using namespace srs_du; -template -static auto find_by_srb_id(srb_id_t srb_id, Vec&& bearers) -{ - return std::find_if( - bearers.begin(), bearers.end(), [srb_id](const auto& b) { return b.lcid == srb_id_to_lcid(srb_id); }); -} - -template -static auto find_by_drb_id(drb_id_t drb_id, Vec&& bearers) -{ - return std::find_if(bearers.begin(), bearers.end(), [drb_id](const auto& b) { return b.drb_id == drb_id; }); -} - /// \brief Finds an unused LCID for DRBs given a list of UE configured RLC bearers. static lcid_t find_empty_lcid(const slotted_id_vector& drbs) { diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp index ce8c4364df..a3667e1a32 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.cpp @@ -45,8 +45,7 @@ du_ran_resource_manager_impl::du_ran_resource_manager_impl(span Deallocate resources for previously configured cells that have now been removed or changed. @@ -94,16 +94,6 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } - // > Update UE SRBs and DRBs. - du_ue_bearer_resource_update_response bearer_resp = - bearer_res_mng.update(ue_mcg, - du_ue_bearer_resource_update_request{ - upd_req.srbs_to_setup, upd_req.drbs_to_setup, upd_req.drbs_to_mod, upd_req.drbs_to_rem}, - reestablished_context); - resp.failed_drbs = std::move(bearer_resp.drbs_failed_to_setup); - resp.failed_drbs.insert( - resp.failed_drbs.end(), bearer_resp.drbs_failed_to_mod.begin(), bearer_resp.drbs_failed_to_mod.end()); - // > Allocate resources for new or modified cells. if (not ue_mcg.cell_group.cells.contains(0) or ue_mcg.cell_group.cells[0].serv_cell_cfg.cell_index != pcell_idx) { // >> PCell changed. Allocate new PCell resources. @@ -120,8 +110,18 @@ du_ran_resource_manager_impl::update_context(du_ue_index_t } } - // Process UE NR capabilities. - ue_cap_manager.update(ue_mcg, upd_req.ue_cap_rat_list); + // > Process UE NR capabilities and update UE dedicated configuration. + u.ue_cap_manager.update(ue_mcg, upd_req.ue_cap_rat_list); + + // > Update UE SRBs and DRBs. + du_ue_bearer_resource_update_response bearer_resp = + bearer_res_mng.update(ue_mcg, + du_ue_bearer_resource_update_request{ + upd_req.srbs_to_setup, upd_req.drbs_to_setup, upd_req.drbs_to_mod, upd_req.drbs_to_rem}, + reestablished_context); + resp.failed_drbs = std::move(bearer_resp.drbs_failed_to_setup); + resp.failed_drbs.insert( + resp.failed_drbs.end(), bearer_resp.drbs_failed_to_mod.begin(), bearer_resp.drbs_failed_to_mod.end()); return resp; } @@ -191,3 +191,8 @@ void du_ran_resource_manager_impl::deallocate_cell_resources(du_ue_index_t ue_in ue_res.cell_group.cells.erase(serv_cell_index); } } + +du_ran_resource_manager_impl::ue_resource_context::ue_resource_context(const du_ran_resource_manager_impl& parent) : + ue_cap_manager(parent.cell_cfg_list, parent.logger) +{ +} diff --git a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h index 15fcfdd3f8..d987015019 100644 --- a/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h +++ b/lib/du_manager/ran_resource_management/du_ran_resource_manager_impl.h @@ -88,21 +88,23 @@ class du_ran_resource_manager_impl : public du_ran_resource_manager span cell_cfg_list; srslog::basic_logger& logger; - struct ue_res_item { + struct ue_resource_context { du_ue_resource_config cg_cfg; + + /// Processor of UE capabilities. + ue_capability_manager ue_cap_manager; + + ue_resource_context(const du_ran_resource_manager_impl& parent_); }; /// Current UE Resource Allocations. - slotted_array ue_res_pool; + slotted_array ue_res_pool; /// Allocator of UE PUCCH resources. du_pucch_resource_manager pucch_res_mng; /// Allocator of UE bearer resources. du_bearer_resource_manager bearer_res_mng; - - /// Processor of UE capabilities. - ue_capability_manager ue_cap_manager; }; } // namespace srs_du diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp index 66bd8f4d4f..09764634cd 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp @@ -39,55 +39,76 @@ srsran::srs_du::decode_ue_nr_cap_container(const byte_buffer& ue_cap_container) return ue_caps; } -ue_capability_manager::ue_capability_manager(const scheduler_expert_config& scheduler_cfg_, - srslog::basic_logger& logger_) : - scheduler_cfg(scheduler_cfg_), logger(logger_) +// Configure dedicated UE configuration to set MCS ant CQI tables. +static void set_pdsch_mcs_table(serving_cell_config& cell_cfg, pdsch_mcs_table mcs_table) { - (void)scheduler_cfg; + cqi_table_t cqi_table; + // Set CQI table according to the MCS table used for PDSCH. + switch (mcs_table) { + case pdsch_mcs_table::qam64: + cqi_table = cqi_table_t::table1; + break; + case pdsch_mcs_table::qam256: + cqi_table = cqi_table_t::table2; + break; + case pdsch_mcs_table::qam64LowSe: + cqi_table = cqi_table_t::table3; + break; + default: + report_error("Invalid MCS table={}\n", mcs_table); + } + + // Set MCS index table for PDSCH. See TS 38.214, Table 5.1.3.1-[1-3]. + if (cell_cfg.init_dl_bwp.pdsch_cfg.has_value()) { + cell_cfg.init_dl_bwp.pdsch_cfg->mcs_table = mcs_table; + } + + if (cell_cfg.csi_meas_cfg.has_value()) { + for (auto& csi_report_cfg : cell_cfg.csi_meas_cfg.value().csi_report_cfg_list) { + // Set CQI table. See TS 38.214, Table 5.2.2.1-[1-4]. + csi_report_cfg.cqi_table = cqi_table; + } + } } -void ue_capability_manager::update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list) +// Configure dedicated UE configuration to set PUSCH MCS. +static void set_pusch_mcs_table(serving_cell_config& cell_cfg, pusch_mcs_table mcs_table) { - if (not decode_ue_capability_list(ue_cap_rat_list)) { - // No updates. - return; - } - if (not ue_caps.has_value()) { - // No UE capabilities decoded. - return; + // Set MCS index table for PDSCH. See TS 38.214, Table 5.1.3.1-[1-3]. + if (cell_cfg.ul_config.has_value() and cell_cfg.ul_config->init_ul_bwp.pusch_cfg.has_value()) { + cell_cfg.ul_config->init_ul_bwp.pusch_cfg->mcs_table = mcs_table; } +} - serving_cell_config& pcell_cfg = ue_res_cfg.cell_group.cells[0].serv_cell_cfg; +ue_capability_manager::ue_capability_manager(span cell_cfg_list_, srslog::basic_logger& logger_) : + base_cell_cfg_list(cell_cfg_list_), logger(logger_) +{ +} - // Enable 256QAM for PDSCH, if supported. - if (ue_caps->pdsch_qam256_supported) { - // Set MCS index table 2 for PDSCH. See TS 38.214, Table 5.1.3.1-2. - if (pcell_cfg.init_dl_bwp.pdsch_cfg.has_value()) { - pcell_cfg.init_dl_bwp.pdsch_cfg->mcs_table = pdsch_mcs_table::qam256; - } +void ue_capability_manager::update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list) +{ + // Decode new UE capabilities, if present. + decode_ue_capability_list(ue_cap_rat_list); - if (pcell_cfg.csi_meas_cfg.has_value()) { - for (auto& csi_report_cfg : pcell_cfg.csi_meas_cfg.value().csi_report_cfg_list) { - if (ue_caps->pdsch_qam256_supported) { - // Enable CQI table 2. See TS 38.214, Table 5.2.2.1-3. - csi_report_cfg.cqi_table = cqi_table_t::table2; - } - } - } - } + du_cell_index_t cell_idx = to_du_cell_index(0); + serving_cell_config& pcell_cfg = ue_res_cfg.cell_group.cells[cell_idx].serv_cell_cfg; + + // Enable 256QAM for PDSCH, if supported. + set_pdsch_mcs_table(pcell_cfg, select_pdsch_mcs_table(cell_idx)); // Enable 256QAM for PUSCH, if supported. - if (ue_caps->pusch_qam256_supported) { - if (pcell_cfg.ul_config.has_value() and pcell_cfg.ul_config->init_ul_bwp.pusch_cfg.has_value()) { - pcell_cfg.ul_config->init_ul_bwp.pusch_cfg->mcs_table = pusch_mcs_table::qam256; - } - } + set_pusch_mcs_table(pcell_cfg, select_pusch_mcs_table(cell_idx)); } bool ue_capability_manager::decode_ue_capability_list(const byte_buffer& ue_cap_rat_list) { using namespace asn1::rrc_nr; + if (ue_cap_rat_list.empty()) { + // No update. + return false; + } + ue_cap_rat_container_list_l asn1_cap_list; { asn1::cbit_ref bref{ue_cap_rat_list}; @@ -113,3 +134,34 @@ bool ue_capability_manager::decode_ue_capability_list(const byte_buffer& ue_cap_ return false; } + +pdsch_mcs_table ue_capability_manager::select_pdsch_mcs_table(du_cell_index_t cell_idx) const +{ + const auto& init_dl_bwp = base_cell_cfg_list[cell_idx].ue_ded_serv_cell_cfg.init_dl_bwp; + + if (not init_dl_bwp.pdsch_cfg.has_value() or not ue_caps.has_value()) { + // No PDSCH config or no UE capabilities decoded yet. Default to QAM64. + return pdsch_mcs_table::qam64; + } + if (init_dl_bwp.pdsch_cfg->mcs_table == pdsch_mcs_table::qam256 and not ue_caps->pdsch_qam256_supported) { + // In case the preferred MCS table is 256QAM, but the UE does not support it, we default to QAM64. + return pdsch_mcs_table::qam64; + } + return init_dl_bwp.pdsch_cfg->mcs_table; +} + +pusch_mcs_table ue_capability_manager::select_pusch_mcs_table(du_cell_index_t cell_idx) const +{ + const auto& base_ul_cfg = base_cell_cfg_list[cell_idx].ue_ded_serv_cell_cfg.ul_config; + + if (not base_ul_cfg.has_value() or not base_ul_cfg->init_ul_bwp.pusch_cfg.has_value() or not ue_caps.has_value()) { + // No PUSCH config or no UE capabilities decoded yet. Default to QAM64. + return pusch_mcs_table::qam64; + } + if (base_ul_cfg->init_ul_bwp.pusch_cfg->mcs_table == pusch_mcs_table::qam256 and + not ue_caps->pusch_qam256_supported) { + // In case the preferred MCS table is 256QAM, but the UE does not support it, we default to QAM64. + return pusch_mcs_table::qam64; + } + return base_ul_cfg->init_ul_bwp.pusch_cfg->mcs_table; +} diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.h b/lib/du_manager/ran_resource_management/ue_capability_manager.h index 70f31b85cd..6230a7bb20 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.h +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.h @@ -28,15 +28,18 @@ expected decode_ue_nr_cap_container(const by class ue_capability_manager { public: - explicit ue_capability_manager(const scheduler_expert_config& scheduler_cfg, srslog::basic_logger& logger_); + explicit ue_capability_manager(span cell_cfg_list, srslog::basic_logger& logger_); void update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list); private: bool decode_ue_capability_list(const byte_buffer& ue_cap_rat_list); - const scheduler_expert_config& scheduler_cfg; - srslog::basic_logger& logger; + pdsch_mcs_table select_pdsch_mcs_table(du_cell_index_t cell_idx) const; + pusch_mcs_table select_pusch_mcs_table(du_cell_index_t cell_idx) const; + + span base_cell_cfg_list; + srslog::basic_logger& logger; std::optional ue_caps; }; From b1ea13150a42015d6aeb50f8c7640e7bcd8d1313 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 14 Aug 2024 18:57:27 +0200 Subject: [PATCH 297/407] du_manager: fix PUSCH 256QAM enablement based on capabilities --- include/srsran/ran/pusch/pusch_configuration.h | 5 +++-- .../ran_resource_management/ue_capability_manager.cpp | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/srsran/ran/pusch/pusch_configuration.h b/include/srsran/ran/pusch/pusch_configuration.h index fd28f7dfce..540369f194 100644 --- a/include/srsran/ran/pusch/pusch_configuration.h +++ b/include/srsran/ran/pusch/pusch_configuration.h @@ -176,8 +176,9 @@ struct pusch_config { return data_scrambling_id_pusch == rhs.data_scrambling_id_pusch && tx_cfg == rhs.tx_cfg && pusch_mapping_type_a_dmrs == rhs.pusch_mapping_type_a_dmrs && pusch_mapping_type_b_dmrs == rhs.pusch_mapping_type_b_dmrs && pusch_pwr_ctrl == rhs.pusch_pwr_ctrl && - res_alloc == rhs.res_alloc && trans_precoder == rhs.trans_precoder && cb_subset == rhs.cb_subset && - max_rank == rhs.max_rank && uci_cfg == rhs.uci_cfg && pusch_td_alloc_list == rhs.pusch_td_alloc_list; + res_alloc == rhs.res_alloc && mcs_table == rhs.mcs_table && trans_precoder == rhs.trans_precoder && + cb_subset == rhs.cb_subset && max_rank == rhs.max_rank && uci_cfg == rhs.uci_cfg && + pusch_td_alloc_list == rhs.pusch_td_alloc_list; } bool operator!=(const pusch_config& rhs) const { return !(rhs == *this); } }; diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp index 09764634cd..285633ca51 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp @@ -139,14 +139,12 @@ pdsch_mcs_table ue_capability_manager::select_pdsch_mcs_table(du_cell_index_t ce { const auto& init_dl_bwp = base_cell_cfg_list[cell_idx].ue_ded_serv_cell_cfg.init_dl_bwp; - if (not init_dl_bwp.pdsch_cfg.has_value() or not ue_caps.has_value()) { - // No PDSCH config or no UE capabilities decoded yet. Default to QAM64. - return pdsch_mcs_table::qam64; - } - if (init_dl_bwp.pdsch_cfg->mcs_table == pdsch_mcs_table::qam256 and not ue_caps->pdsch_qam256_supported) { - // In case the preferred MCS table is 256QAM, but the UE does not support it, we default to QAM64. + if (not init_dl_bwp.pdsch_cfg.has_value()) { + // No base cell PDSCH config. Default to QAM64. return pdsch_mcs_table::qam64; } + // TODO: Support dynamic change of the DL MCS table based on the UE capabilities. This requires changes in the + // scheduler. return init_dl_bwp.pdsch_cfg->mcs_table; } From 6b2bda4a711f19e2d2fa4ab71bd099998d7fff73 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 16 Aug 2024 15:02:19 +0200 Subject: [PATCH 298/407] sched: improve ue_capability_manager documentation --- .../ue_capability_manager.cpp | 9 +++++++-- .../ue_capability_manager.h | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp index 285633ca51..885d09136a 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp @@ -87,8 +87,13 @@ ue_capability_manager::ue_capability_manager(span cell_cfg void ue_capability_manager::update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list) { - // Decode new UE capabilities, if present. - decode_ue_capability_list(ue_cap_rat_list); + // Decode new UE capabilities. + if (not decode_ue_capability_list(ue_cap_rat_list) and not first_update) { + // No changes detected in the UE capabilities, and update(...) was called before. In this case, we can do not need + // to apply any extra changes to the ue_res_cfg that weren't already applied. + return; + } + first_update = false; du_cell_index_t cell_idx = to_du_cell_index(0); serving_cell_config& pcell_cfg = ue_res_cfg.cell_group.cells[cell_idx].serv_cell_cfg; diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.h b/lib/du_manager/ran_resource_management/ue_capability_manager.h index 6230a7bb20..14de5b2e33 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.h +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.h @@ -18,21 +18,32 @@ struct scheduler_expert_config; namespace srs_du { +/// Flat structure summarizing the decoded ASN.1 UE capabilities. struct ue_capability_summary { bool pdsch_qam256_supported = false; bool pusch_qam256_supported = false; }; +/// Helper function to extract a summary of the UE capabilities based on a packed ASN.1 container. expected decode_ue_nr_cap_container(const byte_buffer& ue_cap_container); +/// Entity responsible for handling the UE RAT capabilities container, passed by the CU-CP, and updating the UE +/// configuration in the DU accordingly. class ue_capability_manager { public: explicit ue_capability_manager(span cell_cfg_list, srslog::basic_logger& logger_); + /// \brief Called on each UE capability RAT list container received from the CU-CP, to update the UE DU-specific + /// resources. + /// \param[in/out] ue_res_cfg current UE resource configuration, which will be updated inplace, depending on the UE + /// capabilities received. + /// \param[in] ue_cap_rat_list packed UE capability RAT list container. void update(du_ue_resource_config& ue_res_cfg, const byte_buffer& ue_cap_rat_list); private: + // Helper function to decode a packed UE capability RAT list. Returns true, if the packed container was successfully + // decoded and processed. bool decode_ue_capability_list(const byte_buffer& ue_cap_rat_list); pdsch_mcs_table select_pdsch_mcs_table(du_cell_index_t cell_idx) const; @@ -41,8 +52,10 @@ class ue_capability_manager span base_cell_cfg_list; srslog::basic_logger& logger; + // flag that tells whether this is the first time that update is called. + bool first_update = true; std::optional ue_caps; }; } // namespace srs_du -} // namespace srsran \ No newline at end of file +} // namespace srsran From c0ebf80fce4db53f296080a1045d8fc958c3344c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 15:19:08 +0200 Subject: [PATCH 299/407] du_manager: save PUSCH QAM256 capability on a per-band basis --- .../ue_capability_manager.cpp | 13 ++++++++----- .../ran_resource_management/ue_capability_manager.h | 9 +++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp index 885d09136a..2fe070f941 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.cpp +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.cpp @@ -32,8 +32,8 @@ srsran::srs_du::decode_ue_nr_cap_container(const byte_buffer& ue_cap_container) ue_caps.pdsch_qam256_supported = ue_cap.phy_params.phy_params_fr1.pdsch_256_qam_fr1_present; } for (const auto& band : ue_cap.rf_params.supported_band_list_nr) { - // TODO: save per-band capabilities. - ue_caps.pusch_qam256_supported |= band.pusch_256_qam_present; + auto& band_cap = ue_caps.bands.emplace_back(); + band_cap.pusch_qam256_supported = band.pusch_256_qam_present; } return ue_caps; @@ -161,10 +161,13 @@ pusch_mcs_table ue_capability_manager::select_pusch_mcs_table(du_cell_index_t ce // No PUSCH config or no UE capabilities decoded yet. Default to QAM64. return pusch_mcs_table::qam64; } - if (base_ul_cfg->init_ul_bwp.pusch_cfg->mcs_table == pusch_mcs_table::qam256 and - not ue_caps->pusch_qam256_supported) { + + if (base_ul_cfg->init_ul_bwp.pusch_cfg->mcs_table == pusch_mcs_table::qam256) { // In case the preferred MCS table is 256QAM, but the UE does not support it, we default to QAM64. - return pusch_mcs_table::qam64; + if (std::none_of( + ue_caps->bands.begin(), ue_caps->bands.end(), [](const auto& b) { return b.pusch_qam256_supported; })) { + return pusch_mcs_table::qam64; + } } return base_ul_cfg->init_ul_bwp.pusch_cfg->mcs_table; } diff --git a/lib/du_manager/ran_resource_management/ue_capability_manager.h b/lib/du_manager/ran_resource_management/ue_capability_manager.h index 14de5b2e33..a0739ad0dc 100644 --- a/lib/du_manager/ran_resource_management/ue_capability_manager.h +++ b/lib/du_manager/ran_resource_management/ue_capability_manager.h @@ -20,8 +20,13 @@ namespace srs_du { /// Flat structure summarizing the decoded ASN.1 UE capabilities. struct ue_capability_summary { - bool pdsch_qam256_supported = false; - bool pusch_qam256_supported = false; + struct supported_band { + nr_band band; + bool pusch_qam256_supported = false; + }; + + bool pdsch_qam256_supported = false; + std::vector bands; }; /// Helper function to extract a summary of the UE capabilities based on a packed ASN.1 container. From 4dc2e33ddfff965db65cc61c036019b115892a76 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 16 Aug 2024 15:59:44 +0200 Subject: [PATCH 300/407] sched: simplify ue repo maintenance in slice scheduler --- .../scheduler/config/logical_channel_config.h | 7 ++++ lib/scheduler/slicing/ran_slice_instance.cpp | 39 ++++++++----------- lib/scheduler/slicing/ran_slice_instance.h | 10 +++-- lib/scheduler/slicing/slice_scheduler.cpp | 25 +++++++----- 4 files changed, 45 insertions(+), 36 deletions(-) diff --git a/include/srsran/scheduler/config/logical_channel_config.h b/include/srsran/scheduler/config/logical_channel_config.h index edc4937c23..d9c5ec6c82 100644 --- a/include/srsran/scheduler/config/logical_channel_config.h +++ b/include/srsran/scheduler/config/logical_channel_config.h @@ -28,6 +28,13 @@ struct logical_channel_config { bool lc_sr_mask; bool lc_sr_delay_timer_applied; rrm_policy_member rrm_policy; + + bool operator==(const logical_channel_config& rhs) const + { + return lcid == rhs.lcid and priority == rhs.priority and lc_group == rhs.lc_group and sr_id == rhs.sr_id and + lc_sr_mask == rhs.lc_sr_mask and lc_sr_delay_timer_applied == rhs.lc_sr_delay_timer_applied and + rrm_policy == rhs.rrm_policy; + } }; } // namespace srsran diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 4b4804513e..95476fec01 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -23,16 +23,6 @@ void ran_slice_instance::slot_indication(const ue_repository& cell_ues) { pdsch_rb_count = 0; pusch_rb_count = 0; - // Remove UEs from slice UEs list if it's removed from UE repository. - auto* ue_to_rem_it = slice_ues_to_rem.begin(); - while (ue_to_rem_it != slice_ues_to_rem.end()) { - if (not cell_ues.contains(*ue_to_rem_it)) { - slice_ues.erase(*ue_to_rem_it); - ue_to_rem_it = slice_ues_to_rem.erase(ue_to_rem_it); - continue; - } - ++ue_to_rem_it; - } } void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) @@ -40,20 +30,21 @@ void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) if (not slice_ues.contains(ue_idx)) { return; } - if (lcid < MAX_NOF_RB_LCIDS) { - slice_ues[ue_idx].rem_logical_channel(lcid); - if (not slice_ues[ue_idx].has_bearers_in_slice()) { - slice_ues_to_rem.push_back(ue_idx); - } - return; + + slice_ues[ue_idx].rem_logical_channel(lcid); + + if (not slice_ues[ue_idx].has_bearers_in_slice()) { + // If no more bearers active for this UE, remove it from the slice. + slice_ues.erase(ue_idx); } - // Disable all DRBs. - for (unsigned lcid_to_rem = LCID_MIN_DRB; lcid_to_rem < MAX_NOF_RB_LCIDS; ++lcid_to_rem) { - if (slice_ues[ue_idx].contains(uint_to_lcid(lcid_to_rem))) { - slice_ues[ue_idx].rem_logical_channel(uint_to_lcid(lcid_to_rem)); - } +} + +void ran_slice_instance::rem_ue(du_ue_index_t ue_idx) +{ + if (not slice_ues.contains(ue_idx)) { + return; } - slice_ues_to_rem.push_back(ue_idx); + slice_ues.erase(ue_idx); } const slice_ue_repository& ran_slice_instance::get_ues() @@ -63,6 +54,10 @@ const slice_ue_repository& ran_slice_instance::get_ues() void ran_slice_instance::add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id) { + if (lcid == LCID_SRB0) { + // SRB0 is not handled by slice scheduler. + return; + } if (not slice_ues.contains(u.ue_index)) { slice_ues.emplace(u.ue_index, u); } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index c12b3e4ff0..8141cc9bcb 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -49,9 +49,12 @@ class ran_slice_instance /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. void add_logical_channel(const ue& u, lcid_t lcid, lcg_id_t lcg_id); - /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. + /// Remove a (UE, LCID) from the list of bearers managed by this slice. /// \remark UE is removed if all LCIDs of a UE are removed. - void rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid = MAX_NOF_RB_LCIDS); + void rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid); + + /// Remove UE all associated LCIDs. + void rem_ue(du_ue_index_t ue_idx); /// Returns UEs belonging to this slice. const slice_ue_repository& get_ues(); @@ -66,8 +69,7 @@ class ran_slice_instance unsigned pusch_rb_count = 0; private: - slice_ue_repository slice_ues; - static_vector slice_ues_to_rem; + slice_ue_repository slice_ues; }; } // namespace srsran diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 1e63c0366c..e867342ebf 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -64,27 +64,32 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { - // [Implementation-defined] UE does not have complete configuration. Hence, UE won't be added to the slice. + // [Implementation-defined] UE does not have complete configuration. Hence, UE won't be added to any slice. if (not ue_cfg.is_ue_cfg_complete()) { return; } + if (not ues.contains(ue_cfg.ue_index)) { + // UE is not added to the UE repository. + logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found", ue_cfg.ue_index); + return; + } for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); - if (ues.contains(ue_cfg.ue_index)) { - sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); - } + sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); } } void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_configuration& prev_ue_cfg) { - // Remove old bearers. - for (const logical_channel_config& lc_cfg : prev_ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg); - sl_inst.rem_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid); + if (next_ue_cfg.logical_channels() == prev_ue_cfg.logical_channels()) { + // No changes detected. + return; } - // Add new bearers. + // Remove UE and associated bearer from previous slices. + rem_ue(prev_ue_cfg.ue_index); + + // Add UE and new bearers. add_ue(next_ue_cfg); } @@ -92,7 +97,7 @@ void slice_scheduler::rem_ue(du_ue_index_t ue_idx) { for (auto& slice : slices) { // Remove all logical channels of UE. - slice.inst.rem_logical_channel(ue_idx); + slice.inst.rem_ue(ue_idx); } } From 99f8092e5778954d5ccc69a56e9c90d2f1cd8ddd Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 10:15:39 +0200 Subject: [PATCH 301/407] sched: UE fallback mode toggle or deactivation cancels retxs --- lib/scheduler/policy/scheduler_time_pf.cpp | 10 ++++-- lib/scheduler/policy/scheduler_time_rr.cpp | 30 ++++++----------- lib/scheduler/slicing/ran_slice_instance.cpp | 2 +- lib/scheduler/slicing/ran_slice_instance.h | 2 +- lib/scheduler/slicing/slice_scheduler.cpp | 33 +++++++++---------- lib/scheduler/slicing/slice_scheduler.h | 4 +-- lib/scheduler/ue_scheduling/ue_cell.cpp | 15 +++++++++ .../ue_scheduling/ue_event_manager.cpp | 31 ++++++++++++----- 8 files changed, 75 insertions(+), 52 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index 5b33c706bf..f485b30f89 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -181,9 +181,12 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id dl_newtx_h = nullptr; dl_prio = 0; const ue_cell* ue_cc = u.find_cell(cell_index); - if (ue_cc == nullptr or not ue_cc->is_active() or ue_cc->is_in_fallback_mode()) { + if (ue_cc == nullptr) { return; } + srsran_assert(ue_cc->is_active() and not ue_cc->is_in_fallback_mode(), + "policy scheduler called for UE={} in fallback", + ue_cc->ue_index); static_vector dl_harq_candidates; // Create list of DL HARQ processes with pending retx, sorted from oldest to newest. @@ -260,9 +263,12 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, ul_prio = 0; sr_ind_received = false; const ue_cell* ue_cc = u.find_cell(cell_index); - if (ue_cc == nullptr or not ue_cc->is_active() or ue_cc->is_in_fallback_mode()) { + if (ue_cc == nullptr) { return; } + srsran_assert(ue_cc->is_active() and not ue_cc->is_in_fallback_mode(), + "policy scheduler called for UE={} in fallback", + ue_cc->ue_index); static_vector ul_harq_candidates; // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 90cbd62727..59a54f78d6 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -127,23 +127,19 @@ static static_vector get_ue_dl_harq_candi static_vector dl_harq_candidates; const ue_cell& ue_cc = ue_ref.get_cell(cell_index); - if (ue_cc.is_in_fallback_mode()) { - return dl_harq_candidates; - } if (is_retx) { // Create list of DL HARQ processes with pending retx, sorted from oldest to newest. for (unsigned i = 0; i != ue_cc.harqs.nof_dl_harqs(); ++i) { const dl_harq_process& h = ue_cc.harqs.dl_harq(i); - if (h.has_pending_retx() and not h.last_alloc_params().is_fallback and - h.last_alloc_params().tb[0]->slice_id == slice_id) { + if (h.has_pending_retx() and h.last_alloc_params().tb[0]->slice_id == slice_id) { dl_harq_candidates.push_back(&h); } } std::sort(dl_harq_candidates.begin(), dl_harq_candidates.end(), [](const dl_harq_process* lhs, const dl_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); - } else if (ue_cc.is_active()) { - // If there are no pending new Tx bytes or UE in fallback, return. + } else { + // If there are no pending new Tx bytes, return. if (not ue_ref.has_pending_dl_newtx_bytes()) { return dl_harq_candidates; } @@ -184,9 +180,6 @@ static static_vector get_ue_ul_harq_candi static_vector ul_harq_candidates; const ue_cell& ue_cc = ue_ref.get_cell(cell_index); - if (ue_cc.is_in_fallback_mode()) { - return ul_harq_candidates; - } if (is_retx) { // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { @@ -198,7 +191,7 @@ static static_vector get_ue_ul_harq_candi std::sort(ul_harq_candidates.begin(), ul_harq_candidates.end(), [](const ul_harq_process* lhs, const ul_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); - } else if (ue_cc.is_active()) { + } else { // If there are no pending new Tx bytes, return. if (ue_ref.pending_ul_newtx_bytes() == 0) { return ul_harq_candidates; @@ -284,11 +277,9 @@ static alloc_result alloc_dl_ue(const slice_ue& u, // Prioritize PCell over SCells. for (unsigned i = 0; i != u.nof_cells(); ++i) { const ue_cell& ue_cc = u.get_cell(to_ue_cell_index(i)); - - if (ue_cc.is_in_fallback_mode()) { - // Skip allocation for UEs in fallback mode, as it is handled by the SRB fallback scheduler. - return {alloc_status::skip_ue}; - } + srsran_assert(ue_cc.is_active() and not ue_cc.is_in_fallback_mode(), + "policy scheduler called for UE={} in fallback", + ue_cc.ue_index); // UE is already allocated in the PDCCH for this slot (e.g. we should skip a newTx if a reTx has already been // allocated for this UE). @@ -343,10 +334,9 @@ static alloc_result alloc_ul_ue(const slice_ue& u, // Prioritize PCell over SCells. for (unsigned i = 0; i != u.nof_cells(); ++i) { const ue_cell& ue_cc = u.get_cell(to_ue_cell_index(i)); - if (ue_cc.is_in_fallback_mode()) { - // Skip allocation for UEs in fallback mode, as it is handled by the SRB fallback scheduler. - return {alloc_status::skip_ue}; - } + srsran_assert(ue_cc.is_active() and not ue_cc.is_in_fallback_mode(), + "policy scheduler called for UE={} in fallback", + ue_cc.ue_index); // Get UL HARQ candidates. const auto harq_candidates = get_ue_ul_harq_candidates(u, to_ue_cell_index(i), is_retx, slice_id, logger); diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 95476fec01..f1be415539 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -19,7 +19,7 @@ ran_slice_instance::ran_slice_instance(ran_slice_id_t id_, { } -void ran_slice_instance::slot_indication(const ue_repository& cell_ues) +void ran_slice_instance::slot_indication() { pdsch_rb_count = 0; pusch_rb_count = 0; diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 8141cc9bcb..b3c434a924 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -24,7 +24,7 @@ class ran_slice_instance public: ran_slice_instance(ran_slice_id_t id_, const cell_configuration& cell_cfg_, const slice_rrm_policy_config& cfg_); - void slot_indication(const ue_repository& cell_ues); + void slot_indication(); bool active() const { return not slice_ues.empty(); } diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index e867342ebf..3d2a1cd944 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -49,7 +49,7 @@ void slice_scheduler::slot_indication() // Update the context of each slice. for (auto& slice : slices) { - slice.inst.slot_indication(ues); + slice.inst.slot_indication(); } // Recompute the priority queues. @@ -64,33 +64,32 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { - // [Implementation-defined] UE does not have complete configuration. Hence, UE won't be added to any slice. - if (not ue_cfg.is_ue_cfg_complete()) { - return; - } if (not ues.contains(ue_cfg.ue_index)) { - // UE is not added to the UE repository. + // UE should be added to the repository at this stage. logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found", ue_cfg.ue_index); return; } + + // Add UE and new bearers. + // [Implementation-defined] UE does not have complete configuration. Hence, UE won't be added to any slice. + if (not ue_cfg.is_ue_cfg_complete()) { + return; + } + auto& u = ues[ue_cfg.ue_index]; + for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); - sl_inst.add_logical_channel(ues[ue_cfg.ue_index], lc_cfg.lcid, lc_cfg.lc_group); + sl_inst.add_logical_channel(u, lc_cfg.lcid, lc_cfg.lc_group); } } -void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_configuration& prev_ue_cfg) +void slice_scheduler::reconf_ue(const ue_configuration& ue_cfg) { - if (next_ue_cfg.logical_channels() == prev_ue_cfg.logical_channels()) { - // No changes detected. - return; - } - - // Remove UE and associated bearer from previous slices. - rem_ue(prev_ue_cfg.ue_index); + // Remove UE and previously associated bearers from all slices. + rem_ue(ue_cfg.ue_index); - // Add UE and new bearers. - add_ue(next_ue_cfg); + // Re-add UE but with new bearers. + add_ue(ue_cfg); } void slice_scheduler::rem_ue(du_ue_index_t ue_idx) diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index 91b566a2f3..b94aa29cc2 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -31,8 +31,8 @@ class slice_scheduler void slot_indication(); /// Update the state of the slice with the provided UE configs. - void add_ue(const ue_configuration& ue_cfg); - void reconf_ue(const ue_configuration& next_ue_cfg, const ue_configuration& prev_ue_cfg); + void add_ue(const ue_configuration& next_ue_cfg); + void reconf_ue(const ue_configuration& next_ue_cfg); void rem_ue(du_ue_index_t ue_idx); /// Get next RAN slice for PDSCH scheduling. diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index 847d624de0..d3a928e172 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -74,6 +74,21 @@ void ue_cell::set_fallback_state(bool set_fallback) return; } in_fallback_mode = set_fallback; + + // Cancel pending HARQs retxs of different state. + for (unsigned i = 0; i != harqs.nof_dl_harqs(); ++i) { + dl_harq_process& h = harqs.dl_harq(to_harq_id(i)); + if (not h.empty() and h.last_alloc_params().is_fallback != in_fallback_mode) { + h.cancel_harq_retxs(0); + } + } + for (unsigned i = 0; i != harqs.nof_ul_harqs(); ++i) { + ul_harq_process& h = harqs.ul_harq(to_harq_id(i)); + if (not h.empty()) { + h.cancel_harq_retxs(); + } + } + logger.debug("ue={} rnti={}: {} fallback mode", ue_index, rnti(), in_fallback_mode ? "Entering" : "Leaving"); } diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 7e0a72fb00..3818f665ad 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -146,8 +146,12 @@ void ue_event_manager::handle_ue_creation(ue_config_update_event ev) for (unsigned i = 0, e = added_ue.nof_cells(); i != e; ++i) { // 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()); - // Add UE to a slice. - du_cells[pcell_index].slice_sched->add_ue(*added_ue.ue_cfg_dedicated()); + + // Add UE to slice scheduler, if it does not start in fallback mode. + // Note: The UE is only added to the slice scheduler when outside of fallback mode. + if (not ev.get_fallback_command().has_value() or not ev.get_fallback_command().value()) { + du_cells[pcell_index].slice_sched->add_ue(*added_ue.ue_cfg_dedicated()); + } } // Log Event. @@ -178,8 +182,10 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) } 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()); - // Reconfigure UE in slice scheduler. - du_cells[ue_cc.cell_index].slice_sched->reconf_ue(ev.next_config(), *u.ue_cfg_dedicated()); + if (not ue_cc.is_in_fallback_mode()) { + // Reconfigure UE in slice scheduler. + du_cells[ue_cc.cell_index].slice_sched->reconf_ue(ev.next_config()); + } } } for (unsigned i = 0, e = ev.next_config().nof_cells(); i != e; ++i) { @@ -188,8 +194,10 @@ 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); - // Add UE to a slice. - du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].slice_sched->add_ue(ev.next_config()); + if (not ue_cc->is_in_fallback_mode()) { + // Add UE to a slice. + du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].slice_sched->reconf_ue(ev.next_config()); + } } } @@ -236,11 +244,16 @@ void ue_event_manager::handle_ue_config_applied(du_ue_index_t ue_idx) logger.warning("Received config application confirmation for ue={} that does not exist", ue_idx); return; } - ue& u = ue_db[ue_idx]; + ue& u = ue_db[ue_idx]; + auto& pcell = du_cells[u.get_pcell().cell_index]; // Log UE config applied event. - du_cells[u.get_pcell().cell_index].ev_logger->enqueue( - scheduler_event_logger::ue_cfg_applied_event{ue_idx, u.crnti}); + pcell.ev_logger->enqueue(scheduler_event_logger::ue_cfg_applied_event{ue_idx, u.crnti}); + + if (u.get_pcell().is_in_fallback_mode()) { + // Add UE to slice scheduler, once it leaves fallback mode. + pcell.slice_sched->reconf_ue(*u.ue_cfg_dedicated()); + } // Remove UE from fallback mode. u.get_pcell().set_fallback_state(false); From c05a7d97f3f0fa081b0eb806cd41c02251867602 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 11:03:04 +0200 Subject: [PATCH 302/407] sched: simplify UE slice scheduler add/mod/rem interface --- lib/scheduler/slicing/slice_scheduler.cpp | 49 +++++++++++++++---- lib/scheduler/slicing/slice_scheduler.h | 5 +- .../ue_scheduling/ue_event_manager.cpp | 33 ++++++------- .../policy/scheduler_policy_test.cpp | 2 +- .../slicing/slice_scheduler_test.cpp | 2 +- 5 files changed, 59 insertions(+), 32 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 3d2a1cd944..87db1231b1 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -62,44 +62,73 @@ void slice_scheduler::slot_indication() } } -void slice_scheduler::add_ue(const ue_configuration& ue_cfg) +void slice_scheduler::add_ue(du_ue_index_t ue_idx) { - if (not ues.contains(ue_cfg.ue_index)) { + if (not ues.contains(ue_idx)) { // UE should be added to the repository at this stage. - logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found", ue_cfg.ue_index); + logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found", ue_idx); return; } + auto& u = ues[ue_idx]; + const ue_configuration& ue_cfg = *u.ue_cfg_dedicated(); - // Add UE and new bearers. - // [Implementation-defined] UE does not have complete configuration. Hence, UE won't be added to any slice. + // If UE does not have complete configuration, we won't be added to any slice. if (not ue_cfg.is_ue_cfg_complete()) { return; } - auto& u = ues[ue_cfg.ue_index]; + // If UE is in fallback mode, we do not add it to the slice scheduler. + const ue_cell* ue_cc = u.find_cell(cell_cfg.cell_index); + if (ue_cc == nullptr) { + logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found in cell {}", + ue_cfg.ue_index, + cell_cfg.cell_index); + return; + } + if (ue_cc->is_in_fallback_mode()) { + // Do not include yet the UE in the slice scheduler. + return; + } + + // Add UE and new bearers. for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); sl_inst.add_logical_channel(u, lc_cfg.lcid, lc_cfg.lc_group); } } -void slice_scheduler::reconf_ue(const ue_configuration& ue_cfg) +void slice_scheduler::reconf_ue(du_ue_index_t ue_idx) { // Remove UE and previously associated bearers from all slices. - rem_ue(ue_cfg.ue_index); + rem_ue(ue_idx); // Re-add UE but with new bearers. - add_ue(ue_cfg); + add_ue(ue_idx); } void slice_scheduler::rem_ue(du_ue_index_t ue_idx) { + // Remove all logical channels of UE. + // Note: We take the conservative approach of traversing all slices, because the current UE config might not match + // the UE repositories inside each slice instance (e.g. in case of fallback or during reconfig). for (auto& slice : slices) { - // Remove all logical channels of UE. slice.inst.rem_ue(ue_idx); } } +void slice_scheduler::config_applied(du_ue_index_t ue_idx) +{ + auto& u = ues[ue_idx]; + const ue_cell* ue_cc = u.find_cell(cell_cfg.cell_index); + srsran_assert(not ue_cc->is_in_fallback_mode(), "This function is only called when UE is not in fallback"); + + // Add UE to slices. + for (const logical_channel_config& lc_cfg : u.ue_cfg_dedicated()->logical_channels()) { + ran_slice_instance& sl_inst = get_slice(lc_cfg); + sl_inst.add_logical_channel(u, lc_cfg.lcid, lc_cfg.lc_group); + } +} + ran_slice_instance& slice_scheduler::get_slice(const logical_channel_config& lc_cfg) { // Return default SRB slice if LCID belongs to a SRB. diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index b94aa29cc2..1118f16402 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -31,9 +31,10 @@ class slice_scheduler void slot_indication(); /// Update the state of the slice with the provided UE configs. - void add_ue(const ue_configuration& next_ue_cfg); - void reconf_ue(const ue_configuration& next_ue_cfg); + void add_ue(du_ue_index_t ue_idx); + void reconf_ue(du_ue_index_t ue_idx); void rem_ue(du_ue_index_t ue_idx); + void config_applied(du_ue_index_t ue_idx); /// Get next RAN slice for PDSCH scheduling. std::optional get_next_dl_candidate(); diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 3818f665ad..1a831a4701 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -147,11 +147,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()); - // Add UE to slice scheduler, if it does not start in fallback mode. - // Note: The UE is only added to the slice scheduler when outside of fallback mode. - if (not ev.get_fallback_command().has_value() or not ev.get_fallback_command().value()) { - du_cells[pcell_index].slice_sched->add_ue(*added_ue.ue_cfg_dedicated()); - } + // 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); } // Log Event. @@ -171,6 +169,8 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) } auto& u = ue_db[ue_idx]; + // If a UE carrier has been removed, remove the UE from the respective slice scheduler. + // Update UCI scheduler with cell changes. for (unsigned i = 0, e = u.nof_cells(); i != e; ++i) { auto& ue_cc = u.get_cell(to_ue_cell_index(i)); if (not ev.next_config().contains(ue_cc.cell_index)) { @@ -182,10 +182,6 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) } 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()); - if (not ue_cc.is_in_fallback_mode()) { - // Reconfigure UE in slice scheduler. - du_cells[ue_cc.cell_index].slice_sched->reconf_ue(ev.next_config()); - } } } for (unsigned i = 0, e = ev.next_config().nof_cells(); i != e; ++i) { @@ -194,16 +190,19 @@ 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); - if (not ue_cc->is_in_fallback_mode()) { - // Add UE to a slice. - du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].slice_sched->reconf_ue(ev.next_config()); - } } } // Configure existing UE. ue_db[ue_idx].handle_reconfiguration_request(ue_reconf_command{ev.next_config()}); + // Update slice scheduler. + for (unsigned i = 0, e = u.nof_cells(); i != e; ++i) { + const auto& ue_cc = u.get_cell(to_ue_cell_index(i)); + // Reconfigure UE in slice scheduler. + du_cells[ue_cc.cell_index].slice_sched->reconf_ue(u.ue_index); + } + // Log event. du_cells[u.get_pcell().cell_index].ev_logger->enqueue(scheduler_event_logger::ue_reconf_event{ue_idx, u.crnti}); }); @@ -250,13 +249,11 @@ void ue_event_manager::handle_ue_config_applied(du_ue_index_t ue_idx) // Log UE config applied event. pcell.ev_logger->enqueue(scheduler_event_logger::ue_cfg_applied_event{ue_idx, u.crnti}); - if (u.get_pcell().is_in_fallback_mode()) { - // Add UE to slice scheduler, once it leaves fallback mode. - pcell.slice_sched->reconf_ue(*u.ue_cfg_dedicated()); - } - // Remove UE from fallback mode. u.get_pcell().set_fallback_state(false); + + // Add UE to slice scheduler, once it leaves fallback mode. + pcell.slice_sched->config_applied(ue_idx); }); } diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index aa697e77d7..4101b135f5 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -121,7 +121,7 @@ class base_scheduler_policy_test std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); ues.add_ue(std::make_unique( ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, harq_timeout_handler})); - slice_sched.add_ue(*ues[ue_req.ue_index].ue_cfg_dedicated()); + slice_sched.add_ue(ue_req.ue_index); return ues[ue_req.ue_index]; } diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 89bdee2ac8..8b41f002ec 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -46,7 +46,7 @@ class slice_scheduler_test { const ue_configuration* ue_cfg = test_cfg.add_ue(req); ues.add_ue(std::make_unique(ue_creation_command{*ue_cfg, req.starts_in_fallback, harq_timeout_handler})); - slice_sched.add_ue(*ue_cfg); + slice_sched.add_ue(req.ue_index); return ue_cfg; } From 6765ba0409c67a8a2aab111a147e8bcdd577989d Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 11:33:19 +0200 Subject: [PATCH 303/407] sched: improve logging of cancelled HARQ retxs in the case of DL --- lib/scheduler/ue_scheduling/harq_process.cpp | 25 +++++++++++++------- lib/scheduler/ue_scheduling/harq_process.h | 4 +++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/scheduler/ue_scheduling/harq_process.cpp b/lib/scheduler/ue_scheduling/harq_process.cpp index 45f9757726..322e2ebced 100644 --- a/lib/scheduler/ue_scheduling/harq_process.cpp +++ b/lib/scheduler/ue_scheduling/harq_process.cpp @@ -131,6 +131,7 @@ void detail::harq_process::cancel_harq_retxs(unsigned tb_idx) return; } tb_array[tb_idx].max_nof_harq_retxs = tb_array[tb_idx].nof_retxs; + tb_array[tb_idx].cancelled = true; } template @@ -162,6 +163,7 @@ void detail::harq_process::new_tx_tb_common(unsigned tb_idx, tb_array[tb_idx].nof_retxs = 0; tb_array[tb_idx].harq_bit_idx = harq_bit_idx; tb_array[tb_idx].ack_on_timeout = false; + tb_array[tb_idx].cancelled = false; } template @@ -253,11 +255,18 @@ dl_harq_process::ack_info(uint32_t tb_idx, mac_harq_ack_report_status ack, std:: base_type::ack_info_common(tb_idx, chosen_ack == mac_harq_ack_report_status::ack); if (chosen_ack != mac_harq_ack_report_status::ack and empty(tb_idx)) { - logger.info(id, - "Discarding HARQ process tb={} with tbs={}. Cause: Maximum number of reTxs {} exceeded", - tb_idx, - prev_tx_params.tb[tb_idx]->tbs_bytes, - max_nof_harq_retxs(tb_idx)); + if (this->tb_array[0].cancelled) { + logger.debug(id, + "Discarding HARQ process tb={} with tbs={}. Cause: HARQ process was cancelled", + tb_idx, + prev_tx_params.tb[tb_idx]->tbs_bytes); + } else { + logger.info(id, + "Discarding HARQ process tb={} with tbs={}. Cause: Maximum number of reTxs {} exceeded", + tb_idx, + prev_tx_params.tb[tb_idx]->tbs_bytes, + max_nof_harq_retxs(tb_idx)); + } } return chosen_ack == mac_harq_ack_report_status::ack ? status_update::acked : status_update::nacked; } @@ -313,7 +322,6 @@ void ul_harq_process::new_tx(slot_point pusch_slot, unsigned max_harq_retxs) // Note: For UL, DAI is not used, so we set it to zero. base_type::new_tx_tb_common(0, max_harq_retxs, 0); prev_tx_params = {}; - harq_cancelled = false; } void ul_harq_process::new_retx(slot_point pusch_slot) @@ -330,8 +338,8 @@ int ul_harq_process::crc_info(bool ack) return (int)prev_tx_params.tbs_bytes; } if (empty()) { - if (harq_cancelled) { - logger.info(id, "Discarding HARQ with tbs={}. Cause: HARQ process was cancelled", prev_tx_params.tbs_bytes); + if (this->tb_array[0].cancelled) { + logger.debug(id, "Discarding HARQ with tbs={}. Cause: HARQ process was cancelled", prev_tx_params.tbs_bytes); } else { logger.info(id, "Discarding HARQ with tbs={}. Cause: Maximum number of reTxs {} exceeded", @@ -367,7 +375,6 @@ void ul_harq_process::save_alloc_params(const ul_harq_sched_context& ctx, const void ul_harq_process::cancel_harq_retxs() { - harq_cancelled = true; base_type::cancel_harq_retxs(0); } diff --git a/lib/scheduler/ue_scheduling/harq_process.h b/lib/scheduler/ue_scheduling/harq_process.h index 024f491036..a2cabbc852 100644 --- a/lib/scheduler/ue_scheduling/harq_process.h +++ b/lib/scheduler/ue_scheduling/harq_process.h @@ -149,6 +149,9 @@ class harq_process /// Whether to set the HARQ as ACKed or NACKed when the timeout expires. bool ack_on_timeout = false; + /// Whether the HARQ retransmissions were cancelled (e.g. due to UE changing state). + bool cancelled = false; + bool empty() const { return state == state_t::empty; } }; @@ -438,7 +441,6 @@ class ul_harq_process : private detail::harq_process private: /// Parameters used for the last Tx of this HARQ process. alloc_params prev_tx_params; - bool harq_cancelled = false; }; /// \brief Helper function to fill HARQ allocation grant parameters. From e99dc031752206ad2682fff68c414a7683b95d4c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 15:07:08 +0200 Subject: [PATCH 304/407] sched: cancel HARQ retxs if UE is removed from slice --- lib/scheduler/slicing/slice_scheduler.cpp | 104 +++++++++++++++------- lib/scheduler/slicing/slice_scheduler.h | 9 +- 2 files changed, 77 insertions(+), 36 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 87db1231b1..07d93ad3b6 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -14,7 +14,7 @@ using namespace srsran; -slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, const ue_repository& ues_) : +slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, ue_repository& ues_) : cell_cfg(cell_cfg_), logger(srslog::fetch_basic_logger("SCHED")), ues(ues_) { // Create a number of slices equal to the number of configured RRM Policy members + 1 (default SRB slice) + 1 (default @@ -64,37 +64,13 @@ void slice_scheduler::slot_indication() void slice_scheduler::add_ue(du_ue_index_t ue_idx) { - if (not ues.contains(ue_idx)) { - // UE should be added to the repository at this stage. - logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found", ue_idx); - return; - } - auto& u = ues[ue_idx]; - const ue_configuration& ue_cfg = *u.ue_cfg_dedicated(); - - // If UE does not have complete configuration, we won't be added to any slice. - if (not ue_cfg.is_ue_cfg_complete()) { - return; - } - - // If UE is in fallback mode, we do not add it to the slice scheduler. - const ue_cell* ue_cc = u.find_cell(cell_cfg.cell_index); - if (ue_cc == nullptr) { - logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found in cell {}", - ue_cfg.ue_index, - cell_cfg.cell_index); - return; - } - if (ue_cc->is_in_fallback_mode()) { - // Do not include yet the UE in the slice scheduler. + ue* u = fetch_ue_to_update(ue_idx); + if (u == nullptr) { return; } // Add UE and new bearers. - for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { - ran_slice_instance& sl_inst = get_slice(lc_cfg); - sl_inst.add_logical_channel(u, lc_cfg.lcid, lc_cfg.lc_group); - } + add_impl(*u); } void slice_scheduler::reconf_ue(du_ue_index_t ue_idx) @@ -102,8 +78,28 @@ void slice_scheduler::reconf_ue(du_ue_index_t ue_idx) // Remove UE and previously associated bearers from all slices. rem_ue(ue_idx); - // Re-add UE but with new bearers. - add_ue(ue_idx); + ue* u = fetch_ue_to_update(ue_idx); + if (u == nullptr) { + return; + } + add_impl(*u); + + // Check if any UE HARQs need to be cancelled in case the UE got removed from the respective slice. + ue_cell& ue_cell = *u->find_cell(cell_cfg.cell_index); + for (unsigned i = 0; i != ue_cell.harqs.nof_dl_harqs(); ++i) { + dl_harq_process& h_dl = ue_cell.harqs.dl_harq(to_harq_id(i)); + if (h_dl.has_pending_retx() and h_dl.last_alloc_params().tb[0]->slice_id.has_value() and + not slices[h_dl.last_alloc_params().tb[0]->slice_id->value()].inst.contains(ue_idx)) { + h_dl.cancel_harq_retxs(0); + } + } + for (unsigned i = 0; i != ue_cell.harqs.nof_ul_harqs(); ++i) { + ul_harq_process& h_ul = ue_cell.harqs.ul_harq(to_harq_id(i)); + if (h_ul.has_pending_retx() and h_ul.last_tx_params().slice_id.has_value() and + not slices[h_ul.last_tx_params().slice_id->value()].inst.contains(ue_idx)) { + h_ul.cancel_harq_retxs(); + } + } } void slice_scheduler::rem_ue(du_ue_index_t ue_idx) @@ -118,17 +114,57 @@ void slice_scheduler::rem_ue(du_ue_index_t ue_idx) void slice_scheduler::config_applied(du_ue_index_t ue_idx) { - auto& u = ues[ue_idx]; - const ue_cell* ue_cc = u.find_cell(cell_cfg.cell_index); - srsran_assert(not ue_cc->is_in_fallback_mode(), "This function is only called when UE is not in fallback"); + ue* u = fetch_ue_to_update(ue_idx); + if (u == nullptr) { + logger.error("Config applied to a UE that is inactive or in fallback"); + return; + } // Add UE to slices. - for (const logical_channel_config& lc_cfg : u.ue_cfg_dedicated()->logical_channels()) { + add_impl(*u); +} + +void slice_scheduler::add_impl(const ue& u) +{ + const ue_configuration& ue_cfg = *u.ue_cfg_dedicated(); + for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg); sl_inst.add_logical_channel(u, lc_cfg.lcid, lc_cfg.lc_group); } } +ue* slice_scheduler::fetch_ue_to_update(du_ue_index_t ue_idx) +{ + if (not ues.contains(ue_idx)) { + // UE should be added to the repository at this stage. + logger.warning("ue={}: Not configuring UE to slice scheduler. Cause: No UE context found", ue_idx); + return nullptr; + } + + auto& u = ues[ue_idx]; + const ue_configuration& ue_cfg = *u.ue_cfg_dedicated(); + + // If UE does not have complete configuration, we won't be added to any slice. + if (not ue_cfg.is_ue_cfg_complete()) { + return nullptr; + } + + // If UE is in fallback mode, we do not add it to the slice scheduler. + const ue_cell* ue_cc = u.find_cell(cell_cfg.cell_index); + if (ue_cc == nullptr) { + logger.warning("ue={}: Not adding UE to slice scheduler. Cause: No UE context found in cell {}", + ue_cfg.ue_index, + cell_cfg.cell_index); + return nullptr; + } + if (ue_cc->is_in_fallback_mode()) { + // Do not include yet the UE in the slice scheduler. + return nullptr; + } + + return &u; +} + ran_slice_instance& slice_scheduler::get_slice(const logical_channel_config& lc_cfg) { // Return default SRB slice if LCID belongs to a SRB. diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index 1118f16402..be57405bf0 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -25,7 +25,7 @@ class slice_scheduler constexpr static priority_type skip_prio = 0; public: - slice_scheduler(const cell_configuration& cell_cfg_, const ue_repository& ues_); + slice_scheduler(const cell_configuration& cell_cfg_, ue_repository& ues_); /// Reset the state of the slices. void slot_indication(); @@ -109,13 +109,18 @@ class slice_scheduler ran_slice_instance& get_slice(const logical_channel_config& lc_cfg); + // Fetch UE if it is in a state to be added/reconfigured. + ue* fetch_ue_to_update(du_ue_index_t ue_idx); + + void add_impl(const ue& u); + template std::optional> get_next_candidate(); const cell_configuration& cell_cfg; srslog::basic_logger& logger; - const ue_repository& ues; + ue_repository& ues; std::vector slices; From c66475d26504774cd0753d5eeeebd87aed16230d Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 20 Aug 2024 12:10:36 +0200 Subject: [PATCH 305/407] sched: if HARQ has pending_retx, cancelling means that it gets reset --- lib/scheduler/ue_scheduling/harq_process.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/ue_scheduling/harq_process.cpp b/lib/scheduler/ue_scheduling/harq_process.cpp index 322e2ebced..8e1accec54 100644 --- a/lib/scheduler/ue_scheduling/harq_process.cpp +++ b/lib/scheduler/ue_scheduling/harq_process.cpp @@ -130,6 +130,13 @@ void detail::harq_process::cancel_harq_retxs(unsigned tb_idx) if (empty(tb_idx)) { return; } + if (has_pending_retx(tb_idx)) { + // If a retx is pending, do not allow it to take place. + tb_array[tb_idx].state = transport_block::state_t::empty; + return; + } + // If the HARQ is still waiting for an ACK to arrive, just mark it as max retxs have been exceeded. The ack_info + // function will automatically update the HARQ state. tb_array[tb_idx].max_nof_harq_retxs = tb_array[tb_idx].nof_retxs; tb_array[tb_idx].cancelled = true; } @@ -253,9 +260,13 @@ dl_harq_process::ack_info(uint32_t tb_idx, mac_harq_ack_report_status ack, std:: if (pucch_ack_to_receive <= 1) { // Case: This is the last HARQ-ACK that is expected for this HARQ process. - base_type::ack_info_common(tb_idx, chosen_ack == mac_harq_ack_report_status::ack); - if (chosen_ack != mac_harq_ack_report_status::ack and empty(tb_idx)) { - if (this->tb_array[0].cancelled) { + bool is_ack = chosen_ack == mac_harq_ack_report_status::ack; + base_type::ack_info_common(tb_idx, is_ack); + if (is_ack) { + return status_update::acked; + } + if (empty(tb_idx)) { + if (this->tb_array[tb_idx].cancelled) { logger.debug(id, "Discarding HARQ process tb={} with tbs={}. Cause: HARQ process was cancelled", tb_idx, @@ -268,7 +279,7 @@ dl_harq_process::ack_info(uint32_t tb_idx, mac_harq_ack_report_status ack, std:: max_nof_harq_retxs(tb_idx)); } } - return chosen_ack == mac_harq_ack_report_status::ack ? status_update::acked : status_update::nacked; + return status_update::nacked; } // Case: This is not the last PUCCH HARQ-ACK that is expected for this HARQ process. From f12f1508830f0f076656a151704709db98645c61 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 14 Aug 2024 10:58:12 +0200 Subject: [PATCH 306/407] phy: apply RAII to resource grid pool Revert exchange Review resource grid related phy: pass resource grids by const ref phy: review resource grid related du: fix tear down destruction ofh: fix task dispatcher support: fix task worker pool ofh: remove mutable phy: review resource grid copy usage phy: remove mutable from lambda functions --- apps/examples/phy/radio_ssb.cpp | 2 +- apps/examples/phy/rx_symbol_handler_example.h | 3 +- apps/examples/phy/upper_phy_ssb_example.cpp | 31 ++- .../du_low/du_low_config_translator.cpp | 1 - .../split_dynamic/dynamic_du_impl.h | 2 +- .../ofh/ofh_uplane_rx_symbol_notifier.h | 4 +- .../ofh/transmitter/ofh_downlink_handler.h | 4 +- .../transmitter/ofh_uplink_request_handler.h | 4 +- .../phy/adapters/phy_rg_gateway_adapter.h | 3 +- .../phy/adapters/phy_rx_symbol_adapter.h | 2 +- .../adapters/phy_rx_symbol_request_adapter.h | 4 +- .../phy/lower/lower_phy_request_handler.h | 3 +- .../srsran/phy/lower/lower_phy_rg_handler.h | 4 +- .../phy/lower/lower_phy_rx_symbol_notifier.h | 4 +- .../pdxch/pdxch_processor_request_handler.h | 4 +- .../uplink/puxch/puxch_processor_notifier.h | 4 +- .../puxch/puxch_processor_request_handler.h | 4 +- .../srsran/phy/support/resource_grid_pool.h | 11 +- .../phy/support/resource_grid_reader_empty.h | 82 -------- .../srsran/phy/support/shared_resource_grid.h | 188 ++++++++++++++++++ .../srsran/phy/support/support_factories.h | 4 +- include/srsran/phy/upper/downlink_processor.h | 6 +- include/srsran/phy/upper/uplink_processor.h | 7 +- .../phy/upper/uplink_request_processor.h | 3 +- .../srsran/phy/upper/upper_phy_factories.h | 2 - .../srsran/phy/upper/upper_phy_rg_gateway.h | 4 +- .../phy/upper/upper_phy_rx_symbol_handler.h | 4 +- .../upper_phy_rx_symbol_request_notifier.h | 3 +- include/srsran/ru/ru_adapters.h | 7 +- include/srsran/ru/ru_downlink_plane.h | 4 +- include/srsran/ru/ru_uplink_plane.h | 7 +- .../phy/fapi_to_phy_translator.cpp | 30 ++- .../receiver/ofh_closed_rx_window_handler.cpp | 11 +- ...fh_uplane_rx_symbol_data_flow_notifier.cpp | 4 +- .../ofh_uplane_rx_symbol_data_flow_writer.cpp | 6 +- lib/ofh/support/uplink_context_repository.h | 53 +++-- .../ofh_data_flow_uplane_downlink_data.h | 4 +- ...fh_data_flow_uplane_downlink_data_impl.cpp | 19 +- .../ofh_data_flow_uplane_downlink_data_impl.h | 4 +- ...ata_flow_uplane_downlink_task_dispatcher.h | 5 +- .../ofh_downlink_handler_broadcast_impl.cpp | 8 +- .../ofh_downlink_handler_broadcast_impl.h | 2 +- .../transmitter/ofh_downlink_handler_impl.cpp | 12 +- .../transmitter/ofh_downlink_handler_impl.h | 2 +- .../ofh_uplink_request_handler_impl.cpp | 4 +- .../ofh_uplink_request_handler_impl.h | 2 +- ...h_uplink_request_handler_task_dispatcher.h | 4 +- lib/phy/lower/lower_phy_impl.cpp | 1 - .../adaptors/processor_handler_adaptor.cpp | 5 +- .../adaptors/processor_handler_adaptor.h | 6 +- .../adaptors/processor_notifier_adaptor.cpp | 3 +- .../adaptors/processor_notifier_adaptor.h | 2 +- .../downlink/pdxch/pdxch_processor_impl.cpp | 31 +-- .../downlink/pdxch/pdxch_processor_impl.h | 19 +- .../processors/resource_grid_request_pool.h | 19 +- .../uplink/puxch/puxch_processor_impl.cpp | 29 +-- .../uplink/puxch/puxch_processor_impl.h | 17 +- lib/phy/support/CMakeLists.txt | 3 +- .../resource_grid_pool_asynchronous_impl.cpp | 111 ----------- .../resource_grid_pool_asynchronous_impl.h | 68 ------- .../resource_grid_pool_generic_impl.cpp | 30 --- .../support/resource_grid_pool_generic_impl.h | 42 ---- lib/phy/support/resource_grid_pool_impl.cpp | 135 +++++++++++++ lib/phy/support/resource_grid_pool_impl.h | 72 +++++++ lib/phy/support/support_factories.cpp | 10 +- ...ownlink_processor_single_executor_impl.cpp | 23 +-- .../downlink_processor_single_executor_impl.h | 5 +- lib/phy/upper/uplink_processor_impl.cpp | 22 +- lib/phy/upper/uplink_processor_impl.h | 6 +- .../upper/uplink_processor_task_dispatcher.h | 18 +- .../upper/uplink_request_processor_impl.cpp | 3 +- lib/phy/upper/uplink_request_processor_impl.h | 3 +- lib/phy/upper/upper_phy_factories.cpp | 3 +- .../upper_phy_rx_symbol_handler_impl.cpp | 5 +- .../upper/upper_phy_rx_symbol_handler_impl.h | 5 +- ..._phy_rx_symbol_handler_printer_decorator.h | 5 +- lib/ru/dummy/ru_dummy_impl.h | 4 +- lib/ru/dummy/ru_dummy_sector.h | 68 ++++--- .../ru_downlink_handler_generic_impl.cpp | 3 +- .../ru_downlink_handler_generic_impl.h | 3 +- ...ru_uplink_request_handler_generic_impl.cpp | 3 +- .../ru_uplink_request_handler_generic_impl.h | 3 +- lib/ru/generic/rx_symbol_adapter.h | 2 +- .../ru_ofh_downlink_plane_handler_proxy.cpp | 4 +- .../ofh/ru_ofh_downlink_plane_handler_proxy.h | 3 +- lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.cpp | 3 +- lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.h | 2 +- .../ofh/ru_ofh_uplink_plane_handler_proxy.cpp | 5 +- .../ofh/ru_ofh_uplink_plane_handler_proxy.h | 3 +- lib/support/executors/task_worker_pool.cpp | 2 +- tests/integrationtests/ofh/CMakeLists.txt | 7 +- .../ofh/ofh_integration_test.cpp | 56 ++++-- .../phy/fapi_to_phy_translator_test.cpp | 67 +++++-- ...h_uplane_rx_symbol_notifier_test_doubles.h | 3 +- tests/unittests/ofh/receiver/helpers.h | 20 +- ...data_flow_uplane_uplink_data_impl_test.cpp | 13 +- .../receiver/ofh_message_receiver_test.cpp | 3 +- ...lane_rx_symbol_data_flow_notifier_test.cpp | 35 ++-- ...uplane_rx_symbol_data_flow_writer_test.cpp | 74 ++++--- ...ta_flow_uplane_downlink_data_impl_test.cpp | 19 +- .../ofh_downlink_handler_impl_test.cpp | 44 ++-- .../ofh_uplink_request_handler_impl_test.cpp | 118 ++--------- tests/unittests/phy/lower/lower_phy_test.cpp | 35 +++- .../phy/lower/lower_phy_test_doubles.h | 4 +- .../downlink_processor_test_doubles.h | 4 +- .../downlink/pdxch/pdxch_processor_test.cpp | 44 ++-- .../pdxch/pdxch_processor_test_doubles.h | 3 +- .../puxch_processor_notifier_test_doubles.h | 7 +- .../uplink/puxch/puxch_processor_test.cpp | 31 +-- .../puxch/puxch_processor_test_doubles.h | 7 +- .../phy/support/resource_grid_pool_test.cpp | 45 ++--- .../phy/support/resource_grid_test_doubles.h | 71 +++++-- .../phy/upper/downlink_processor_test.cpp | 25 ++- .../upper/downlink_processor_test_doubles.h | 3 +- .../phy/upper/uplink_processor_test_doubles.h | 6 +- .../uplink_request_processor_test_doubles.h | 3 +- .../upper/upper_phy_rg_gateway_test_doubles.h | 3 +- .../upper_phy_rx_symbol_handler_test.cpp | 10 +- ..._rx_symbol_request_notifier_test_doubles.h | 3 +- 119 files changed, 1191 insertions(+), 966 deletions(-) delete mode 100644 include/srsran/phy/support/resource_grid_reader_empty.h create mode 100644 include/srsran/phy/support/shared_resource_grid.h delete mode 100644 lib/phy/support/resource_grid_pool_asynchronous_impl.cpp delete mode 100644 lib/phy/support/resource_grid_pool_asynchronous_impl.h delete mode 100644 lib/phy/support/resource_grid_pool_generic_impl.cpp delete mode 100644 lib/phy/support/resource_grid_pool_generic_impl.h create mode 100644 lib/phy/support/resource_grid_pool_impl.cpp create mode 100644 lib/phy/support/resource_grid_pool_impl.h diff --git a/apps/examples/phy/radio_ssb.cpp b/apps/examples/phy/radio_ssb.cpp index 4b00fe85b7..f123aaeb4d 100644 --- a/apps/examples/phy/radio_ssb.cpp +++ b/apps/examples/phy/radio_ssb.cpp @@ -258,9 +258,9 @@ static const auto profiles = to_array({ /// Global instances. static std::mutex stop_execution_mutex; static std::atomic stop = {false}; +static std::unique_ptr upper_phy = nullptr; static std::unique_ptr lower_phy_instance = nullptr; static std::unique_ptr radio = nullptr; -static std::unique_ptr upper_phy = nullptr; static void stop_execution() { diff --git a/apps/examples/phy/rx_symbol_handler_example.h b/apps/examples/phy/rx_symbol_handler_example.h index d97762e21c..d5e99abb8c 100644 --- a/apps/examples/phy/rx_symbol_handler_example.h +++ b/apps/examples/phy/rx_symbol_handler_example.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/phy/lower/lower_phy_timing_notifier.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/upper_phy_rx_symbol_handler.h" #include @@ -28,7 +29,7 @@ class rx_symbol_handler_example : public upper_phy_rx_symbol_handler logger.set_level(log_level); } - void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const resource_grid_reader& grid) override + void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const shared_resource_grid& grid) override { std::unique_lock lock(mutex); logger.debug(context.slot.sfn(), diff --git a/apps/examples/phy/upper_phy_ssb_example.cpp b/apps/examples/phy/upper_phy_ssb_example.cpp index 6e7c3e1157..8f234b6848 100644 --- a/apps/examples/phy/upper_phy_ssb_example.cpp +++ b/apps/examples/phy/upper_phy_ssb_example.cpp @@ -14,6 +14,7 @@ #include "srsran/phy/support/resource_grid_mapper.h" #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/support/resource_grid_writer.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/support/support_factories.h" #include "srsran/phy/upper/channel_processors/channel_processor_factories.h" #include "srsran/phy/upper/channel_processors/ssb_processor.h" @@ -117,10 +118,11 @@ class upper_phy_example_sw : public upper_phy_ssb_example // Request RX symbol if UL processing is enabled. if (enable_ul_processing) { resource_grid_context rx_symb_context; - rx_symb_context.sector = 0; - rx_symb_context.slot = context.slot; - resource_grid& rg = ul_rg_pool->get_resource_grid(rx_symb_context); - rx_symb_req_notifier->on_uplink_slot_request(rx_symb_context, rg); + rx_symb_context.sector = 0; + rx_symb_context.slot = context.slot; + shared_resource_grid rg = ul_rg_pool->allocate_resource_grid(rx_symb_context); + srsran_assert(rg, "Failed to fetch a resource grid."); + rx_symb_req_notifier->on_uplink_slot_request(rx_symb_context, std::move(rg)); } // Request PRACH capture if PRACH processing is enabled. @@ -150,10 +152,21 @@ class upper_phy_example_sw : public upper_phy_ssb_example rg_context.slot = context.slot; // Get a resource grid from the pool. - resource_grid& rg = dl_rg_pool->get_resource_grid(rg_context); + shared_resource_grid rg = dl_rg_pool->allocate_resource_grid(rg_context); + + // Abort slot processing if the grid is not valid. + if (!rg) { + logger.warning(context.slot.sfn(), context.slot.slot_index(), "Invalid resource grid."); + + // Raise TTI boundary and notify. + tti_boundary = true; + cvar_tti_boundary.notify_all(); + + return; + } // Set all the RE to zero. - rg.set_all_zero(); + rg.get().set_all_zero(); // Calculate SSB period in half-radio frame. unsigned ssb_period_hrf = ssb_config.period_ms / 5; @@ -182,7 +195,7 @@ class upper_phy_example_sw : public upper_phy_ssb_example pdu.bch_payload = {}; pdu.ports = {0}; - ssb->process(rg.get_writer(), pdu); + ssb->process(rg.get().get_writer(), pdu); logger.info("SSB: phys_cell_id={}; ssb_idx={};", pdu.phys_cell_id, pdu.ssb_idx); } } @@ -212,11 +225,11 @@ class upper_phy_example_sw : public upper_phy_ssb_example re_pattern grid_allocation(0, nof_subcs / NRE, 1, ~re_prb_mask(), ~symbol_slot_mask()); // Map the data symbols to the grid. - resource_grid_mapper& mapper = rg.get_mapper(); + resource_grid_mapper& mapper = rg->get_mapper(); mapper.map(data_symbols, grid_allocation, precoding_config); } - gateway->send(rg_context, rg.get_reader()); + gateway->send(rg_context, std::move(rg)); // Raise TTI boundary and notify. tti_boundary = true; 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 54f83696d1..c012ac3e9d 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 @@ -125,7 +125,6 @@ static void generate_du_low_config(du_low_config& out_config, upper_phy_cell.ldpc_decoder_iterations = du_low.expert_phy_cfg.pusch_decoder_max_iterations; upper_phy_cell.ldpc_decoder_early_stop = du_low.expert_phy_cfg.pusch_decoder_early_stop; upper_phy_cell.nof_dl_rg = dl_pipeline_depth + 2; - upper_phy_cell.dl_rg_expire_timeout_slots = dl_pipeline_depth; upper_phy_cell.nof_dl_processors = dl_pipeline_depth; upper_phy_cell.nof_ul_rg = ul_pipeline_depth; upper_phy_cell.max_ul_thread_concurrency = du_low.expert_execution_cfg.threads.nof_ul_threads + 1; diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_impl.h b/apps/units/flexible_du/split_dynamic/dynamic_du_impl.h index 00fd5dcea8..21629dd3c5 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_impl.h +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_impl.h @@ -48,10 +48,10 @@ class dynamic_du_impl : public du upper_ru_ul_adapter ru_ul_adapt; upper_ru_timing_adapter ru_timing_adapt; upper_ru_error_adapter ru_error_adapt; + std::vector> du_list; std::unique_ptr ru; upper_ru_dl_rg_adapter ru_dl_rg_adapt; upper_ru_ul_request_adapter ru_ul_request_adapt; - std::vector> du_list; }; } // namespace srsran diff --git a/include/srsran/ofh/ofh_uplane_rx_symbol_notifier.h b/include/srsran/ofh/ofh_uplane_rx_symbol_notifier.h index 2c2cd1427c..574480e3c9 100644 --- a/include/srsran/ofh/ofh_uplane_rx_symbol_notifier.h +++ b/include/srsran/ofh/ofh_uplane_rx_symbol_notifier.h @@ -15,7 +15,7 @@ namespace srsran { class prach_buffer; struct prach_buffer_context; -class resource_grid_reader; +class shared_resource_grid; namespace ofh { @@ -39,7 +39,7 @@ class uplane_rx_symbol_notifier /// /// \param[in] context Notification context. /// \param[in] grid Resource grid that belongs to the context. - virtual void on_new_uplink_symbol(const uplane_rx_symbol_context& context, const resource_grid_reader& grid) = 0; + virtual void on_new_uplink_symbol(const uplane_rx_symbol_context& context, shared_resource_grid grid) = 0; /// \brief Notifies the completion of a PRACH window. /// \param[in] context PRACH context. diff --git a/include/srsran/ofh/transmitter/ofh_downlink_handler.h b/include/srsran/ofh/transmitter/ofh_downlink_handler.h index 1bd0fcbcb1..5eaba35793 100644 --- a/include/srsran/ofh/transmitter/ofh_downlink_handler.h +++ b/include/srsran/ofh/transmitter/ofh_downlink_handler.h @@ -13,7 +13,7 @@ namespace srsran { struct resource_grid_context; -class resource_grid_reader; +class shared_resource_grid; namespace ofh { @@ -30,7 +30,7 @@ class downlink_handler /// /// \param[in] context Resource grid context. /// \param[in] grid Downlink data to transmit. - virtual void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) = 0; + virtual void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) = 0; /// Sets the error notifier of this sector to the given one. virtual void set_error_notifier(error_notifier& notifier) = 0; diff --git a/include/srsran/ofh/transmitter/ofh_uplink_request_handler.h b/include/srsran/ofh/transmitter/ofh_uplink_request_handler.h index c022317622..74c829b0fd 100644 --- a/include/srsran/ofh/transmitter/ofh_uplink_request_handler.h +++ b/include/srsran/ofh/transmitter/ofh_uplink_request_handler.h @@ -14,8 +14,8 @@ namespace srsran { class prach_buffer; struct prach_buffer_context; -class resource_grid; struct resource_grid_context; +class shared_resource_grid; namespace ofh { @@ -43,7 +43,7 @@ class uplink_request_handler /// /// \param[in] context Resource grid context. /// \param[in] buffer Resource grid to store the processed slot. - virtual void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) = 0; + virtual void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace ofh diff --git a/include/srsran/phy/adapters/phy_rg_gateway_adapter.h b/include/srsran/phy/adapters/phy_rg_gateway_adapter.h index 7a2b550699..99238412fb 100644 --- a/include/srsran/phy/adapters/phy_rg_gateway_adapter.h +++ b/include/srsran/phy/adapters/phy_rg_gateway_adapter.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/phy/lower/lower_phy_rg_handler.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/upper_phy_rg_gateway.h" namespace srsran { @@ -26,7 +27,7 @@ class phy_rg_gateway_adapter : public upper_phy_rg_gateway void connect(lower_phy_rg_handler* handler) { rg_handler = handler; } // See interface for documentation. - void send(const resource_grid_context& context, const resource_grid_reader& grid) override + void send(const resource_grid_context& context, const shared_resource_grid& grid) override { report_fatal_error_if_not(rg_handler, "Adapter is not connected."); rg_handler->handle_resource_grid(context, grid); diff --git a/include/srsran/phy/adapters/phy_rx_symbol_adapter.h b/include/srsran/phy/adapters/phy_rx_symbol_adapter.h index 7c7b0034d5..745434b67d 100644 --- a/include/srsran/phy/adapters/phy_rx_symbol_adapter.h +++ b/include/srsran/phy/adapters/phy_rx_symbol_adapter.h @@ -27,7 +27,7 @@ class phy_rx_symbol_adapter : public lower_phy_rx_symbol_notifier void connect(upper_phy_rx_symbol_handler* upper_handler) { rx_symbol_handler = upper_handler; } // See interface for documentation. - void on_rx_symbol(const lower_phy_rx_symbol_context& context, const resource_grid_reader& grid) override + void on_rx_symbol(const lower_phy_rx_symbol_context& context, const shared_resource_grid& grid) override { report_fatal_error_if_not(rx_symbol_handler, "Adapter is not connected."); upper_phy_rx_symbol_context upper_context; diff --git a/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h b/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h index 8378896dad..0c4bffb456 100644 --- a/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h +++ b/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h @@ -33,11 +33,11 @@ class phy_rx_symbol_request_adapter : public upper_phy_rx_symbol_request_notifie } // See interface for documentation. - void on_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) override + void on_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) override { report_fatal_error_if_not(rx_symbol_request_handler, "Adapter is not connected."); - rx_symbol_request_handler->request_uplink_slot(context, grid); + rx_symbol_request_handler->request_uplink_slot(context, std::move(grid)); } }; diff --git a/include/srsran/phy/lower/lower_phy_request_handler.h b/include/srsran/phy/lower/lower_phy_request_handler.h index e5ed9bf7a3..69adeeeec7 100644 --- a/include/srsran/phy/lower/lower_phy_request_handler.h +++ b/include/srsran/phy/lower/lower_phy_request_handler.h @@ -16,6 +16,7 @@ class resource_grid; class prach_buffer; struct prach_buffer_context; struct resource_grid_context; +class shared_resource_grid; /// \brief Describes the lower physical layer request handler. /// @@ -44,7 +45,7 @@ class lower_phy_request_handler /// /// \param[in] context Resource grid context. /// \param[in] grid Resource grid to store the processed slot. - virtual void request_uplink_slot(const resource_grid_context& context, resource_grid& grid) = 0; + virtual void request_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/lower/lower_phy_rg_handler.h b/include/srsran/phy/lower/lower_phy_rg_handler.h index 8c8bfaaed9..31128c4391 100644 --- a/include/srsran/phy/lower/lower_phy_rg_handler.h +++ b/include/srsran/phy/lower/lower_phy_rg_handler.h @@ -14,6 +14,8 @@ namespace srsran { +class shared_resource_grid; + /// \brief Lower physical layer resource grid handler interface. /// /// The resource grid handler modulates and transmits the given downlink resource grid through the underlying radio @@ -28,7 +30,7 @@ class lower_phy_rg_handler /// /// \param[in] context Resource grid context. /// \param[in] grid Resource grid to transmit. - virtual void handle_resource_grid(const resource_grid_context& context, const resource_grid_reader& grid) = 0; + virtual void handle_resource_grid(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/lower/lower_phy_rx_symbol_notifier.h b/include/srsran/phy/lower/lower_phy_rx_symbol_notifier.h index b2a3675760..a38ea02c26 100644 --- a/include/srsran/phy/lower/lower_phy_rx_symbol_notifier.h +++ b/include/srsran/phy/lower/lower_phy_rx_symbol_notifier.h @@ -12,10 +12,10 @@ namespace srsran { -class resource_grid_reader; class prach_buffer; struct lower_phy_rx_symbol_context; struct prach_buffer_context; +class shared_resource_grid; /// \brief Lower physical layer notifier for events related to received symbols. /// @@ -31,7 +31,7 @@ class lower_phy_rx_symbol_notifier /// /// \param[in] context Notification context. /// \param[in] grid Resource grid that belongs to the context. - virtual void on_rx_symbol(const lower_phy_rx_symbol_context& context, const resource_grid_reader& grid) = 0; + virtual void on_rx_symbol(const lower_phy_rx_symbol_context& context, const shared_resource_grid& grid) = 0; /// \brief Notifies the completion of PRACH window. /// diff --git a/include/srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_request_handler.h b/include/srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_request_handler.h index 5b6c2e3ac9..f15a15896a 100644 --- a/include/srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_request_handler.h +++ b/include/srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_request_handler.h @@ -13,7 +13,7 @@ namespace srsran { struct resource_grid_context; -class resource_grid_reader; +class shared_resource_grid; /// \brief Lower physical layer downlink processor - Request handler interface. /// @@ -32,7 +32,7 @@ class pdxch_processor_request_handler /// /// \param[in] grid Resource grid to transmit. /// \param[in] context Resource grid transmission context. - virtual void handle_request(const resource_grid_reader& grid, const resource_grid_context& context) = 0; + virtual void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) = 0; }; } // namespace srsran \ No newline at end of file diff --git a/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h b/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h index 49a711c909..594fe6d2e1 100644 --- a/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h +++ b/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h @@ -14,7 +14,7 @@ namespace srsran { struct lower_phy_rx_symbol_context; struct resource_grid_context; -class resource_grid_reader; +class shared_resource_grid; /// \brief Lower physical layer PUxCH processor - Notifier interface. /// @@ -37,7 +37,7 @@ class puxch_processor_notifier /// See \ref lower_phy_error_notifier::on_puxch_request_late for more information. /// \param[in] grid Received resource grid. /// \param[in] context Received symbol context. - virtual void on_rx_symbol(const resource_grid_reader& grid, const lower_phy_rx_symbol_context& context) = 0; + virtual void on_rx_symbol(const shared_resource_grid& grid, const lower_phy_rx_symbol_context& context) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_request_handler.h b/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_request_handler.h index 1450642884..7c695316b2 100644 --- a/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_request_handler.h +++ b/include/srsran/phy/lower/processors/uplink/puxch/puxch_processor_request_handler.h @@ -13,7 +13,7 @@ namespace srsran { struct resource_grid_context; -class resource_grid; +class shared_resource_grid; /// \brief Lower physical layer PUxCH processor - Request handler interface. /// @@ -32,7 +32,7 @@ class puxch_processor_request_handler /// /// \param[in] grid Destination uplink resource grid. /// \param[in] context Resource grid context. - virtual void handle_request(resource_grid& grid, const resource_grid_context& context) = 0; + virtual void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) = 0; }; } // namespace srsran \ No newline at end of file diff --git a/include/srsran/phy/support/resource_grid_pool.h b/include/srsran/phy/support/resource_grid_pool.h index 0b5d6c1977..1e35194833 100644 --- a/include/srsran/phy/support/resource_grid_pool.h +++ b/include/srsran/phy/support/resource_grid_pool.h @@ -12,20 +12,21 @@ #include "resource_grid.h" #include "resource_grid_context.h" +#include "shared_resource_grid.h" #include namespace srsran { -/// Describes a resource grid pool interface +/// Resource grid pool interface. class resource_grid_pool { public: - /// Default destructor + /// Default destructor. virtual ~resource_grid_pool() = default; - /// Get a resource grid for the given context - /// \param [in] context Provides the given context - virtual resource_grid& get_resource_grid(const resource_grid_context& context) = 0; + /// \brief Allocates a unique resource grid. + /// \param [in] context Allocation context. + virtual shared_resource_grid allocate_resource_grid(const resource_grid_context& context) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/support/resource_grid_reader_empty.h b/include/srsran/phy/support/resource_grid_reader_empty.h deleted file mode 100644 index 6c2deae215..0000000000 --- a/include/srsran/phy/support/resource_grid_reader_empty.h +++ /dev/null @@ -1,82 +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/phy/support/resource_grid_reader.h" -#include "srsran/srsvec/zero.h" - -namespace srsran { - -/// Defines an empty resource grid reader that behaves as it is filled with zeros. -class resource_grid_reader_empty : public resource_grid_reader -{ -public: - /// Creates an empty resource grid reader with the given dimensions. - resource_grid_reader_empty(unsigned nof_ports_, unsigned nof_symbols_, unsigned nof_prb_) : - nof_ports(nof_ports_), nof_symbols(nof_symbols_), nof_prb(nof_prb_) - { - } - - // See interface for documentation. - unsigned get_nof_ports() const override { return nof_ports; } - - // See interface for documentation. - unsigned get_nof_subc() const override { return nof_prb * NRE; } - - // See interface for documentation. - unsigned get_nof_symbols() const override { return nof_symbols; } - - // See interface for documentation. - bool is_empty(unsigned /**/) const override { return true; } - - // See interface for documentation. - bool is_empty() const override { return true; } - - // See interface for documentation. - span get(span symbols, - unsigned /**/, - unsigned /**/, - unsigned /**/, - const bounded_bitset& /**/) const override - { - srsvec::zero(symbols); - return {}; - } - - // See interface for documentation. - span get(span symbols, - unsigned /**/, - unsigned /**/, - unsigned /**/, - const bounded_bitset& /**/) const override - { - srsvec::zero(symbols); - return {}; - } - - // See interface for documentation. - void get(span symbols, unsigned /**/, unsigned /**/, unsigned /**/, unsigned /**/) const override - { - srsvec::zero(symbols); - } - - // See interface for documentation. - void get(span symbols, unsigned /**/, unsigned /**/, unsigned /**/) const override { srsvec::zero(symbols); } - - // See interface for documentation. - span get_view(unsigned /**/, unsigned /**/) const override { return {}; } - -private: - unsigned nof_ports; - unsigned nof_symbols; - unsigned nof_prb; -}; - -} // namespace srsran diff --git a/include/srsran/phy/support/shared_resource_grid.h b/include/srsran/phy/support/shared_resource_grid.h new file mode 100644 index 0000000000..a7e9251e3a --- /dev/null +++ b/include/srsran/phy/support/shared_resource_grid.h @@ -0,0 +1,188 @@ +/* + * + * 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/phy/support/resource_grid.h" +#include "srsran/support/srsran_assert.h" +#include + +namespace srsran { + +class resource_grid_reader; +class resource_grid_writer; + +/// \brief Unique resource grid. +/// +/// It feedbacks to the resource grid pool the destruction of the instance. +class shared_resource_grid +{ +public: + /// Resource grid pool interface. + class pool_interface + { + public: + /// Default destructor. + virtual ~pool_interface() = default; + + /// \brief Gets the reference to the resource grid from a given identifier. + /// + /// \param[in] identifier Internal pool resource grid identifier. + /// \return A reference to the selected resource grid. + /// \remark An assertion is triggered if the identifier is invalid. + virtual resource_grid& get(unsigned identifier) = 0; + + /// \brief Notifies the pool of the release of the resource grid. + /// + /// \param[in] identifier Internal pool resource grid identifier. + /// \remark An assertion is triggered if the identifier is invalid. + virtual void notify_release_scope(unsigned identifier) = 0; + }; + + /// Default constructor creates an invalid resource grid. + shared_resource_grid() = default; + + /// \brief Constructs a shared resource grid. + /// \param pool_ Reference to the resource grid pool. + /// \param ref_count_ Reference counter. + /// \param identifier_ Resource grid identifier within the pool. + shared_resource_grid(pool_interface& pool_, std::atomic& ref_count_, unsigned identifier_) : + pool(&pool_), ref_count(&ref_count_), identifier(identifier_) + { + } + + /// \brief Move constructor - moves the ownership of other resource grid. + /// + /// Copies the pool reference, reference count and grid identifier. It invalidates the other instance without . + shared_resource_grid(shared_resource_grid&& other) noexcept : + pool(std::exchange(other.pool, nullptr)), + ref_count(std::exchange(other.ref_count, nullptr)), + identifier(other.identifier) + { + } + + /// Overload copy assign operator is forbade to avoid copying unintentionally. + shared_resource_grid& operator=(const shared_resource_grid& other) = delete; + + /// \brief Overload move assign operator. + /// + /// It releases the current ownership and takes the ownership of the other instance. + shared_resource_grid& operator=(shared_resource_grid&& other) noexcept + { + // First release previous grid. + release(); + + // Overwrite with the other grid. + pool = other.pool; + ref_count = other.ref_count; + identifier = other.identifier; + + // Invalidate the other grid. + other.pool = nullptr; + other.ref_count = nullptr; + + return *this; + } + + /// Default destructor - It releases the resource grid identifier. + ~shared_resource_grid() { release(); } + + /// \brief Explicitly releases the resource grid. + /// + /// The last owner to release the grid shall notify the pool. + void release() + { + if (is_valid()) { + bool last = dec_ref_count(); + if (last) { + pool->notify_release_scope(identifier); + } + pool = nullptr; + ref_count = nullptr; + } + } + + /// Gets the resource grid. + resource_grid& get() + { + srsran_assert(is_valid(), "The resource grid is invalid."); + return pool->get(identifier); + } + + /// Gets the resource grid for read-only. + resource_grid& get() const + { + srsran_assert(pool != nullptr, "The resource grid is invalid."); + return pool->get(identifier); + } + + /// Gets the resource grid reader. + const resource_grid_reader& get_reader() const + { + srsran_assert(pool != nullptr, "The resource grid is invalid."); + return pool->get(identifier).get_reader(); + } + + /// Gets the resource grid writer. + resource_grid_writer& get_writer() const + { + srsran_assert(pool != nullptr, "The resource grid is invalid."); + return pool->get(identifier).get_writer(); + } + + /// Explicit copy of the resource grid. + shared_resource_grid copy() const { return shared_resource_grid(*this); } + + /// Accesses the resource grid pointer for read and write. + resource_grid* operator->() { return &get(); } + + /// Accesses the resource grid pointer for read-only. + const resource_grid& operator->() const { return get(); } + + /// Forbids reference operator to avoid changing the scope by reference. + resource_grid* operator&() = delete; + + /// \brief Determines whether the resource grid is valid. + /// + /// \return \c true if the pool and the reference counter are not \c nullptr. + bool is_valid() const { return (pool != nullptr) && (ref_count != nullptr); } + + /// \brief Overload conversion to bool. + /// \return \c true if the resource grid is valid. + explicit operator bool() const noexcept { return is_valid(); } + +private: + /// Copy constructor is explicit to avoid copying unintentionally. + explicit shared_resource_grid(const shared_resource_grid& other) noexcept : + pool(other.pool), ref_count(other.ref_count), identifier(other.identifier) + { + if (is_valid()) { + inc_ref_count(); + } + } + + /// \brief Decrement the reference counter. + /// \return \c true if it is the last. + /// \remark This method assumes the instance is valid. + bool dec_ref_count() { return ref_count->fetch_sub(1, std::memory_order::memory_order_acq_rel) == 1; } + + /// \brief Increases the reference count by one. + /// \remark This method assumes the instance is valid. + void inc_ref_count() { ref_count->fetch_add(1, std::memory_order::memory_order_relaxed); } + + /// Resource grid pool. Set to \c nullptr for invalid resource grid. + pool_interface* pool = nullptr; + /// Reference counter. Set to \c nullptr for invalid resource grid. + std::atomic* ref_count = nullptr; + /// Resource grid identifier within the resource grid pool. + unsigned identifier = 0; +}; + +} // namespace srsran diff --git a/include/srsran/phy/support/support_factories.h b/include/srsran/phy/support/support_factories.h index 351f6915fa..3dd90395ad 100644 --- a/include/srsran/phy/support/support_factories.h +++ b/include/srsran/phy/support/support_factories.h @@ -61,13 +61,11 @@ create_generic_resource_grid_pool(std::vector> gr /// The resource grid repetition is not deterministic but it is guaranteed that it is repeated after /// \c expire_timeout_slots. /// -/// \param[in] expire_timeout_slots Number of slots after which resource grids are expired. /// \param[in] async_executor Asynchronous task executor for setting the grid to zero. /// \param[in] grids Resource grids, ownerships are transferred to the pool. /// \return An asynchronous resource grid pool. std::unique_ptr -create_asynchronous_resource_grid_pool(unsigned expire_timeout_slots, - task_executor& async_executor, +create_asynchronous_resource_grid_pool(task_executor& async_executor, std::vector> grids); /// \brief Creates a long PRACH sequence buffer. diff --git a/include/srsran/phy/upper/downlink_processor.h b/include/srsran/phy/upper/downlink_processor.h index f3b7de8591..e8f227963f 100644 --- a/include/srsran/phy/upper/downlink_processor.h +++ b/include/srsran/phy/upper/downlink_processor.h @@ -18,7 +18,7 @@ namespace srsran { struct resource_grid_context; -class resource_grid; +class shared_resource_grid; class unique_tx_buffer; /// \brief Downlink processor class that groups and process all the downlink channels within a slot. @@ -62,14 +62,14 @@ class downlink_processor /// \brief Configures the resource grid of the downlink_processor. /// /// \param[in] context Resource grid context that contains the information of the processing slot. - /// \param[in] grid Resource grid that will contain the data of the processed downlink channels. + /// \param[in] grid Resource grid that will contain the data of the processed downlink channels. /// \return \c true if the resource grid is successfully configured, \c false otherwise. /// /// \note /// - Calling this method is mandatory before processing any PDU. /// - The resource grid number of ports and bandwidth must be sufficient to accommodate all the PDUs. // :TODO: move this method to other interface to avoid controlling the order of the methods execution. - virtual bool configure_resource_grid(const resource_grid_context& context, resource_grid& grid) = 0; + virtual bool configure_resource_grid(const resource_grid_context& context, shared_resource_grid grid) = 0; /// \brief Stops accepting PDUs. /// diff --git a/include/srsran/phy/upper/uplink_processor.h b/include/srsran/phy/upper/uplink_processor.h index 9be9ea3043..a4142adfcf 100644 --- a/include/srsran/phy/upper/uplink_processor.h +++ b/include/srsran/phy/upper/uplink_processor.h @@ -27,6 +27,7 @@ struct prach_buffer_context; class slot_point; class upper_phy_rx_results_notifier; struct srs_estimator_configuration; +class shared_resource_grid; /// \brief Uplink processor interface. /// @@ -102,7 +103,7 @@ class uplink_processor virtual void process_pusch(span data, unique_rx_buffer rm_buffer, upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::pusch_pdu& pdu) = 0; /// \brief Processes a PUCCH transmission. @@ -114,7 +115,7 @@ class uplink_processor /// \param[in] grid Resource grid. /// \param[in] pdu PUCCH transmission parameters. virtual void - process_pucch(upper_phy_rx_results_notifier& notifier, const resource_grid_reader& grid, const pucch_pdu& pdu) = 0; + process_pucch(upper_phy_rx_results_notifier& notifier, const shared_resource_grid& grid, const pucch_pdu& pdu) = 0; /// \brief Processes Sounding Reference Signals. /// @@ -125,7 +126,7 @@ class uplink_processor /// \param[in] grid UL resource grid containing the SRS RE. /// \param[in] pdu SRS configuration parameters. virtual void - process_srs(upper_phy_rx_results_notifier& notifier, const resource_grid_reader& grid, const srs_pdu& pdu) = 0; + process_srs(upper_phy_rx_results_notifier& notifier, const shared_resource_grid& grid, const srs_pdu& pdu) = 0; }; /// Uplink processor validation interface. diff --git a/include/srsran/phy/upper/uplink_request_processor.h b/include/srsran/phy/upper/uplink_request_processor.h index a968957c9f..8c97a2c32b 100644 --- a/include/srsran/phy/upper/uplink_request_processor.h +++ b/include/srsran/phy/upper/uplink_request_processor.h @@ -15,6 +15,7 @@ namespace srsran { struct prach_buffer_context; class resource_grid; struct resource_grid_context; +class shared_resource_grid; /// \brief Interface of the uplink request processor. /// @@ -38,7 +39,7 @@ class uplink_request_processor /// /// \param[in] context Resource grid context. /// \param[in] grid Grid in which to store the captured data. - virtual void process_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) = 0; + virtual void process_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/upper/upper_phy_factories.h b/include/srsran/phy/upper/upper_phy_factories.h index c3ba41e4d9..4ac02554c2 100644 --- a/include/srsran/phy/upper/upper_phy_factories.h +++ b/include/srsran/phy/upper/upper_phy_factories.h @@ -288,8 +288,6 @@ struct upper_phy_config { /// Number of downlink resource grids. Downlink resource grids minimum reuse time is \c dl_rg_expire_timeout_slots /// slots. unsigned nof_dl_rg; - /// Downlink resource grid timeout expiration in number of slots. - unsigned dl_rg_expire_timeout_slots; /// Number of uplink resource grids. They are reused after \c nof_ul_rg slots. unsigned nof_ul_rg; /// Number of PRACH buffer. diff --git a/include/srsran/phy/upper/upper_phy_rg_gateway.h b/include/srsran/phy/upper/upper_phy_rg_gateway.h index fc8fbdde35..ebf30c9779 100644 --- a/include/srsran/phy/upper/upper_phy_rg_gateway.h +++ b/include/srsran/phy/upper/upper_phy_rg_gateway.h @@ -14,6 +14,8 @@ namespace srsran { +class shared_resource_grid; + /// Interface of the upper physical layer resource grid gateway. class upper_phy_rg_gateway { @@ -25,7 +27,7 @@ class upper_phy_rg_gateway /// /// \param[in] context Context the resource grid belongs to. /// \param[in] grid Resource grid reader instance. - virtual void send(const resource_grid_context& context, const resource_grid_reader& grid) = 0; + virtual void send(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/upper/upper_phy_rx_symbol_handler.h b/include/srsran/phy/upper/upper_phy_rx_symbol_handler.h index 9759c303b7..3098ecd000 100644 --- a/include/srsran/phy/upper/upper_phy_rx_symbol_handler.h +++ b/include/srsran/phy/upper/upper_phy_rx_symbol_handler.h @@ -19,7 +19,7 @@ namespace srsran { class prach_buffer; struct prach_buffer_context; -class resource_grid_reader; +class shared_resource_grid; /// Describes the context of a newly received symbol. struct upper_phy_rx_symbol_context { @@ -41,7 +41,7 @@ class upper_phy_rx_symbol_handler /// \brief Handles the reception of an OFDM symbol. /// \param[in] context Notification context: specifies sector, slot and symbol. /// \param[in] grid Resource grid for the current slot (encompasses all receive antenna ports). - virtual void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const resource_grid_reader& grid) = 0; + virtual void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const shared_resource_grid& grid) = 0; /// \brief Handles the arrival of PRACH sequences. /// \param[in] context PRACH context: specifies sector, slot and window. diff --git a/include/srsran/phy/upper/upper_phy_rx_symbol_request_notifier.h b/include/srsran/phy/upper/upper_phy_rx_symbol_request_notifier.h index 0090ffbb3b..f112d7c214 100644 --- a/include/srsran/phy/upper/upper_phy_rx_symbol_request_notifier.h +++ b/include/srsran/phy/upper/upper_phy_rx_symbol_request_notifier.h @@ -18,6 +18,7 @@ namespace srsran { class prach_buffer; struct prach_buffer_context; class resource_grid; +class shared_resource_grid; struct resource_grid_context; /// \brief Interface of the upper-PHY notifier in charge of requesting symbol captures. @@ -36,7 +37,7 @@ class upper_phy_rx_symbol_request_notifier /// /// \param[in] context Resource grid context. /// \param[in] grid Grid in which to store the captured data. - virtual void on_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) = 0; + virtual void on_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/include/srsran/ru/ru_adapters.h b/include/srsran/ru/ru_adapters.h index 3471af33bb..cb75d4b8f0 100644 --- a/include/srsran/ru/ru_adapters.h +++ b/include/srsran/ru/ru_adapters.h @@ -15,6 +15,7 @@ #include "ru_timing_notifier.h" #include "ru_uplink_plane.h" #include "srsran/phy/support/prach_buffer_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/upper_phy_error_handler.h" #include "srsran/phy/upper/upper_phy_rg_gateway.h" #include "srsran/phy/upper/upper_phy_rx_symbol_handler.h" @@ -28,7 +29,7 @@ class upper_ru_dl_rg_adapter : public upper_phy_rg_gateway { public: // See interface for documentation. - void send(const resource_grid_context& context, const resource_grid_reader& grid) override + void send(const resource_grid_context& context, const shared_resource_grid& grid) override { srsran_assert(dl_handler, "Adapter is not connected."); dl_handler->handle_dl_data(context, grid); @@ -53,7 +54,7 @@ class upper_ru_ul_request_adapter : public upper_phy_rx_symbol_request_notifier } // See interface for documentation. - void on_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) override + void on_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) override { srsran_assert(ul_handler, "Adapter is not connected"); ul_handler->handle_new_uplink_slot(context, grid); @@ -73,7 +74,7 @@ class upper_ru_ul_adapter : public ru_uplink_plane_rx_symbol_notifier explicit upper_ru_ul_adapter(unsigned nof_sectors) : handlers(nof_sectors) {} // See interface for documentation. - void on_new_uplink_symbol(const ru_uplink_rx_symbol_context& context, const resource_grid_reader& grid) override + void on_new_uplink_symbol(const ru_uplink_rx_symbol_context& context, const shared_resource_grid& grid) override { srsran_assert(context.sector < handlers.size(), "Unsupported sector {}", context.sector); handlers[context.sector]->handle_rx_symbol({context.sector, context.slot, context.symbol_id}, grid); diff --git a/include/srsran/ru/ru_downlink_plane.h b/include/srsran/ru/ru_downlink_plane.h index 16e9041c91..17a414018e 100644 --- a/include/srsran/ru/ru_downlink_plane.h +++ b/include/srsran/ru/ru_downlink_plane.h @@ -15,7 +15,7 @@ namespace srsran { struct resource_grid_context; -class resource_grid_reader; +class shared_resource_grid; /// \brief Radio Unit resource grid handler interface. /// @@ -31,7 +31,7 @@ class ru_downlink_plane_handler /// /// \param[in] context Resource grid context. /// \param[in] grid Downlink data to transmit. - virtual void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) = 0; + virtual void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/include/srsran/ru/ru_uplink_plane.h b/include/srsran/ru/ru_uplink_plane.h index 1dfb116a5a..dbab2cefe2 100644 --- a/include/srsran/ru/ru_uplink_plane.h +++ b/include/srsran/ru/ru_uplink_plane.h @@ -16,9 +16,8 @@ namespace srsran { class prach_buffer; struct prach_buffer_context; -class resource_grid; struct resource_grid_context; -class resource_grid_reader; +class shared_resource_grid; /// Radio Unit uplink received symbol context. struct ru_uplink_rx_symbol_context { @@ -44,7 +43,7 @@ class ru_uplink_plane_rx_symbol_notifier /// /// \param[in] context Notification context. /// \param[in] grid Resource grid that belongs to the context. - virtual void on_new_uplink_symbol(const ru_uplink_rx_symbol_context& context, const resource_grid_reader& grid) = 0; + virtual void on_new_uplink_symbol(const ru_uplink_rx_symbol_context& context, const shared_resource_grid& grid) = 0; /// \brief Notifies the completion of a PRACH window. /// @@ -82,7 +81,7 @@ class ru_uplink_plane_handler /// /// \param[in] context Resource grid context. /// \param[in] buffer Resource grid to store the processed slot. - virtual void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) = 0; + virtual void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) = 0; }; } // namespace srsran diff --git a/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp b/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp index 0d23ae9d76..0731cb5b65 100644 --- a/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp +++ b/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp @@ -21,6 +21,7 @@ #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/phy/support/prach_buffer_context.h" #include "srsran/phy/support/resource_grid_pool.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/downlink_processor.h" #include "srsran/phy/upper/uplink_request_processor.h" #include "srsran/phy/upper/uplink_slot_pdu_repository.h" @@ -51,7 +52,10 @@ class downlink_processor_dummy : public downlink_processor { srslog::fetch_basic_logger("FAPI").warning("Could not enqueue NZP-CSI-RS PDU in the downlink processor"); } - bool configure_resource_grid(const resource_grid_context& context, resource_grid& grid) override { return true; } + bool configure_resource_grid(const resource_grid_context& context, shared_resource_grid grid) override + { + return true; + } void finish_processing_pdus() override {} }; @@ -116,10 +120,16 @@ fapi_to_phy_translator::slot_based_upper_phy_controller::slot_based_upper_phy_co // FIXME: 0 is hardcoded as the sector as in this implementation there is one DU per sector, so each DU have its own // resource grid pool and downlink processor pool. It is also in the previous get processor call of the downlink // processor pool - resource_grid& grid = rg_pool.get_resource_grid({slot_, 0}); + shared_resource_grid grid = rg_pool.allocate_resource_grid({slot_, 0}); + + // If the resource grid is not valid, all DL transmissions for this slot shall be discarded. + if (!grid) { + dl_processor = dummy_dl_processor; + return; + } // Configure the downlink processor. - bool success = dl_processor.get().configure_resource_grid(context, grid); + bool success = dl_processor.get().configure_resource_grid(context, std::move(grid)); // Swap the DL processor with a dummy if it failed to configure the resource grid. if (!success) { @@ -512,9 +522,19 @@ void fapi_to_phy_translator::ul_tti_request(const fapi::ul_tti_request_message& // Get ul_resource_grid. resource_grid_context pool_context = rg_context; pool_context.sector = 0; - resource_grid& ul_rg = ul_rg_pool.get_resource_grid(pool_context); + shared_resource_grid ul_rg = ul_rg_pool.allocate_resource_grid(pool_context); + + // Abort UL processing for this slot if the resource grid is not available. + if (!ul_rg) { + logger.warning("Failed to allocate UL resource grid for UL_TTI.request from slot {}.{}", msg.sfn, msg.slot); + // Raise out of message transmit error. + error_notifier.get().on_error_indication(fapi::build_msg_tx_error_indication(msg.sfn, msg.slot)); + l1_tracer << instant_trace_event{"ul_tti_failed_grid", instant_trace_event::cpu_scope::global}; + return; + } + // Request to capture uplink slot. - ul_request_processor.process_uplink_slot_request(rg_context, ul_rg); + ul_request_processor.process_uplink_slot_request(rg_context, std::move(ul_rg)); l1_tracer << trace_event("ul_tti_request", tp); } diff --git a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp index 42d63dd61a..0551036bc0 100644 --- a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp +++ b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp @@ -43,16 +43,17 @@ void closed_rx_window_handler::on_new_symbol(slot_symbol_point symbol_point) void closed_rx_window_handler::handle_uplink_context(slot_symbol_point symbol_point) { - const auto& context = uplink_repo->pop_resource_grid_symbol(symbol_point.get_slot(), symbol_point.get_symbol_index()); + expected context = + uplink_repo->pop_resource_grid_symbol(symbol_point.get_slot(), symbol_point.get_symbol_index()); if (!context.has_value()) { return; } - const auto ctx_value = context.value(); - uplane_rx_symbol_context notification_context = { - ctx_value.context.slot, symbol_point.get_symbol_index(), ctx_value.context.sector}; - notifier->on_new_uplink_symbol(notification_context, ctx_value.grid->get_reader()); + uplink_context::uplink_context_resource_grid_info& ctx_value = context.value(); + uplane_rx_symbol_context notification_context = { + ctx_value.context.slot, symbol_point.get_symbol_index(), ctx_value.context.sector}; + notifier->on_new_uplink_symbol(notification_context, std::move(ctx_value.grid)); if (log_unreceived_messages) { logger.warning("Missed incoming User-Plane uplink messages for slot '{}', symbol '{}' and sector#{}", diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp index 521b3f2bc4..666eda7cda 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier.cpp @@ -23,9 +23,9 @@ void uplane_rx_symbol_data_flow_notifier::notify_received_symbol(slot_point slot return; } - const auto ctx_value = context.value(); + uplink_context::uplink_context_resource_grid_info& ctx_value = context.value(); uplane_rx_symbol_context notification_context = {ctx_value.context.slot, symbol, ctx_value.context.sector}; - notifier->on_new_uplink_symbol(notification_context, ctx_value.grid->get_reader()); + notifier->on_new_uplink_symbol(notification_context, std::move(ctx_value.grid)); logger.debug("Notifying UL symbol in slot '{}', symbol '{}' for sector#{}", notification_context.slot, diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp index 691ca53416..61901ec1b3 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp @@ -20,9 +20,9 @@ void uplane_rx_symbol_data_flow_writer::write_to_resource_grid(unsigned { trace_point access_repo_tp = ofh_tracer.now(); - slot_point slot = results.params.slot; - unsigned symbol = results.params.symbol_id; - uplink_context ul_context = ul_context_repo->get(slot, symbol); + slot_point slot = results.params.slot; + unsigned symbol = results.params.symbol_id; + const uplink_context& ul_context = ul_context_repo->get(slot, symbol); if (ul_context.empty()) { logger.warning("Dropped received Open Fronthaul message as no uplink slot context was found for slot '{}', symbol " "'{}' and eAxC '{}'", diff --git a/lib/ofh/support/uplink_context_repository.h b/lib/ofh/support/uplink_context_repository.h index e299f3113a..4352ddc31b 100644 --- a/lib/ofh/support/uplink_context_repository.h +++ b/lib/ofh/support/uplink_context_repository.h @@ -14,7 +14,9 @@ #include "srsran/ofh/ofh_constants.h" #include "srsran/phy/support/resource_grid.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/support/resource_grid_writer.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/cyclic_prefix.h" #include "srsran/ran/resource_allocation/ofdm_symbol_range.h" #include "srsran/ran/resource_block.h" @@ -31,28 +33,39 @@ class uplink_context /// Information related to the resource grid stored in the uplink context. struct uplink_context_resource_grid_info { resource_grid_context context; - resource_grid* grid = nullptr; + shared_resource_grid grid; }; /// Default constructor. uplink_context() = default; + uplink_context copy() const + { + uplink_context context; + context.symbol = symbol; + context.grid.context = grid.context; + context.grid.grid = grid.grid.copy(); + context.re_written = re_written; + return context; + } + /// Constructs an uplink slot context with the given resource grid and resource grid context. - uplink_context(unsigned symbol_, const resource_grid_context& context_, resource_grid& grid_) : - symbol(symbol_), grid({context_, &grid_}) + uplink_context(unsigned symbol_, const resource_grid_context& context_, const shared_resource_grid& grid_) : + symbol(symbol_), grid({context_, grid_.copy()}) { + const resource_grid_reader& reader = grid.grid->get_reader(); + re_written = static_vector, MAX_NOF_SUPPORTED_EAXC>( - grid_.get_writer().get_nof_ports(), - bounded_bitset(size_t(grid_.get_writer().get_nof_subc()))); + reader.get_nof_ports(), bounded_bitset(size_t(reader.get_nof_subc()))); } /// Returns true if this context is empty, otherwise false. - bool empty() const { return grid.grid == nullptr; } + bool empty() const { return !grid.grid.is_valid(); } /// Returns the number of PRBs of the context grid or zero if no grid was configured for this context. unsigned get_grid_nof_prbs() const { - return (grid.grid) ? (grid.grid->get_writer().get_nof_subc() / NOF_SUBCARRIERS_PER_RB) : 0U; + return (grid.grid) ? (grid.grid.get_reader().get_nof_subc() / NOF_SUBCARRIERS_PER_RB) : 0U; } /// Returns the resource grid context. @@ -66,9 +79,10 @@ class uplink_context void write_grid(unsigned port, unsigned start_re, span re_iq_buffer) { srsran_assert(grid.grid, "Invalid resource grid"); + resource_grid_writer& writer = grid.grid->get_writer(); // Skip writing if the given port does not fit in the grid. - if (port >= grid.grid->get_writer().get_nof_ports()) { + if (port >= writer.get_nof_ports()) { return; } span grid_view = grid.grid->get_writer().get_view(port, symbol).subspan(start_re, re_iq_buffer.size()); @@ -88,12 +102,15 @@ class uplink_context return make_unexpected(default_error_t{}); } - return {grid}; + return uplink_context_resource_grid_info{grid.context, grid.grid.copy()}; } /// Returns the context grid information. const uplink_context_resource_grid_info& get_uplink_context_resource_grid_info() const { return grid; } + /// Gets the context grid information and clears it. + uplink_context_resource_grid_info pop_uplink_context_resource_grid_info() { return std::move(grid); } + private: /// Returns true when all the REs for the current symbol have been written. bool have_all_prbs_been_written() const @@ -142,7 +159,8 @@ class uplink_context_repository explicit uplink_context_repository(unsigned size_) : buffer(size_) {} /// Adds the given entry to the repository at slot. - void add(const resource_grid_context& context, resource_grid& grid, const ofdm_symbol_range& symbol_range) + void + add(const resource_grid_context& context, const shared_resource_grid& grid, const ofdm_symbol_range& symbol_range) { std::lock_guard lock(mutex); @@ -163,7 +181,7 @@ class uplink_context_repository uplink_context get(slot_point slot, unsigned symbol) const { std::lock_guard lock(mutex); - return entry(slot, symbol); + return entry(slot, symbol).copy(); } /// \brief Tries to pop a complete resource grid for the given slot and symbol. @@ -174,7 +192,7 @@ class uplink_context_repository { std::lock_guard lock(mutex); - const auto result = entry(slot, symbol).try_getting_complete_resource_grid(); + auto result = entry(slot, symbol).try_getting_complete_resource_grid(); // Symbol is complete or exists. Clear the context. if (result.has_value()) { @@ -189,19 +207,16 @@ class uplink_context_repository { std::lock_guard lock(mutex); - const auto& result = entry(slot, symbol); + auto& result = entry(slot, symbol); // Symbol does not exists. Do nothing. if (result.empty()) { return make_unexpected(default_error_t{}); } - const auto info = result.get_uplink_context_resource_grid_info(); - - // Clear the symbol. - entry(slot, symbol) = {}; - - return {info}; + // Pop and clear the slot/symbol information. + uplink_context::uplink_context_resource_grid_info info = result.pop_uplink_context_resource_grid_info(); + return info; } /// Clears the repository entry for the given slot and symbol. diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data.h b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data.h index 97dd4ff1a6..ce8977fb1f 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data.h +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data.h @@ -15,7 +15,7 @@ namespace srsran { struct resource_grid_context; -class resource_grid_reader; +class shared_resource_grid; namespace ofh { @@ -42,7 +42,7 @@ class data_flow_uplane_downlink_data /// Enqueues the User-Plane downlink data messages with the given context and resource grid. virtual void enqueue_section_type_1_message(const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid) = 0; + const shared_resource_grid& grid) = 0; }; } // namespace ofh diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp index 22bb871e9e..3f371d4675 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp @@ -13,6 +13,7 @@ #include "scoped_frame_buffer.h" #include "srsran/phy/support/resource_grid_context.h" #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/resource_block.h" #include "srsran/srsvec/conversion.h" #include @@ -82,23 +83,25 @@ data_flow_uplane_downlink_data_impl::data_flow_uplane_downlink_data_impl( void data_flow_uplane_downlink_data_impl::enqueue_section_type_1_message( const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { trace_point tp = ofh_tracer.now(); - enqueue_section_type_1_message_symbol_burst(context, grid); + enqueue_section_type_1_message_symbol_burst(context, std::move(grid)); ofh_tracer << trace_event(formatted_trace_names[context.eaxc].c_str(), tp); } void data_flow_uplane_downlink_data_impl::enqueue_section_type_1_message_symbol_burst( const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { + const resource_grid_reader& reader = grid.get_reader(); + // Temporary buffer used to store IQ data when the RU operating bandwidth is not the same to the cell bandwidth. std::array temp_buffer; - if (SRSRAN_UNLIKELY(ru_nof_prbs * NOF_SUBCARRIERS_PER_RB != grid.get_nof_subc())) { + if (SRSRAN_UNLIKELY(ru_nof_prbs * NOF_SUBCARRIERS_PER_RB != reader.get_nof_subc())) { // Zero out the elements that won't be filled after reading the resource grid. - std::fill(temp_buffer.begin() + grid.get_nof_subc(), temp_buffer.end(), 0); + std::fill(temp_buffer.begin() + reader.get_nof_subc(), temp_buffer.end(), 0); } units::bytes headers_size = eth_builder->get_header_size() + @@ -123,11 +126,11 @@ void data_flow_uplane_downlink_data_impl::enqueue_section_type_1_message_symbol_ ofh_tracer << trace_event("ofh_uplane_pool_access", pool_access_tp); span iq_data; - if (SRSRAN_LIKELY(ru_nof_prbs * NOF_SUBCARRIERS_PER_RB == grid.get_nof_subc())) { - iq_data = grid.get_view(context.port, symbol_id); + if (SRSRAN_LIKELY(ru_nof_prbs * NOF_SUBCARRIERS_PER_RB == reader.get_nof_subc())) { + iq_data = reader.get_view(context.port, symbol_id); } else { span temp_iq_data(temp_buffer.data(), ru_nof_prbs * NOF_SUBCARRIERS_PER_RB); - grid.get(temp_iq_data.first(grid.get_nof_subc()), context.port, symbol_id, 0); + reader.get(temp_iq_data.first(reader.get_nof_subc()), context.port, symbol_id, 0); iq_data = temp_iq_data; } diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.h b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.h index f81181b1ee..d499a18bf9 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.h +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.h @@ -95,12 +95,12 @@ class data_flow_uplane_downlink_data_impl : public data_flow_uplane_downlink_dat // See interface for documentation. void enqueue_section_type_1_message(const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid) override; + const shared_resource_grid& grid) override; private: /// Enqueues an User-Plane message burst. void enqueue_section_type_1_message_symbol_burst(const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid); + const shared_resource_grid& grid); /// Enqueues an User-Plane message symbol with the given context and grid. unsigned enqueue_section_type_1_message_symbol(span iq_symbol_data, diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_task_dispatcher.h b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_task_dispatcher.h index 579bc627df..cb3edc3ebb 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_task_dispatcher.h +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_task_dispatcher.h @@ -11,6 +11,7 @@ #pragma once #include "ofh_data_flow_uplane_downlink_data.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/support/executors/task_executor.h" #include @@ -30,10 +31,10 @@ class data_flow_uplane_downlink_task_dispatcher : public data_flow_uplane_downli // See interface for documentation. void enqueue_section_type_1_message(const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid) override + const shared_resource_grid& grid) override { if (!executor.execute( - [this, context, &grid]() { data_flow_uplane->enqueue_section_type_1_message(context, grid); })) { + [this, context, rg = grid.copy()]() { data_flow_uplane->enqueue_section_type_1_message(context, rg); })) { srslog::fetch_basic_logger("OFH").warning( "Failed to dispatch message in the downlink data flow User-Plane for slot '{}'", context.slot); } diff --git a/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.cpp b/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.cpp index 61e7ff83a1..f1ab4ea3ad 100644 --- a/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.cpp +++ b/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.cpp @@ -14,6 +14,7 @@ #include "srsran/ofh/ofh_error_notifier.h" #include "srsran/phy/support/resource_grid_context.h" #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; using namespace ofh; @@ -56,9 +57,10 @@ downlink_handler_broadcast_impl::downlink_handler_broadcast_impl( } void downlink_handler_broadcast_impl::handle_dl_data(const resource_grid_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { - trace_point tp = ofh_tracer.now(); + const resource_grid_reader& reader = grid.get_reader(); + trace_point tp = ofh_tracer.now(); // Clear any stale buffers associated with the context slot. frame_pool->clear_downlink_slot(context.slot, logger); @@ -80,7 +82,7 @@ void downlink_handler_broadcast_impl::handle_dl_data(const resource_grid_context cplane_context.direction = data_direction::downlink; cplane_context.symbol_range = tdd_config ? get_active_tdd_dl_symbols(tdd_config.value(), context.slot.slot_index(), cp) - : ofdm_symbol_range(0, grid.get_nof_symbols()); + : ofdm_symbol_range(0, reader.get_nof_symbols()); data_flow_uplane_resource_grid_context uplane_context; uplane_context.slot = context.slot; diff --git a/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h b/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h index 4caffde036..b8a3815661 100644 --- a/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h +++ b/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h @@ -64,7 +64,7 @@ class downlink_handler_broadcast_impl : public downlink_handler downlink_handler_broadcast_impl_dependencies&& dependencies); // See interface for documentation. - void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override; + void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) override; // See interface for documentation. void set_error_notifier(error_notifier& notifier) override { err_notifier = std::ref(notifier); } diff --git a/lib/ofh/transmitter/ofh_downlink_handler_impl.cpp b/lib/ofh/transmitter/ofh_downlink_handler_impl.cpp index f918616ae4..4d3c69aae9 100644 --- a/lib/ofh/transmitter/ofh_downlink_handler_impl.cpp +++ b/lib/ofh/transmitter/ofh_downlink_handler_impl.cpp @@ -15,6 +15,7 @@ #include "srsran/ofh/ofh_error_notifier.h" #include "srsran/phy/support/resource_grid_context.h" #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; using namespace ofh; @@ -54,12 +55,13 @@ downlink_handler_impl::downlink_handler_impl(const downlink_handler_impl_config& srsran_assert(frame_pool, "Invalid frame pool"); } -void downlink_handler_impl::handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) +void downlink_handler_impl::handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) { - srsran_assert(grid.get_nof_ports() <= dl_eaxc.size(), + const resource_grid_reader& reader = grid.get_reader(); + srsran_assert(reader.get_nof_ports() <= dl_eaxc.size(), "Number of RU ports is '{}' and must be equal or greater than the number of cell ports which is '{}'", dl_eaxc.size(), - grid.get_nof_ports()); + reader.get_nof_ports()); trace_point tp = ofh_tracer.now(); @@ -84,14 +86,14 @@ void downlink_handler_impl::handle_dl_data(const resource_grid_context& context, cplane_context.direction = data_direction::downlink; cplane_context.symbol_range = tdd_config ? get_active_tdd_dl_symbols(tdd_config.value(), context.slot.slot_index(), cp) - : ofdm_symbol_range(0, grid.get_nof_symbols()); + : ofdm_symbol_range(0, reader.get_nof_symbols()); data_flow_uplane_resource_grid_context uplane_context; uplane_context.slot = context.slot; uplane_context.sector = context.sector; uplane_context.symbol_range = cplane_context.symbol_range; - for (unsigned cell_port_id = 0, e = grid.get_nof_ports(); cell_port_id != e; ++cell_port_id) { + for (unsigned cell_port_id = 0, e = reader.get_nof_ports(); cell_port_id != e; ++cell_port_id) { cplane_context.eaxc = dl_eaxc[cell_port_id]; // Control-Plane data flow. data_flow_cplane->enqueue_section_type_1_message(cplane_context); diff --git a/lib/ofh/transmitter/ofh_downlink_handler_impl.h b/lib/ofh/transmitter/ofh_downlink_handler_impl.h index 4942ce4516..6785418ee4 100644 --- a/lib/ofh/transmitter/ofh_downlink_handler_impl.h +++ b/lib/ofh/transmitter/ofh_downlink_handler_impl.h @@ -61,7 +61,7 @@ class downlink_handler_impl : public downlink_handler downlink_handler_impl(const downlink_handler_impl_config& config, downlink_handler_impl_dependencies&& dependencies); // See interface for documentation. - void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override; + void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) override; // See interface for documentation. void set_error_notifier(error_notifier& notifier) override { err_notifier = std::ref(notifier); } diff --git a/lib/ofh/transmitter/ofh_uplink_request_handler_impl.cpp b/lib/ofh/transmitter/ofh_uplink_request_handler_impl.cpp index 8cdb18bc90..9888039a35 100644 --- a/lib/ofh/transmitter/ofh_uplink_request_handler_impl.cpp +++ b/lib/ofh/transmitter/ofh_uplink_request_handler_impl.cpp @@ -9,6 +9,7 @@ */ #include "ofh_uplink_request_handler_impl.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/prach/prach_configuration.h" #include "srsran/ran/prach/prach_frequency_mapping.h" #include "srsran/ran/prach/prach_preamble_information.h" @@ -167,7 +168,8 @@ void uplink_request_handler_impl::handle_prach_occasion(const prach_buffer_conte } } -void uplink_request_handler_impl::handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) +void uplink_request_handler_impl::handle_new_uplink_slot(const resource_grid_context& context, + const shared_resource_grid& grid) { logger.debug("Registering UL context entry for slot '{}' and sector#{}", context.slot, context.sector); diff --git a/lib/ofh/transmitter/ofh_uplink_request_handler_impl.h b/lib/ofh/transmitter/ofh_uplink_request_handler_impl.h index faae067695..9c69c1c45d 100644 --- a/lib/ofh/transmitter/ofh_uplink_request_handler_impl.h +++ b/lib/ofh/transmitter/ofh_uplink_request_handler_impl.h @@ -60,7 +60,7 @@ class uplink_request_handler_impl : public uplink_request_handler void handle_prach_occasion(const prach_buffer_context& context, prach_buffer& buffer) override; // See interface for documentation. - void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) override; + void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override; private: srslog::basic_logger& logger; diff --git a/lib/ofh/transmitter/ofh_uplink_request_handler_task_dispatcher.h b/lib/ofh/transmitter/ofh_uplink_request_handler_task_dispatcher.h index 814d74e67c..f2e447eecd 100644 --- a/lib/ofh/transmitter/ofh_uplink_request_handler_task_dispatcher.h +++ b/lib/ofh/transmitter/ofh_uplink_request_handler_task_dispatcher.h @@ -37,9 +37,9 @@ class uplink_request_handler_task_dispatcher : public uplink_request_handler } // See interface for documentation. - void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) override + void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override { - if (!executor.execute([this, context, &grid]() { ul_handler->handle_new_uplink_slot(context, grid); })) { + if (!executor.execute([this, context, rg = grid.copy()]() { ul_handler->handle_new_uplink_slot(context, rg); })) { srslog::fetch_basic_logger("OFH").warning("Failed to dispatch new uplink slot for slot '{}'", context.slot); } } diff --git a/lib/phy/lower/lower_phy_impl.cpp b/lib/phy/lower/lower_phy_impl.cpp index 78aad48a1f..8ba06095bb 100644 --- a/lib/phy/lower/lower_phy_impl.cpp +++ b/lib/phy/lower/lower_phy_impl.cpp @@ -10,7 +10,6 @@ #include "lower_phy_impl.h" #include "srsran/phy/lower/lower_phy_rx_symbol_context.h" -#include "srsran/phy/support/resource_grid_reader_empty.h" using namespace srsran; diff --git a/lib/phy/lower/processors/adaptors/processor_handler_adaptor.cpp b/lib/phy/lower/processors/adaptors/processor_handler_adaptor.cpp index 97c48f8132..e1586f6b18 100644 --- a/lib/phy/lower/processors/adaptors/processor_handler_adaptor.cpp +++ b/lib/phy/lower/processors/adaptors/processor_handler_adaptor.cpp @@ -9,11 +9,12 @@ */ #include "processor_handler_adaptor.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; void processor_handler_adaptor::rg_handler_adaptor::handle_resource_grid(const resource_grid_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { pdxch_handler.handle_request(grid, context); } @@ -25,7 +26,7 @@ void processor_handler_adaptor::request_handler_adaptor::request_prach_window(co } void processor_handler_adaptor::request_handler_adaptor::request_uplink_slot(const resource_grid_context& context, - resource_grid& grid) + const shared_resource_grid& grid) { puxch_handler.handle_request(grid, context); } diff --git a/lib/phy/lower/processors/adaptors/processor_handler_adaptor.h b/lib/phy/lower/processors/adaptors/processor_handler_adaptor.h index 14ffae2aeb..96348b4ddb 100644 --- a/lib/phy/lower/processors/adaptors/processor_handler_adaptor.h +++ b/lib/phy/lower/processors/adaptors/processor_handler_adaptor.h @@ -18,6 +18,8 @@ namespace srsran { +class shared_resource_grid; + /// Adapts the lower physical layer handlers to the internal processors request handlers. class processor_handler_adaptor { @@ -45,7 +47,7 @@ class processor_handler_adaptor rg_handler_adaptor(pdxch_processor_request_handler& pdxch_handler_) : pdxch_handler(pdxch_handler_) {} // See interface for documentation. - void handle_resource_grid(const resource_grid_context& context, const resource_grid_reader& grid) override; + void handle_resource_grid(const resource_grid_context& context, const shared_resource_grid& grid) override; private: /// Actual PDxCH processor request handler. @@ -67,7 +69,7 @@ class processor_handler_adaptor void request_prach_window(const prach_buffer_context& context, prach_buffer& buffer) override; // See interface for documentation. - void request_uplink_slot(const resource_grid_context& context, resource_grid& grid) override; + void request_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override; private: /// Actual PRACH processor request handler. diff --git a/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.cpp b/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.cpp index c89c1e6fb4..a555478c5c 100644 --- a/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.cpp +++ b/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.cpp @@ -10,6 +10,7 @@ #include "processor_notifier_adaptor.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/support/srsran_assert.h" using namespace srsran; @@ -75,7 +76,7 @@ void processor_notifier_adaptor::puxch_adaptor::on_puxch_request_late(const reso error_notifier->on_puxch_request_late(context); } -void processor_notifier_adaptor::puxch_adaptor::on_rx_symbol(const resource_grid_reader& grid, +void processor_notifier_adaptor::puxch_adaptor::on_rx_symbol(const shared_resource_grid& grid, const lower_phy_rx_symbol_context& context) { srsran_assert(error_notifier, "The adaptor is not connected to an error notifier."); diff --git a/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.h b/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.h index b6cf7d50b5..ea84aec051 100644 --- a/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.h +++ b/lib/phy/lower/processors/adaptors/processor_notifier_adaptor.h @@ -177,7 +177,7 @@ class processor_notifier_adaptor void on_puxch_request_late(const resource_grid_context& context) override; // See interface for documentation. - void on_rx_symbol(const resource_grid_reader& grid, const lower_phy_rx_symbol_context& context) override; + void on_rx_symbol(const shared_resource_grid& grid, const lower_phy_rx_symbol_context& context) override; private: /// Receive notifier. diff --git a/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp b/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp index 208b077524..9663d24e79 100644 --- a/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp +++ b/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp @@ -10,13 +10,11 @@ #include "pdxch_processor_impl.h" #include "srsran/instrumentation/traces/du_traces.h" -#include "srsran/phy/support/resource_grid_reader_empty.h" +#include "srsran/phy/support/resource_grid_reader.h" #include "srsran/srsvec/zero.h" using namespace srsran; -const resource_grid_reader_empty pdxch_processor_impl::empty_rg(MAX_PORTS, MAX_NSYMB_PER_SLOT, MAX_RB); - void pdxch_processor_impl::connect(pdxch_processor_notifier& notifier_) { notifier = ¬ifier_; @@ -43,12 +41,12 @@ bool pdxch_processor_impl::process_symbol(baseband_gateway_buffer_writer& current_slot = context.slot; // Exchange an empty request with the current slot with a stored request. - auto request = requests.exchange({context.slot, nullptr}); + auto request = requests.exchange({context.slot, shared_resource_grid()}); // Handle the returned request. - if (request.grid == nullptr) { - // If the request resource grid pointer is nullptr, the request is empty. - current_grid = empty_rg; + if (!request.grid) { + // If the request resource grid pointer is invalid, the request is empty. + current_grid.release(); return false; } @@ -58,16 +56,21 @@ bool pdxch_processor_impl::process_symbol(baseband_gateway_buffer_writer& late_context.slot = request.slot; late_context.sector = context.sector; notifier->on_pdxch_request_late(late_context); - current_grid = empty_rg; + current_grid.release(); return false; } // If the request is valid, then select request grid. - current_grid = *request.grid; + current_grid = std::move(request.grid); + } + + // Skip processing if the resource grid is invalid. + if (!current_grid) { + return false; } // Skip processing if the resource grid is empty. - if (current_grid.get().is_empty()) { + if (current_grid.get_reader().is_empty()) { return false; } @@ -76,21 +79,21 @@ bool pdxch_processor_impl::process_symbol(baseband_gateway_buffer_writer& // Modulate each of the ports. for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { - modulator->modulate(samples.get_channel_buffer(i_port), current_grid, i_port, symbol_index_subframe); + modulator->modulate(samples.get_channel_buffer(i_port), current_grid.get_reader(), i_port, symbol_index_subframe); } return true; } -void pdxch_processor_impl::handle_request(const resource_grid_reader& grid, const resource_grid_context& context) +void pdxch_processor_impl::handle_request(const shared_resource_grid& grid, const resource_grid_context& context) { srsran_assert(notifier != nullptr, "Notifier has not been connected."); // Swap the new request by the current request in the circular array. - auto request = requests.exchange({context.slot, &grid}); + auto request = requests.exchange({context.slot, grid.copy()}); // If there was a request with a resource grid, then notify a late event with the context of the discarded request. - if (request.grid != nullptr) { + if (request.grid) { resource_grid_context late_context; late_context.slot = request.slot; late_context.sector = context.sector; diff --git a/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.h b/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.h index 2f7783e413..e853f87d73 100644 --- a/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.h +++ b/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.h @@ -9,6 +9,7 @@ */ #pragma once + #include "../../resource_grid_request_pool.h" #include "srsran/gateways/baseband/buffer/baseband_gateway_buffer_dynamic.h" #include "srsran/phy/lower/modulation/ofdm_modulator.h" @@ -17,7 +18,6 @@ #include "srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_notifier.h" #include "srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_request_handler.h" #include "srsran/phy/support/resource_grid_context.h" -#include "srsran/phy/support/resource_grid_reader_empty.h" namespace srsran { @@ -55,16 +55,15 @@ class pdxch_processor_impl : public pdxch_processor, bool process_symbol(baseband_gateway_buffer_writer& samples, const symbol_context& context) override; // See interface for documentation. - void handle_request(const resource_grid_reader& grid, const resource_grid_context& context) override; + void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) override; - unsigned nof_symbols_per_slot; - unsigned nof_tx_ports; - pdxch_processor_notifier* notifier = nullptr; - std::unique_ptr modulator; - slot_point current_slot; - std::reference_wrapper current_grid = empty_rg; - resource_grid_request_pool requests; - static const resource_grid_reader_empty empty_rg; + unsigned nof_symbols_per_slot; + unsigned nof_tx_ports; + pdxch_processor_notifier* notifier = nullptr; + std::unique_ptr modulator; + slot_point current_slot; + shared_resource_grid current_grid; + resource_grid_request_pool requests; }; } // namespace srsran diff --git a/lib/phy/lower/processors/resource_grid_request_pool.h b/lib/phy/lower/processors/resource_grid_request_pool.h index 193bbeb90a..c1fac68993 100644 --- a/lib/phy/lower/processors/resource_grid_request_pool.h +++ b/lib/phy/lower/processors/resource_grid_request_pool.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/adt/circular_array.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/slot_point.h" #include #include @@ -23,20 +24,22 @@ namespace srsran { /// resource grid. The pool access is thread-safe and it is done by exchange requests. /// /// \tparam GridType Resource grid type. -template class resource_grid_request_pool { public: /// Internal storage type. struct request_type { - slot_point slot; - GridType* grid; + slot_point slot; + shared_resource_grid grid; }; /// \brief Exchanges a request from the pool by the given one. /// \param[in] request The given request, it is copied into request.slot.system_slot() % REQUEST_ARRAY_SIZE. /// \return The previous request at position request.slot.system_slot() % REQUEST_ARRAY_SIZE . - request_type exchange(const request_type& request) { return requests[request.slot.system_slot()].exchange(request); } + request_type exchange(request_type request) + { + return requests[request.slot.system_slot()].exchange(std::move(request)); + } private: /// Number of requests contained in the array. @@ -47,15 +50,17 @@ class resource_grid_request_pool { public: /// Default constructor - constructs an empty request. - request_wrapper() : request({slot_point(), nullptr}) {} + request_wrapper() : request({slot_point(), shared_resource_grid()}) {} /// \brief Exchanges the previous request with a new request. /// \param[in] new_request New request. /// \return A copy of the previous request. - request_type exchange(const request_type& new_request) + request_type exchange(request_type new_request) { std::unique_lock lock(mutex); - return std::exchange(request, new_request); + request_type old_request = std::move(request); + request = std::move(new_request); + return old_request; } private: diff --git a/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.cpp b/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.cpp index 128a8c09b1..342209c161 100644 --- a/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.cpp +++ b/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.cpp @@ -26,27 +26,27 @@ bool puxch_processor_impl::process_symbol(const baseband_gateway_buffer_reader& current_slot = context.slot; // Exchange an empty request with the current slot with a stored request. - auto request = requests.exchange({context.slot, nullptr}); + auto request = requests.exchange({context.slot, shared_resource_grid()}); // Handle the returned request. - if (request.grid == nullptr) { - // If the request resource grid pointer is nullptr, the request is empty. - current_grid = nullptr; + if (!request.grid) { + // If the request resource grid pointer is invalid, the request is empty. + current_grid.release(); } else if (current_slot != request.slot) { // If the slot of the request does not match the current slot, then notify a late event. resource_grid_context late_context; late_context.slot = request.slot; late_context.sector = context.sector; notifier->on_puxch_request_late(late_context); - current_grid = nullptr; + current_grid.release(); } else { // If the request is valid, then select request grid. - current_grid = request.grid; + current_grid = std::move(request.grid); } } // Skip symbol processing if the context slot does not match with the current slot or no resource grid is available. - if (current_grid == nullptr) { + if (!current_grid) { return false; } @@ -56,27 +56,32 @@ bool puxch_processor_impl::process_symbol(const baseband_gateway_buffer_reader& // Demodulate each of the ports. for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { demodulator->demodulate( - current_grid->get_writer(), samples.get_channel_buffer(i_port), i_port, symbol_index_subframe); + current_grid.get().get_writer(), samples.get_channel_buffer(i_port), i_port, symbol_index_subframe); } // Notify. lower_phy_rx_symbol_context rx_symbol_context; rx_symbol_context.slot = current_slot; rx_symbol_context.nof_symbols = context.nof_symbols; - notifier->on_rx_symbol(current_grid->get_reader(), context); + notifier->on_rx_symbol(current_grid, context); + + // Release current grid if the slot is completed. + if (context.nof_symbols == nof_symbols_per_slot - 1) { + current_grid.release(); + } return true; } -void puxch_processor_impl::handle_request(resource_grid& grid, const resource_grid_context& context) +void puxch_processor_impl::handle_request(const shared_resource_grid& grid, const resource_grid_context& context) { srsran_assert(notifier != nullptr, "Notifier has not been connected."); // Swap the new request by the current request in the circular array. - auto request = requests.exchange({context.slot, &grid}); + auto request = requests.exchange({context.slot, grid.copy()}); // If there was a request at the same request index, notify a late event with the context of the discarded request. - if (request.grid != nullptr) { + if (request.grid) { resource_grid_context late_context; late_context.slot = request.slot; late_context.sector = context.sector; diff --git a/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h b/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h index 91ee53aeae..44baf7c681 100644 --- a/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h +++ b/lib/phy/lower/processors/uplink/puxch/puxch_processor_impl.h @@ -17,6 +17,7 @@ #include "srsran/phy/lower/processors/uplink/puxch/puxch_processor_baseband.h" #include "srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h" #include "srsran/phy/lower/processors/uplink/puxch/puxch_processor_request_handler.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/slot_point.h" namespace srsran { @@ -56,15 +57,15 @@ class puxch_processor_impl : public puxch_processor, const lower_phy_rx_symbol_context& context) override; // See interface for documentation. - void handle_request(resource_grid& grid, const resource_grid_context& context) override; + void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) override; - unsigned nof_symbols_per_slot; - unsigned nof_rx_ports; - puxch_processor_notifier* notifier = nullptr; - std::unique_ptr demodulator; - slot_point current_slot; - resource_grid* current_grid = nullptr; - resource_grid_request_pool requests; + unsigned nof_symbols_per_slot; + unsigned nof_rx_ports; + puxch_processor_notifier* notifier = nullptr; + std::unique_ptr demodulator; + slot_point current_slot; + shared_resource_grid current_grid; + resource_grid_request_pool requests; }; } // namespace srsran diff --git a/lib/phy/support/CMakeLists.txt b/lib/phy/support/CMakeLists.txt index 03ad8e12e5..bf20cf487c 100644 --- a/lib/phy/support/CMakeLists.txt +++ b/lib/phy/support/CMakeLists.txt @@ -14,8 +14,7 @@ add_library(srsran_phy_support STATIC re_pattern.cpp resource_grid_impl.cpp resource_grid_mapper_impl.cpp - resource_grid_pool_asynchronous_impl.cpp - resource_grid_pool_generic_impl.cpp + resource_grid_pool_impl.cpp resource_grid_reader_impl.cpp resource_grid_writer_impl.cpp support_factories.cpp) diff --git a/lib/phy/support/resource_grid_pool_asynchronous_impl.cpp b/lib/phy/support/resource_grid_pool_asynchronous_impl.cpp deleted file mode 100644 index d2e4034367..0000000000 --- a/lib/phy/support/resource_grid_pool_asynchronous_impl.cpp +++ /dev/null @@ -1,111 +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 "resource_grid_pool_asynchronous_impl.h" -#include "srsran/adt/optional.h" -#include "srsran/instrumentation/traces/du_traces.h" -#include "srsran/phy/support/resource_grid.h" -#include "srsran/phy/support/resource_grid_context.h" -#include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/support/executors/task_executor.h" -#include "srsran/support/srsran_assert.h" - -using namespace srsran; - -resource_grid_pool_asynchronous_impl::resource_grid_pool_asynchronous_impl(unsigned expire_timeout_slots_, - task_executor& async_executor_, - std::vector grids_) : - logger(srslog::fetch_basic_logger("PHY", true)), - expire_timeout_slots(expire_timeout_slots_), - grids(std::move(grids_)), - grids_str_zero(grids.size()), - grids_str_reserved(grids.size()), - reserved(grids.size()), - available(grids.size()), - async_executor(async_executor_) -{ - // Make sure the expiration timeout is consistent with the number of grids. If the expiration time is greater than - // or equal to the number of grids, the pool blocks. - srsran_assert(expire_timeout_slots < grids.size(), - "The grid expiration time (i.e., {}) must be lesser than the number of grids (i.e., {}).", - expire_timeout_slots, - grids.size()); - - // Move grids to available list. - for (unsigned i_grid = 0, i_grid_end = grids.size(); i_grid != i_grid_end; ++i_grid) { - grids_str_zero[i_grid] = "set_all_zero#" + std::to_string(i_grid); - grids_str_reserved[i_grid] = "rg_reserved#" + std::to_string(i_grid); - - bool success = available.push_blocking(i_grid); - srsran_assert(success, "Failed to push grid."); - } -} - -resource_grid& resource_grid_pool_asynchronous_impl::get_resource_grid(const resource_grid_context& context) -{ - // While the reserved buffer is not empty and the first element is expired. - while (!reserved.empty() && (reserved.top().expiration <= context.slot)) { - // Read first element. - reserved_resource_grid grid = reserved.top(); - - // Extract grid identifier. - unsigned grid_id = grid.grid_id; - - // Skip setting to zero if the grid is empty. - if (grids[grid_id]->get_reader().is_empty()) { - reserved.pop(); - available.push_blocking(grid_id); - continue; - } - - // Create lambda function for setting the grid to zero. - auto set_all_zero_func = [this, grid_id]() { - trace_point tp = l1_tracer.now(); - - // Set grid to zero. - grids[grid_id]->set_all_zero(); - - // Queue available grid. - bool success = available.push_blocking(grid_id); - srsran_assert(success, "Failed to push grid."); - - l1_tracer << trace_event(grids_str_zero[grid_id].c_str(), tp); - }; - - // Try to execute the asynchronous housekeeping task. - bool success = async_executor.execute(set_all_zero_func); - - // Pop the resource grid identifier if it was successfully executed. Otherwise, it skips zeroing. - if (success) { - reserved.pop(); - } else { - logger.warning(context.slot.sfn(), context.slot.slot_index(), "Failed to enqueue grid zeroing task."); - break; - } - } - - // Trace point for grid reservation. - trace_point tp = l1_tracer.now(); - - // Pop first available grid. - std::optional grid = available.pop_blocking(); - srsran_assert(grid.has_value(), "Failed to pop grid."); - - // Prepare reserved grid and enqueue. - reserved_resource_grid reserved_grid; - reserved_grid.expiration = context.slot + expire_timeout_slots; - reserved_grid.grid_id = grid.value(); - reserved.push(reserved_grid); - - // Trace the resource grid reservation. - l1_tracer << trace_event(grids_str_reserved[grid.value()].c_str(), tp); - - return *grids[reserved_grid.grid_id]; -} diff --git a/lib/phy/support/resource_grid_pool_asynchronous_impl.h b/lib/phy/support/resource_grid_pool_asynchronous_impl.h deleted file mode 100644 index a66d983f66..0000000000 --- a/lib/phy/support/resource_grid_pool_asynchronous_impl.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/adt/mpmc_queue.h" -#include "srsran/adt/ring_buffer.h" -#include "srsran/phy/support/resource_grid.h" -#include "srsran/phy/support/resource_grid_context.h" -#include "srsran/phy/support/resource_grid_pool.h" -#include "srsran/srslog/srslog.h" -#include "srsran/support/event_tracing.h" -#include -#include - -namespace srsran { - -class task_executor; - -/// Implements a generic resource grid pool that zeroes the resource grids after a number of slots. -class resource_grid_pool_asynchronous_impl : public resource_grid_pool -{ -public: - using resource_grid_ptr = std::unique_ptr; - - /// \brief Constructs a resource grid pool. - /// \param expire_timeout_slots_ Resource grid timeout expiration in slots. - /// \param async_executor_ Asynchronous housekeeping executor. - /// \param grids Resource grids. - resource_grid_pool_asynchronous_impl(unsigned expire_timeout_slots_, - task_executor& async_executor_, - std::vector> grids); - - // See interface for documentation. - resource_grid& get_resource_grid(const resource_grid_context& context) override; - -private: - struct reserved_resource_grid { - slot_point expiration; - unsigned grid_id; - }; - - /// PHY logger. - srslog::basic_logger& logger; - /// Grid expiration timeout in slots. - unsigned expire_timeout_slots; - /// Actual pool of resource grids. - std::vector grids; - /// Pool of resource grid zero set string for tracing. - std::vector grids_str_zero; - /// Pool of resource grid reservation string for tracing. - std::vector grids_str_reserved; - /// Reserved resource grids. - ring_buffer reserved; - /// Queue of resource grids ready to use. - concurrent_queue available; - /// Asynchronous task executor. - task_executor& async_executor; -}; - -} // namespace srsran diff --git a/lib/phy/support/resource_grid_pool_generic_impl.cpp b/lib/phy/support/resource_grid_pool_generic_impl.cpp deleted file mode 100644 index 0f96dfd8b4..0000000000 --- a/lib/phy/support/resource_grid_pool_generic_impl.cpp +++ /dev/null @@ -1,30 +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 "resource_grid_pool_generic_impl.h" -#include "srsran/support/srsran_assert.h" - -using namespace srsran; - -resource_grid_pool_generic_impl::resource_grid_pool_generic_impl(std::vector grids_) : - grids(std::move(grids_)) -{ - srsran_assert(std::all_of(grids.begin(), grids.end(), [](const auto& ptr) { return ptr != nullptr; }), - "Detected invalid grid pointer."); -} - -resource_grid& resource_grid_pool_generic_impl::get_resource_grid(const resource_grid_context& context) -{ - unsigned index = count; - - count = (count + 1) % grids.size(); - - return *grids[index]; -} diff --git a/lib/phy/support/resource_grid_pool_generic_impl.h b/lib/phy/support/resource_grid_pool_generic_impl.h deleted file mode 100644 index 2c1af684ce..0000000000 --- a/lib/phy/support/resource_grid_pool_generic_impl.h +++ /dev/null @@ -1,42 +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/complex.h" -#include "srsran/adt/concurrent_queue.h" -#include "srsran/adt/ring_buffer.h" -#include "srsran/phy/support/resource_grid_pool.h" -#include "srsran/srsvec/aligned_vec.h" -#include "srsran/support/executors/task_executor.h" -#include - -namespace srsran { - -/// Implements a generic resource grid pool. -class resource_grid_pool_generic_impl : public resource_grid_pool -{ -public: - using resource_grid_ptr = std::unique_ptr; - - /// \brief Constructs a resource grid pool. - /// \param grids_ Actual vector containing resource grids. - resource_grid_pool_generic_impl(std::vector grids_); - - // See interface for documentation. - resource_grid& get_resource_grid(const resource_grid_context& context) override; - -private: - unsigned count = 0; - /// Actual pool of resource grids. - std::vector grids; -}; - -} // namespace srsran diff --git a/lib/phy/support/resource_grid_pool_impl.cpp b/lib/phy/support/resource_grid_pool_impl.cpp new file mode 100644 index 0000000000..1f90c2e39c --- /dev/null +++ b/lib/phy/support/resource_grid_pool_impl.cpp @@ -0,0 +1,135 @@ +/* + * + * 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 "resource_grid_pool_impl.h" +#include "srsran/adt/optional.h" +#include "srsran/instrumentation/traces/du_traces.h" +#include "srsran/phy/support/resource_grid.h" +#include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/support/executors/task_executor.h" +#include "srsran/support/srsran_assert.h" + +using namespace srsran; + +resource_grid_pool_impl::resource_grid_pool_impl(task_executor* async_executor_, + std::vector grids_) : + logger(srslog::fetch_basic_logger("PHY", true)), + grids(std::move(grids_)), + grids_scope_count(grids.size()), + grids_str_zero(grids.size()), + grids_str_reserved(grids.size()), + async_executor(async_executor_) +{ + // Create tracing list. + for (unsigned i_grid = 0, i_grid_end = grids.size(); i_grid != i_grid_end; ++i_grid) { + grids_str_zero[i_grid] = "set_all_zero#" + std::to_string(i_grid); + grids_str_reserved[i_grid] = "rg_reserved#" + std::to_string(i_grid); + } + + // All grids scopes must be zero. + std::fill(grids_scope_count.begin(), grids_scope_count.end(), ref_counter_available); +} + +resource_grid_pool_impl::~resource_grid_pool_impl() +{ + // Ensure that all the grids returned to the pool. The application will result in segmentation fault. + report_fatal_error_if_not(std::all_of(grids_scope_count.cbegin(), + grids_scope_count.cend(), + [](auto& e) { return e == ref_counter_available; }), + "Not all the resource grids have returned to the pool."); +} + +shared_resource_grid resource_grid_pool_impl::allocate_resource_grid(const resource_grid_context& context) +{ + // Trace point for grid reservation. + trace_point tp = l1_tracer.now(); + + // Select an identifier from the current request counter. + unsigned identifier = counter; + + // Increment request counter and wrap it with the number of grids. + counter = (counter + 1) % grids.size(); + + // Select counter for the selected identifier. + std::atomic& ref_count = grids_scope_count[identifier]; + + // Try to reset the reference counter. + unsigned expected = ref_counter_available; + bool available = ref_count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel); + + // Return an invalid grid if not available. + if (!available) { + logger.warning(context.slot.sfn(), + context.slot.slot_index(), + "Resource grid with identifier {} is not available.", + identifier); + return {}; + } + + // Trace the resource grid reservation. + l1_tracer << trace_event(grids_str_reserved[identifier].c_str(), tp); + + return {*this, ref_count, identifier}; +} + +resource_grid& resource_grid_pool_impl::get(unsigned identifier) +{ + srsran_assert(identifier < grids.size(), + "RG identifier (i.e., {}) is out of range {}.", + identifier, + interval(0, grids.size())); + return *grids[identifier]; +} + +void resource_grid_pool_impl::notify_release_scope(unsigned identifier) +{ + // verify the identifier is valid. + srsran_assert(identifier < grids.size(), + "RG identifier (i.e., {}) is out of range {}.", + identifier, + interval(0, grids.size())); + + // Skip zeroing if the grid is empty. + if (grids[identifier]->get_reader().is_empty()) { + grids_scope_count[identifier] = ref_counter_available; + return; + } + + // If the pool is not configured with an asynchronous executor, it skips the zeroing process. + if (async_executor == nullptr) { + grids_scope_count[identifier] = ref_counter_available; + return; + } + + // Create lambda function for setting the grid to zero. + auto set_all_zero_func = [this, identifier]() { + trace_point tp = l1_tracer.now(); + + // Set grid to zero. + grids[identifier]->set_all_zero(); + + // Make the grid available. + grids_scope_count[identifier] = ref_counter_available; + + l1_tracer << trace_event(grids_str_zero[identifier].c_str(), tp); + }; + + // Try to execute the asynchronous housekeeping task. + bool success = async_executor->execute(set_all_zero_func); + + // Warn about the failure to enqueue the zeroing task. + if (!success) { + logger.warning("Failed to enqueue grid zeroing task."); + + // Make the resource grid available even if it is not empty. + grids_scope_count[identifier] = ref_counter_available; + } +} diff --git a/lib/phy/support/resource_grid_pool_impl.h b/lib/phy/support/resource_grid_pool_impl.h new file mode 100644 index 0000000000..f2867d2182 --- /dev/null +++ b/lib/phy/support/resource_grid_pool_impl.h @@ -0,0 +1,72 @@ +/* + * + * 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/phy/support/resource_grid.h" +#include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/resource_grid_pool.h" +#include "srsran/phy/support/shared_resource_grid.h" +#include "srsran/srslog/srslog.h" +#include "srsran/support/event_tracing.h" +#include +#include + +namespace srsran { + +class task_executor; + +/// \brief Implements a resource grid pool. +/// +/// It zeroes the resource grids asynchronously upon their scope release if it is given an asynchronous executor. +/// Otherwise, it does not zero the resource grid. +class resource_grid_pool_impl : public resource_grid_pool, private shared_resource_grid::pool_interface +{ +public: + using resource_grid_ptr = std::unique_ptr; + + /// \brief Constructs a resource grid pool. + /// \param async_executor_ Asynchronous housekeeping executor. + /// \param grids_ Resource grids. + resource_grid_pool_impl(task_executor* async_executor_, std::vector> grids_); + + /// \brief The destructor checks that all resource grids have been returned to the pool. + ~resource_grid_pool_impl(); + + // See resource_grid_pool interface for documentation. + shared_resource_grid allocate_resource_grid(const resource_grid_context& context) override; + +private: + /// Reference counter value to indicate the availability of a resource grid. + static constexpr unsigned ref_counter_available = std::numeric_limits::max(); + + // See shared_resource_grid::pool_interface for documentation. + resource_grid& get(unsigned identifier) override; + + // See shared_resource_grid::pool_interface for documentation. + void notify_release_scope(unsigned identifier) override; + + /// PHY logger. + srslog::basic_logger& logger; + /// Actual pool of resource grids. + std::vector grids; + /// Counts the resource grid requests. + unsigned counter = 0; + /// Resource grid scope count. Zero means they are available. + std::vector> grids_scope_count; + /// Pool of resource grid zero set string for tracing. + std::vector grids_str_zero; + /// Pool of resource grid reservation string for tracing. + std::vector grids_str_reserved; + /// Asynchronous task executor. + task_executor* async_executor; +}; + +} // namespace srsran diff --git a/lib/phy/support/support_factories.cpp b/lib/phy/support/support_factories.cpp index 639b2fe1bb..bb835d4b6b 100644 --- a/lib/phy/support/support_factories.cpp +++ b/lib/phy/support/support_factories.cpp @@ -13,8 +13,7 @@ #include "prach_buffer_impl.h" #include "prach_buffer_pool_impl.h" #include "resource_grid_impl.h" -#include "resource_grid_pool_asynchronous_impl.h" -#include "resource_grid_pool_generic_impl.h" +#include "resource_grid_pool_impl.h" #include "srsran/phy/generic_functions/precoding/precoding_factories.h" #include "srsran/ran/prach/prach_constants.h" @@ -52,15 +51,14 @@ class resource_grid_factory_impl : public resource_grid_factory std::unique_ptr srsran::create_generic_resource_grid_pool(std::vector> grids) { - return std::make_unique(std::move(grids)); + return std::make_unique(nullptr, std::move(grids)); } std::unique_ptr -srsran::create_asynchronous_resource_grid_pool(unsigned expire_timeout_slots, - task_executor& async_executor, +srsran::create_asynchronous_resource_grid_pool(task_executor& async_executor, std::vector> grids) { - return std::make_unique(expire_timeout_slots, async_executor, std::move(grids)); + return std::make_unique(&async_executor, std::move(grids)); } std::unique_ptr diff --git a/lib/phy/upper/downlink_processor_single_executor_impl.cpp b/lib/phy/upper/downlink_processor_single_executor_impl.cpp index de8fd438b1..a47c225ddd 100644 --- a/lib/phy/upper/downlink_processor_single_executor_impl.cpp +++ b/lib/phy/upper/downlink_processor_single_executor_impl.cpp @@ -27,7 +27,6 @@ downlink_processor_single_executor_impl::downlink_processor_single_executor_impl task_executor& executor_, srslog::basic_logger& logger_) : gateway(gateway_), - current_grid(nullptr), pdcch_proc(std::move(pdcch_proc_)), pdsch_proc(std::move(pdsch_proc_)), ssb_proc(std::move(ssb_proc_)), @@ -63,8 +62,8 @@ void downlink_processor_single_executor_impl::process_pdcch(const pdcch_processo trace_point process_pdcch_tp = l1_tracer.now(); // Do not execute if the grid is not available. - if (current_grid != nullptr) { - resource_grid_mapper& mapper = current_grid->get_mapper(); + if (current_grid) { + resource_grid_mapper& mapper = current_grid.get().get_mapper(); pdcch_proc->process(mapper, pdu); } @@ -106,7 +105,7 @@ void downlink_processor_single_executor_impl::process_pdsch( trace_point process_pdsch_tp = l1_tracer.now(); // Do not execute if the grid is not available. - if (current_grid != nullptr) { + if (current_grid) { resource_grid_mapper& mapper = current_grid->get_mapper(); pdsch_proc->process(mapper, pdsch_notifier, data, pdu); @@ -150,7 +149,7 @@ void downlink_processor_single_executor_impl::process_ssb(const ssb_processor::p trace_point process_ssb_tp = l1_tracer.now(); // Do not execute if the grid is not available. - if (current_grid != nullptr) { + if (current_grid) { ssb_proc->process(current_grid->get_writer(), pdu); } @@ -192,7 +191,7 @@ void downlink_processor_single_executor_impl::process_nzp_csi_rs(const nzp_csi_r trace_point process_nzp_csi_rs_tp = l1_tracer.now(); // Do not execute if the grid is not available. - if (current_grid != nullptr) { + if (current_grid) { resource_grid_mapper& mapper = current_grid->get_mapper(); csi_rs_proc->map(mapper, config); } @@ -213,7 +212,7 @@ void downlink_processor_single_executor_impl::process_nzp_csi_rs(const nzp_csi_r } bool downlink_processor_single_executor_impl::configure_resource_grid(const resource_grid_context& context, - resource_grid& grid) + shared_resource_grid grid) { std::lock_guard lock(mutex); @@ -222,9 +221,9 @@ bool downlink_processor_single_executor_impl::configure_resource_grid(const reso return false; } - report_fatal_error_if_not(current_grid == nullptr, "A previously configured resource grid is still in use."); + report_fatal_error_if_not(!current_grid, "A previously configured resource grid is still in use."); - current_grid = &grid; + current_grid = std::move(grid); rg_context = context; // update internal state to allow processing PDUs and increase the pending task counter. @@ -256,9 +255,9 @@ void downlink_processor_single_executor_impl::send_resource_grid() l1_tracer << instant_trace_event("send_resource_grid", instant_trace_event::cpu_scope::global); // Send the resource grid if available. - if (current_grid != nullptr) { - gateway.send(rg_context, current_grid->get_reader()); - current_grid = nullptr; + if (current_grid.is_valid()) { + shared_resource_grid grid2 = std::move(current_grid); + gateway.send(rg_context, std::move(grid2)); } // Update internal state. diff --git a/lib/phy/upper/downlink_processor_single_executor_impl.h b/lib/phy/upper/downlink_processor_single_executor_impl.h index 175d2e3ca5..02708c8863 100644 --- a/lib/phy/upper/downlink_processor_single_executor_impl.h +++ b/lib/phy/upper/downlink_processor_single_executor_impl.h @@ -13,6 +13,7 @@ #include "downlink_processor_single_executor_state.h" #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/downlink_processor.h" #include "srsran/srslog/logger.h" #include @@ -86,7 +87,7 @@ class downlink_processor_single_executor_impl : public downlink_processor, priva void process_nzp_csi_rs(const nzp_csi_rs_generator::config_t& config) override; // See interface for documentation. - bool configure_resource_grid(const resource_grid_context& context, resource_grid& grid) override; + bool configure_resource_grid(const resource_grid_context& context, shared_resource_grid grid) override; // See interface for documentation. void finish_processing_pdus() override; @@ -120,7 +121,7 @@ class downlink_processor_single_executor_impl : public downlink_processor, priva upper_phy_rg_gateway& gateway; resource_grid_context rg_context; - resource_grid* current_grid; + shared_resource_grid current_grid; std::unique_ptr pdcch_proc; std::unique_ptr pdsch_proc; std::unique_ptr ssb_proc; diff --git a/lib/phy/upper/uplink_processor_impl.cpp b/lib/phy/upper/uplink_processor_impl.cpp index 804da2ff7f..207681d83c 100644 --- a/lib/phy/upper/uplink_processor_impl.cpp +++ b/lib/phy/upper/uplink_processor_impl.cpp @@ -12,6 +12,8 @@ #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/phy/support/prach_buffer.h" #include "srsran/phy/support/prach_buffer_context.h" +#include "srsran/phy/support/resource_grid.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/unique_rx_buffer.h" #include "srsran/phy/upper/upper_phy_rx_results_notifier.h" @@ -74,7 +76,7 @@ void uplink_processor_impl::process_prach(upper_phy_rx_results_notifier& notifie void uplink_processor_impl::process_pusch(span data, unique_rx_buffer rm_buffer, upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::pusch_pdu& pdu) { trace_point tp = l1_tracer.now(); @@ -94,13 +96,13 @@ void uplink_processor_impl::process_pusch(span dat notifier, to_rnti(pdu.pdu.rnti), pdu.pdu.slot, to_harq_id(pdu.harq_id), data); // Process PUSCH. - pusch_proc->process(data, std::move(rm_buffer), processor_notifier, grid, pdu.pdu); + pusch_proc->process(data, std::move(rm_buffer), processor_notifier, grid.get_reader(), pdu.pdu); l1_tracer << trace_event("process_pusch", tp); } void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::pucch_pdu& pdu) { trace_point tp = l1_tracer.now(); @@ -113,19 +115,19 @@ void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& not // Process the PUCCH. switch (pdu.context.format) { case pucch_format::FORMAT_0: - proc_result = pucch_proc->process(grid, pdu.format0); + proc_result = pucch_proc->process(grid.get_reader(), pdu.format0); break; case pucch_format::FORMAT_1: - proc_result = pucch_proc->process(grid, pdu.format1); + proc_result = pucch_proc->process(grid.get_reader(), pdu.format1); break; case pucch_format::FORMAT_2: - proc_result = pucch_proc->process(grid, pdu.format2); + proc_result = pucch_proc->process(grid.get_reader(), pdu.format2); break; case pucch_format::FORMAT_3: - proc_result = pucch_proc->process(grid, pdu.format3); + proc_result = pucch_proc->process(grid.get_reader(), pdu.format3); break; case pucch_format::FORMAT_4: - proc_result = pucch_proc->process(grid, pdu.format4); + proc_result = pucch_proc->process(grid.get_reader(), pdu.format4); break; default: srsran_assert(0, "Invalid PUCCH format={}", pdu.context.format); @@ -143,14 +145,14 @@ void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& not } void uplink_processor_impl::process_srs(upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::srs_pdu& pdu) { trace_point tp = l1_tracer.now(); ul_srs_results result; result.context = pdu.context; - result.processor_result = srs->estimate(grid, pdu.config); + result.processor_result = srs->estimate(grid.get_reader(), pdu.config); l1_tracer << trace_event("process_srs", tp); diff --git a/lib/phy/upper/uplink_processor_impl.h b/lib/phy/upper/uplink_processor_impl.h index 0998d11bd3..f0f6615206 100644 --- a/lib/phy/upper/uplink_processor_impl.h +++ b/lib/phy/upper/uplink_processor_impl.h @@ -153,17 +153,17 @@ class uplink_processor_impl : public uplink_processor void process_pusch(span data, unique_rx_buffer rm_buffer, upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::pusch_pdu& pdu) override; // See interface for documentation. void process_pucch(upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const pucch_pdu& pdu) override; // See interface for documentation. void - process_srs(upper_phy_rx_results_notifier& notifier, const resource_grid_reader& grid, const srs_pdu& pdu) override; + process_srs(upper_phy_rx_results_notifier& notifier, const shared_resource_grid& grid, const srs_pdu& pdu) override; private: /// Maximum number of PUSCH notifier adaptors. diff --git a/lib/phy/upper/uplink_processor_task_dispatcher.h b/lib/phy/upper/uplink_processor_task_dispatcher.h index 459c88bfe6..1aa2738da7 100644 --- a/lib/phy/upper/uplink_processor_task_dispatcher.h +++ b/lib/phy/upper/uplink_processor_task_dispatcher.h @@ -58,12 +58,12 @@ class uplink_processor_task_dispatcher : public uplink_processor void process_pusch(span data, unique_rx_buffer rm_buffer, upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::pusch_pdu& pdu) override { - bool success = - pusch_executor.execute([data, rm_buffer2 = std::move(rm_buffer), ¬ifier, &grid, pdu, this]() mutable { - processor->process_pusch(data, std::move(rm_buffer2), notifier, grid, pdu); + bool success = pusch_executor.execute( + [data, rm_buffer2 = std::move(rm_buffer), ¬ifier, rg = grid.copy(), pdu, this]() mutable { + processor->process_pusch(data, std::move(rm_buffer2), notifier, rg, pdu); }); if (!success) { @@ -87,11 +87,11 @@ class uplink_processor_task_dispatcher : public uplink_processor // See interface for documentation. void process_pucch(upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const pucch_pdu& pdu) override { - bool success = - pucch_executor.execute([¬ifier, &grid, pdu, this]() { processor->process_pucch(notifier, grid, pdu); }); + bool success = pucch_executor.execute( + [¬ifier, rg = grid.copy(), pdu, this]() { processor->process_pucch(notifier, rg, pdu); }); if (!success) { logger.warning( pdu.context.slot.sfn(), pdu.context.slot.slot_index(), "Failed to execute PUCCH. Ignoring processing."); @@ -122,10 +122,10 @@ class uplink_processor_task_dispatcher : public uplink_processor } void - process_srs(upper_phy_rx_results_notifier& notifier, const resource_grid_reader& grid, const srs_pdu& pdu) override + process_srs(upper_phy_rx_results_notifier& notifier, const shared_resource_grid& grid, const srs_pdu& pdu) override { bool success = - srs_executor.execute([¬ifier, &grid, pdu, this]() { processor->process_srs(notifier, grid, pdu); }); + srs_executor.execute([¬ifier, rg = grid.copy(), pdu, this]() { processor->process_srs(notifier, rg, pdu); }); if (!success) { logger.warning( pdu.context.slot.sfn(), pdu.context.slot.slot_index(), "Failed to execute SRS. Ignoring processing."); diff --git a/lib/phy/upper/uplink_request_processor_impl.cpp b/lib/phy/upper/uplink_request_processor_impl.cpp index e2d88ef393..07ee42bf15 100644 --- a/lib/phy/upper/uplink_request_processor_impl.cpp +++ b/lib/phy/upper/uplink_request_processor_impl.cpp @@ -10,6 +10,7 @@ #include "uplink_request_processor_impl.h" #include "srsran/phy/support/prach_buffer_pool.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/upper_phy_rx_symbol_request_notifier.h" using namespace srsran; @@ -31,7 +32,7 @@ void uplink_request_processor_impl::process_prach_request(const prach_buffer_con } void uplink_request_processor_impl::process_uplink_slot_request(const resource_grid_context& context, - resource_grid& grid) + const shared_resource_grid& grid) { rx_symbol_request_notifier.on_uplink_slot_request(context, grid); } diff --git a/lib/phy/upper/uplink_request_processor_impl.h b/lib/phy/upper/uplink_request_processor_impl.h index 31f4ae7e29..92710e5ca2 100644 --- a/lib/phy/upper/uplink_request_processor_impl.h +++ b/lib/phy/upper/uplink_request_processor_impl.h @@ -16,6 +16,7 @@ namespace srsran { class prach_buffer_pool; class upper_phy_rx_symbol_request_notifier; +class shared_resource_grid; /// \brief Implementation of the uplink request processor interface. /// @@ -33,7 +34,7 @@ class uplink_request_processor_impl : public uplink_request_processor void process_prach_request(const prach_buffer_context& context) override; // See interface for documentation. - void process_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) override; + void process_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) override; private: /// Symbol request notifier. diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 06b676800d..a5cb00cf54 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -311,8 +311,7 @@ create_dl_resource_grid_pool(const upper_phy_config& config, std::shared_ptrcreate(nof_tx_ports, MAX_NSYMB_PER_SLOT, dl_bw_rb * NRE); }); - return create_asynchronous_resource_grid_pool( - config.dl_rg_expire_timeout_slots, *config.dl_executors.front(), std::move(grids)); + return create_asynchronous_resource_grid_pool(*config.dl_executors.front(), std::move(grids)); } static std::unique_ptr diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp index f2191de55a..4a78c324c0 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp @@ -11,6 +11,7 @@ #include "upper_phy_rx_symbol_handler_impl.h" #include "upper_phy_rx_results_notifier_wrapper.h" #include "srsran/phy/support/prach_buffer_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" #include "srsran/phy/upper/channel_processors/pusch/formatters.h" #include "srsran/phy/upper/rx_buffer_pool.h" @@ -34,7 +35,7 @@ upper_phy_rx_symbol_handler_impl::upper_phy_rx_symbol_handler_impl( } void upper_phy_rx_symbol_handler_impl::handle_rx_symbol(const upper_phy_rx_symbol_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { // Run PUSCH buffer housekeeping when a new slot starts. if (context.symbol == 0) { @@ -74,7 +75,7 @@ void upper_phy_rx_symbol_handler_impl::handle_rx_prach_window(const prach_buffer void upper_phy_rx_symbol_handler_impl::process_pusch(const uplink_processor::pusch_pdu& pdu, uplink_processor& ul_processor, - const resource_grid_reader& grid, + const shared_resource_grid& grid, slot_point slot) { const pusch_processor::pdu_t& proc_pdu = pdu.pdu; diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h index 8e257e6d3d..78fcb5d625 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/adt/circular_array.h" +#include "srsran/phy/support/resource_grid_writer.h" #include "srsran/phy/upper/rx_buffer_pool.h" #include "srsran/phy/upper/uplink_slot_pdu_repository.h" #include "srsran/phy/upper/upper_phy_rx_symbol_handler.h" @@ -84,7 +85,7 @@ class upper_phy_rx_symbol_handler_impl : public upper_phy_rx_symbol_handler upper_phy_rx_results_notifier& rx_results_notifier_); // See interface for documentation. - void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const resource_grid_reader& grid) override; + void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const shared_resource_grid& grid) override; // See interface for documentation. void handle_rx_prach_window(const prach_buffer_context& context, const prach_buffer& buffer) override; @@ -93,7 +94,7 @@ class upper_phy_rx_symbol_handler_impl : public upper_phy_rx_symbol_handler /// Process the given PUSCH PDU using the given uplink processor, grid and slot. void process_pusch(const uplink_processor::pusch_pdu& pdu, uplink_processor& ul_processor, - const resource_grid_reader& grid, + const shared_resource_grid& grid, slot_point slot); private: diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h b/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h index 60b98cb17a..d60e515877 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/conversion.h" #include "srsran/support/error_handling.h" @@ -53,7 +54,7 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol } } - void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const resource_grid_reader& grid) override + void handle_rx_symbol(const upper_phy_rx_symbol_context& context, const shared_resource_grid& grid) override { // Handle Rx symbol. handler->handle_rx_symbol(context, grid); @@ -68,7 +69,7 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol // Save the resource grid. for (unsigned i_port = start_port; i_port != end_port; ++i_port) { for (unsigned symbol_idx = 0; symbol_idx != nof_symbols; ++symbol_idx) { - grid.get(temp_buffer, i_port, symbol_idx, 0); + grid.get_reader().get(temp_buffer, i_port, symbol_idx, 0); file.write(reinterpret_cast(temp_buffer.data()), temp_buffer.size() * sizeof(cf_t)); } } diff --git a/lib/ru/dummy/ru_dummy_impl.h b/lib/ru/dummy/ru_dummy_impl.h index 3bce90f8e4..c71b756f4c 100644 --- a/lib/ru/dummy/ru_dummy_impl.h +++ b/lib/ru/dummy/ru_dummy_impl.h @@ -79,7 +79,7 @@ class ru_dummy_impl : public radio_unit, void print_metrics() override; // See ru_downlink_plane_handler for documentation. - void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override + void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) override { interval sector_range(0, sectors.size()); srsran_assert(sector_range.contains(context.sector), @@ -101,7 +101,7 @@ class ru_dummy_impl : public radio_unit, } // See ru_uplink_plane_handler for documentation. - void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) override + void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override { interval sector_range(0, sectors.size()); srsran_assert(sector_range.contains(context.sector), diff --git a/lib/ru/dummy/ru_dummy_sector.h b/lib/ru/dummy/ru_dummy_sector.h index 834ea2173b..382cc99aaf 100644 --- a/lib/ru/dummy/ru_dummy_sector.h +++ b/lib/ru/dummy/ru_dummy_sector.h @@ -16,6 +16,7 @@ #include "srsran/phy/constants.h" #include "srsran/phy/support/prach_buffer_context.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/cyclic_prefix.h" #include "srsran/ran/slot_point.h" #include "srsran/ru/ru_downlink_plane.h" @@ -63,16 +64,17 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane } // See ru_downlink_plane_handler interface for documentation. - void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override + void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) override { std::lock_guard lock(dl_request_mutex); - resource_grid_context prev_context = std::exchange(dl_request[context.slot.system_slot()], context); + request_information info = {context, grid.copy()}; + std::swap(info, dl_request[context.slot.system_slot()]); // If the previous slot is valid, it is a late. - if (prev_context.slot.valid()) { + if (info.context.slot.valid()) { logger.warning("Real-time failure in RU: received late DL request from slot {} in sector {}.", - prev_context.slot, - prev_context.sector); + info.context.slot, + info.context.sector); } } @@ -80,31 +82,32 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane void handle_prach_occasion(const prach_buffer_context& context, prach_buffer& buffer) override { std::lock_guard lock(prach_request_mutex); - prach_buffer_context prev_context = std::exchange(prach_request[context.slot.system_slot()], context); + prach_buffer_context info = std::exchange(prach_request[context.slot.system_slot()], context); // Detect if there is an unhandled request from a different slot. - if (prev_context.slot.valid()) { + if (info.slot.valid()) { logger.warning(context.slot.sfn(), context.slot.slot_index(), "Real-time failure in RU: received late PRACH request from slot {} in sector {}.", - prev_context.slot, - prev_context.sector); + info.slot, + info.sector); } } // See ru_uplink_plane_handler interface for documentation. - void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) override + void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override { std::lock_guard lock(ul_request_mutex); - resource_grid_context prev_context = std::exchange(ul_request[context.slot.system_slot()], context); + request_information info = {context, grid.copy()}; + std::swap(info, ul_request[context.slot.system_slot()]); // Detect if there is an unhandled request from a different slot. - if (prev_context.slot.valid()) { + if (info.context.slot.valid()) { logger.warning(context.slot.sfn(), context.slot.slot_index(), "Real-time failure in RU: received late UL request from slot {} in sector {}.", - prev_context.slot, - prev_context.sector); + info.context.slot, + info.context.sector); } } @@ -114,40 +117,40 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane // Process DL request for this slot. slot_point current_dl_slot = slot + dl_data_margin; - resource_grid_context context = {slot_point(), 0}; + request_information dl_info = {}; { std::lock_guard lock(dl_request_mutex); - context = std::exchange(dl_request[current_dl_slot.system_slot()], context); + std::swap(dl_info, dl_request[current_dl_slot.system_slot()]); } // Notify with a warning message if the DL previous saved context do not match with the current slot. - if (context.slot.valid() && (context.slot != current_dl_slot)) { + if (dl_info.context.slot.valid() && (dl_info.context.slot != current_dl_slot)) { logger.warning(current_dl_slot.sfn(), current_dl_slot.slot_index(), "Real-time failure in RU: detected late DL request from slot {} in sector {}.", - context.slot, - context.sector); + dl_info.context.slot, + dl_info.context.sector); } // Process UL request for this slot. - resource_grid_context ul_context = {slot_point(), 0}; + request_information ul_info = {}; { std::lock_guard lock(ul_request_mutex); - ul_context = std::exchange(ul_request[slot.system_slot()], ul_context); + std::swap(ul_info, ul_request[slot.system_slot()]); } // Check if the UL context from the request list is valid. - if (ul_context.slot.valid()) { - if (ul_context.slot == slot) { + if (ul_info.context.slot.valid()) { + if (ul_info.context.slot == slot) { // Prepare receive symbol context. ru_uplink_rx_symbol_context rx_context; - rx_context.slot = ul_context.slot; - rx_context.sector = ul_context.sector; + rx_context.slot = ul_info.context.slot; + rx_context.sector = ul_info.context.sector; // Notify received resource grid for each symbol. for (unsigned i_symbol = 0; i_symbol != MAX_NSYMB_PER_SLOT; ++i_symbol) { rx_context.symbol_id = i_symbol; - symbol_notifier.on_new_uplink_symbol(rx_context, rx_symbols_resource_grid); + symbol_notifier.on_new_uplink_symbol(rx_context, std::move(ul_info.grid)); } } else { @@ -155,8 +158,8 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane logger.warning(slot.sfn(), slot.slot_index(), "Real-time failure in RU: detected late UL request from slot {} in sector {}.", - ul_context.slot, - ul_context.sector); + ul_info.context.slot, + ul_info.context.sector); } } @@ -187,6 +190,11 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane /// Maximum number of requests stored in the ring buffers. static constexpr unsigned max_nof_request = 40; + struct request_information { + resource_grid_context context; + shared_resource_grid grid; + }; + /// Logger. srslog::basic_logger& logger; /// Receive symbol notifier. @@ -198,7 +206,7 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane /// Downlink request margin. unsigned dl_data_margin; /// Buffer containing the UL requests slots. - circular_array ul_request; + circular_array ul_request; /// Protects the circular buffer containing the UL requests. std::mutex ul_request_mutex; /// Buffer containing the PRACH requests slots. @@ -206,7 +214,7 @@ class ru_dummy_sector : public ru_uplink_plane_handler, public ru_downlink_plane /// Protects the circular buffer containing the PRACH requests. std::mutex prach_request_mutex; /// Circular buffer containing the DL requests indexed by system slot. - circular_array dl_request; + circular_array dl_request; /// Protects the circular buffer containing the DL requests. std::mutex dl_request_mutex; }; diff --git a/lib/ru/generic/ru_downlink_handler_generic_impl.cpp b/lib/ru/generic/ru_downlink_handler_generic_impl.cpp index 38d082e211..5b6398edbe 100644 --- a/lib/ru/generic/ru_downlink_handler_generic_impl.cpp +++ b/lib/ru/generic/ru_downlink_handler_generic_impl.cpp @@ -10,11 +10,12 @@ #include "ru_downlink_handler_generic_impl.h" #include "srsran/phy/lower/lower_phy_rg_handler.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; void ru_downlink_handler_generic_impl::handle_dl_data(const resource_grid_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { srsran_assert(context.sector < handler.size(), "Invalid sector {}", context.sector); diff --git a/lib/ru/generic/ru_downlink_handler_generic_impl.h b/lib/ru/generic/ru_downlink_handler_generic_impl.h index 63b8e9c225..ffcfa8e0f0 100644 --- a/lib/ru/generic/ru_downlink_handler_generic_impl.h +++ b/lib/ru/generic/ru_downlink_handler_generic_impl.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ru/ru_downlink_plane.h" namespace srsran { @@ -25,7 +26,7 @@ class ru_downlink_handler_generic_impl : public ru_downlink_plane_handler } // See interface for documentation. - void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override; + void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) override; private: std::vector handler; diff --git a/lib/ru/generic/ru_uplink_request_handler_generic_impl.cpp b/lib/ru/generic/ru_uplink_request_handler_generic_impl.cpp index 78de826140..e8a122eb43 100644 --- a/lib/ru/generic/ru_uplink_request_handler_generic_impl.cpp +++ b/lib/ru/generic/ru_uplink_request_handler_generic_impl.cpp @@ -12,6 +12,7 @@ #include "srsran/phy/lower/lower_phy_request_handler.h" #include "srsran/phy/support/prach_buffer_context.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; @@ -24,7 +25,7 @@ void ru_uplink_request_handler_generic_impl::handle_prach_occasion(const prach_b } void ru_uplink_request_handler_generic_impl::handle_new_uplink_slot(const resource_grid_context& context, - resource_grid& grid) + const shared_resource_grid& grid) { srsran_assert(context.sector < low_phy_handler.size(), "Invalid sector {}", context.sector); diff --git a/lib/ru/generic/ru_uplink_request_handler_generic_impl.h b/lib/ru/generic/ru_uplink_request_handler_generic_impl.h index e012a3e904..46adc92cf1 100644 --- a/lib/ru/generic/ru_uplink_request_handler_generic_impl.h +++ b/lib/ru/generic/ru_uplink_request_handler_generic_impl.h @@ -15,6 +15,7 @@ namespace srsran { class lower_phy_request_handler; +class shared_resource_grid; /// Radio Unit uplink request handler generic implementation. class ru_uplink_request_handler_generic_impl : public ru_uplink_plane_handler @@ -29,7 +30,7 @@ class ru_uplink_request_handler_generic_impl : public ru_uplink_plane_handler void handle_prach_occasion(const prach_buffer_context& context, prach_buffer& buffer) override; // See interface for documentation. - void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) override; + void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override; private: std::vector low_phy_handler; diff --git a/lib/ru/generic/rx_symbol_adapter.h b/lib/ru/generic/rx_symbol_adapter.h index 1656068a1c..bfbfe0d116 100644 --- a/lib/ru/generic/rx_symbol_adapter.h +++ b/lib/ru/generic/rx_symbol_adapter.h @@ -26,7 +26,7 @@ class ru_rx_symbol_adapter : public lower_phy_rx_symbol_notifier } // See interface for documentation. - void on_rx_symbol(const lower_phy_rx_symbol_context& context, const resource_grid_reader& grid) override + void on_rx_symbol(const lower_phy_rx_symbol_context& context, const shared_resource_grid& grid) override { ru_uplink_rx_symbol_context upper_context; upper_context.slot = context.slot; diff --git a/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.cpp b/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.cpp index 3cdd2f6e3c..d67660a428 100644 --- a/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.cpp +++ b/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.cpp @@ -11,11 +11,13 @@ #include "ru_ofh_downlink_plane_handler_proxy.h" #include "srsran/ofh/transmitter/ofh_downlink_handler.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" +#include using namespace srsran; void ru_downlink_plane_handler_proxy::handle_dl_data(const resource_grid_context& context, - const resource_grid_reader& grid) + const shared_resource_grid& grid) { srsran_assert(context.sector < sectors.size(), "Invalid sector id '{}'", context.sector); diff --git a/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.h b/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.h index ae733e44ef..a5cd45b799 100644 --- a/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.h +++ b/lib/ru/ofh/ru_ofh_downlink_plane_handler_proxy.h @@ -15,6 +15,7 @@ namespace srsran { class task_executor; +class shared_resource_grid; namespace ofh { class downlink_handler; @@ -31,7 +32,7 @@ class ru_downlink_plane_handler_proxy : public ru_downlink_plane_handler } // See interface for documentation. - void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override; + void handle_dl_data(const resource_grid_context& context, const shared_resource_grid& grid) override; private: std::vector sectors; diff --git a/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.cpp b/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.cpp index 8d7417cd0b..cfad327703 100644 --- a/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.cpp +++ b/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.cpp @@ -9,11 +9,12 @@ */ #include "ru_ofh_rx_symbol_handler_impl.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; void ru_ofh_rx_symbol_handler_impl::on_new_uplink_symbol(const ofh::uplane_rx_symbol_context& context, - const resource_grid_reader& grid) + shared_resource_grid grid) { ru_uplink_rx_symbol_context ru_context; ru_context.sector = context.sector; diff --git a/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.h b/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.h index a6ecac34c4..d77bc53f09 100644 --- a/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.h +++ b/lib/ru/ofh/ru_ofh_rx_symbol_handler_impl.h @@ -22,7 +22,7 @@ class ru_ofh_rx_symbol_handler_impl : public ofh::uplane_rx_symbol_notifier explicit ru_ofh_rx_symbol_handler_impl(ru_uplink_plane_rx_symbol_notifier& notifier_) : notifier(notifier_) {} // See interface for documentation. - void on_new_uplink_symbol(const ofh::uplane_rx_symbol_context& context, const resource_grid_reader& grid) override; + void on_new_uplink_symbol(const ofh::uplane_rx_symbol_context& context, shared_resource_grid grid) override; // See interface for documentation. void on_new_prach_window_data(const prach_buffer_context& context, const prach_buffer& buffer) override; diff --git a/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.cpp b/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.cpp index 75d53ed3fb..151a2a8187 100644 --- a/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.cpp +++ b/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.cpp @@ -12,6 +12,7 @@ #include "srsran/ofh/transmitter/ofh_uplink_request_handler.h" #include "srsran/phy/support/prach_buffer_context.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" using namespace srsran; @@ -23,9 +24,11 @@ void ru_uplink_plane_handler_proxy::handle_prach_occasion(const prach_buffer_con sector->handle_prach_occasion(context, buffer); } -void ru_uplink_plane_handler_proxy::handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) +void ru_uplink_plane_handler_proxy::handle_new_uplink_slot(const resource_grid_context& context, + const shared_resource_grid& grid) { srsran_assert(context.sector < sectors.size(), "Invalid sector id '{}'", context.sector); + srsran_assert(grid, "Invalid grid."); auto& sector = sectors[context.sector]; sector->handle_new_uplink_slot(context, grid); diff --git a/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.h b/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.h index 8aa931ae4b..f256735298 100644 --- a/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.h +++ b/lib/ru/ofh/ru_ofh_uplink_plane_handler_proxy.h @@ -15,6 +15,7 @@ namespace srsran { class task_executor; +class shared_resource_grid; namespace ofh { class uplink_request_handler; @@ -35,7 +36,7 @@ class ru_uplink_plane_handler_proxy : public ru_uplink_plane_handler void handle_prach_occasion(const prach_buffer_context& context, prach_buffer& buffer) override; // See interface for documentation. - void handle_new_uplink_slot(const resource_grid_context& context, resource_grid& grid) override; + void handle_new_uplink_slot(const resource_grid_context& context, const shared_resource_grid& grid) override; private: std::vector sectors; diff --git a/lib/support/executors/task_worker_pool.cpp b/lib/support/executors/task_worker_pool.cpp index e530ce90c8..ccafcd2bf9 100644 --- a/lib/support/executors/task_worker_pool.cpp +++ b/lib/support/executors/task_worker_pool.cpp @@ -168,8 +168,8 @@ template std::function task_worker_pool::create_pop_loop_task() { return [this]() { - unique_task job; while (true) { + unique_task job; if (not this->queue.pop_blocking(job)) { break; } diff --git a/tests/integrationtests/ofh/CMakeLists.txt b/tests/integrationtests/ofh/CMakeLists.txt index 7a22fbdf2c..b5f2060f26 100644 --- a/tests/integrationtests/ofh/CMakeLists.txt +++ b/tests/integrationtests/ofh/CMakeLists.txt @@ -9,7 +9,12 @@ set_directory_properties(PROPERTIES LABELS "ofh") add_executable(ofh_integration_test ofh_integration_test.cpp) -target_link_libraries(ofh_integration_test srslog srsran_ru_ofh srsran_phy_support srsran_support) +target_link_libraries(ofh_integration_test + srslog + srsran_ru_ofh + srsran_phy_support + srsran_channel_precoder + srsran_support) add_test(ofh_integration_test ofh_integration_test) set_tests_properties(ofh_integration_test PROPERTIES LABELS "tsan;NO_MEMCHECK") diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index 4a8daf6eb7..abbfde4563 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -8,7 +8,6 @@ * */ -#include "../../../lib/phy/support/resource_grid_impl.h" #include "helpers.h" #include "srsran/adt/bounded_bitset.h" #include "srsran/adt/circular_map.h" @@ -17,6 +16,9 @@ #include "srsran/ofh/ethernet/ethernet_gateway.h" #include "srsran/ofh/ethernet/ethernet_receiver.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/resource_grid_writer.h" +#include "srsran/phy/support/shared_resource_grid.h" +#include "srsran/phy/support/support_factories.h" #include "srsran/ru/ru_controller.h" #include "srsran/ru/ru_downlink_plane.h" #include "srsran/ru/ru_error_notifier.h" @@ -404,7 +406,10 @@ class dummy_rx_symbol_notifier : public ru_uplink_plane_rx_symbol_notifier { public: // See interface for documentation. - void on_new_uplink_symbol(const ru_uplink_rx_symbol_context& context, const resource_grid_reader& grid) override {} + void on_new_uplink_symbol(const ru_uplink_rx_symbol_context& context, const shared_resource_grid& grid) override + { + srsran_assert(grid, "Invalid grid."); + } // See interface for documentation. void on_new_prach_window_data(const prach_buffer_context& context, const prach_buffer& buffer) override {} @@ -656,13 +661,19 @@ class test_du_emulator { std::uniform_real_distribution dist(-1.0, +1.0); + std::shared_ptr precoder_factory = create_channel_precoder_factory("auto"); + report_fatal_error_if_not(precoder_factory, "Invalid factory"); + + std::shared_ptr rg_factory = create_resource_grid_factory(precoder_factory); + report_fatal_error_if_not(rg_factory, "Invalid factory"); + // Create resource grids according to TDD pattern. + std::vector> dl_resource_grids; for (unsigned rg_id = 0; rg_id != tdd_pattern.nof_dl_slots; rg_id++) { // Downlink. - dl_resource_grids.push_back(std::make_unique( - nof_antennas_dl, get_nsymb_per_slot(cyclic_prefix::NORMAL), nof_prb * NOF_SUBCARRIERS_PER_RB, nullptr)); - resource_grid_impl& grid = *dl_resource_grids.back(); - resource_grid_writer& rg_writer = grid.get_writer(); + dl_resource_grids.push_back( + rg_factory->create(nof_antennas_dl, MAX_NSYMB_PER_SLOT, nof_prb * NOF_SUBCARRIERS_PER_RB)); + resource_grid_writer& rg_writer = dl_resource_grids.back()->get_writer(); // Pre-generate random downlink data. for (unsigned sym = 0; sym != get_nsymb_per_slot(cyclic_prefix::NORMAL); ++sym) { @@ -673,11 +684,15 @@ class test_du_emulator } } } + dl_rg_pool = create_generic_resource_grid_pool(std::move(dl_resource_grids)); + // Uplink. + std::vector> ul_resource_grids; for (unsigned rg_id = 0; rg_id != tdd_pattern.nof_ul_slots; rg_id++) { - ul_resource_grids.push_back(std::make_unique( - nof_antennas_ul, get_nsymb_per_slot(cyclic_prefix::NORMAL), nof_prb * NOF_SUBCARRIERS_PER_RB, nullptr)); + ul_resource_grids.push_back( + rg_factory->create(nof_antennas_ul, MAX_NSYMB_PER_SLOT, nof_prb * NOF_SUBCARRIERS_PER_RB)); } + ul_rg_pool = create_generic_resource_grid_pool(std::move(ul_resource_grids)); } /// Starts the DU emulator. @@ -707,9 +722,12 @@ class test_du_emulator // Push downlink data. if (is_dl_slot) { - resource_grid_impl& grid = *dl_resource_grids[slot_id]; resource_grid_context context{slot, 0}; - dl_handler.handle_dl_data(context, grid.get_reader()); + + shared_resource_grid dl_grid = dl_rg_pool->allocate_resource_grid(context); + srsran_assert(dl_grid, "Failed to get grid."); + + dl_handler.handle_dl_data(context, std::move(dl_grid)); logger.info("DU emulator pushed DL data in slot {}", slot); } @@ -717,7 +735,11 @@ class test_du_emulator if (is_ul_slot) { slot_id = tdd_pattern.dl_ul_tx_period_nof_slots - slot_id - 1; resource_grid_context context{slot, 0}; - ul_handler.handle_new_uplink_slot(context, *ul_resource_grids[slot_id]); + + shared_resource_grid ul_grid = ul_rg_pool->allocate_resource_grid(context); + srsran_assert(ul_grid, "Failed to get grid."); + + ul_handler.handle_new_uplink_slot(context, std::move(ul_grid)); } // Sleep until the end of the slot. @@ -732,12 +754,12 @@ class test_du_emulator test_finished.store(true, std::memory_order_relaxed); } - srslog::basic_logger& logger; - std::vector> dl_resource_grids; - std::vector> ul_resource_grids; - task_executor& executor; - ru_downlink_plane_handler& dl_handler; - ru_uplink_plane_handler& ul_handler; + srslog::basic_logger& logger; + std::unique_ptr dl_rg_pool; + std::unique_ptr ul_rg_pool; + task_executor& executor; + ru_downlink_plane_handler& dl_handler; + ru_uplink_plane_handler& ul_handler; const unsigned nof_prb; std::chrono::microseconds slot_duration_us; diff --git a/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp b/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp index 9209464679..524c7693d9 100644 --- a/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp +++ b/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp @@ -68,14 +68,43 @@ class uplink_pdu_validator_dummy : public uplink_pdu_validator bool is_valid(const srs_estimator_configuration& config) const override { return true; } }; -class resource_grid_pool_dummy : public resource_grid_pool +class resource_grid_pool_dummy : public resource_grid_pool, private shared_resource_grid::pool_interface { - resource_grid& grid; - public: - explicit resource_grid_pool_dummy(resource_grid& grid_) : grid(grid_) {} + explicit resource_grid_pool_dummy() {} + + shared_resource_grid allocate_resource_grid(const resource_grid_context& context) override + { + unsigned expected_available_ref_count = 0; + bool available = ref_count.compare_exchange_strong(expected_available_ref_count, 1); + srsran_assert(available, "The grid must NOT be reserved."); + return {*this, ref_count, 0}; + } + + unsigned get_getter_count() const { return getter_count; } + + bool is_available() const { return ref_count == 0; } + +private: + resource_grid& get(unsigned identifier_) override + { + srsran_assert(identifier == identifier_, "Identifier unmatched."); + srsran_assert(ref_count != 0, "Reference counter must NOT be zero."); + ++getter_count; + return grid; + } + + void notify_release_scope(unsigned identifier_) override + { + srsran_assert(identifier == identifier_, "Identifier unmatched."); + srsran_assert(ref_count == 0, "Reference counter must be zero."); + } + + static constexpr unsigned identifier = 0; + std::atomic ref_count = {}; + unsigned getter_count = 0; - resource_grid& get_resource_grid(const srsran::resource_grid_context& context) override { return grid; } + resource_grid_dummy grid; }; class downlink_processor_pool_dummy : public downlink_processor_pool @@ -102,7 +131,6 @@ class downlink_processor_pool_dummy : public downlink_processor_pool class fapi_to_phy_translator_fixture : public ::testing::Test { protected: - resource_grid_spy grid; downlink_processor_pool_dummy dl_processor_pool; resource_grid_pool_dummy rg_pool; uplink_request_processor_dummy ul_request_processor; @@ -132,8 +160,7 @@ class fapi_to_phy_translator_fixture : public ::testing::Test fapi_to_phy_translator translator; public: - fapi_to_phy_translator_fixture() : - grid(0, 0, 0), rg_pool(grid), pdu_repo(2), worker(1), translator(config, std::move(dependencies)) + fapi_to_phy_translator_fixture() : pdu_repo(2), worker(1), translator(config, std::move(dependencies)) { translator.set_slot_error_message_notifier(error_notifier_spy); translator.handle_new_slot(slot); @@ -143,14 +170,14 @@ class fapi_to_phy_translator_fixture : public ::testing::Test TEST_F(fapi_to_phy_translator_fixture, downlink_processor_is_not_configured_on_new_slot) { ASSERT_FALSE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_TRUE(rg_pool.is_available()); ASSERT_FALSE(error_notifier_spy.has_on_error_indication_been_called()); } TEST_F(fapi_to_phy_translator_fixture, downlink_processor_is_configured_on_new_dl_tti_request) { ASSERT_FALSE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); fapi::dl_tti_request_message msg; msg.sfn = slot.sfn(); @@ -169,7 +196,7 @@ TEST_F(fapi_to_phy_translator_fixture, when_is_last_message_in_slot_flag_is_enabled_controller_is_released_at_the_dl_tti_handling) { ASSERT_FALSE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); fapi::dl_tti_request_message msg; msg.sfn = slot.sfn(); @@ -182,7 +209,7 @@ TEST_F(fapi_to_phy_translator_fixture, ASSERT_TRUE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); // Assert that the resource grid has not been set to zero. - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); ASSERT_FALSE(error_notifier_spy.has_on_error_indication_been_called()); ASSERT_TRUE(dl_processor_pool.processor(slot).has_finish_processing_pdus_method_been_called()); } @@ -193,7 +220,7 @@ TEST_F(fapi_to_phy_translator_fixture, dl_ssb_pdu_is_processed) slot_point msg_slot(scs, msg.sfn, msg.slot); ASSERT_FALSE(dl_processor_pool.processor(msg_slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); translator.handle_new_slot(msg_slot); // Process SSB PDU. @@ -203,7 +230,7 @@ TEST_F(fapi_to_phy_translator_fixture, dl_ssb_pdu_is_processed) ASSERT_TRUE(dl_processor_pool.processor(msg_slot).has_configure_resource_grid_method_been_called()); ASSERT_TRUE(dl_processor_pool.processor(msg_slot).has_process_ssb_method_been_called()); // Assert that the resource grid has NOT been set to zero. - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); translator.handle_new_slot(msg_slot + 1); ++msg.slot; @@ -220,7 +247,7 @@ TEST_F(fapi_to_phy_translator_fixture, dl_ssb_pdu_within_allowed_delay_is_proces slot_point msg_slot(scs, msg.sfn, msg.slot); ASSERT_FALSE(dl_processor_pool.processor(msg_slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); translator.handle_new_slot(msg_slot); @@ -236,14 +263,14 @@ TEST_F(fapi_to_phy_translator_fixture, dl_ssb_pdu_within_allowed_delay_is_proces ASSERT_TRUE(dl_processor_pool.processor(msg_slot).has_configure_resource_grid_method_been_called()); ASSERT_TRUE(dl_processor_pool.processor(msg_slot).has_process_ssb_method_been_called()); // Assert that the resource grid has NOT been set to zero. - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); ASSERT_FALSE(error_notifier_spy.has_on_error_indication_been_called()); } TEST_F(fapi_to_phy_translator_fixture, receiving_a_dl_tti_request_sends_previous_slot) { ASSERT_FALSE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); fapi::dl_tti_request_message msg; msg.sfn = slot.sfn(); @@ -261,7 +288,7 @@ TEST_F(fapi_to_phy_translator_fixture, receiving_a_dl_tti_request_sends_previous // Assert that the downlink processor is configured. ASSERT_TRUE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); // Assert that the resource grid has NOT been set to zero. - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); // Send another DL_TTI.request and check that the previous one has been sent. ++msg.slot; @@ -306,7 +333,7 @@ TEST_F(fapi_to_phy_translator_fixture, receiving_a_dl_tti_request_from_a_slot_de TEST_F(fapi_to_phy_translator_fixture, message_received_is_sended_when_a_message_for_the_next_slot_is_received) { ASSERT_FALSE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); fapi::dl_tti_request_message msg; msg.sfn = slot.sfn(); @@ -319,7 +346,7 @@ TEST_F(fapi_to_phy_translator_fixture, message_received_is_sended_when_a_message // Assert that the downlink processor is configured. ASSERT_TRUE(dl_processor_pool.processor(slot).has_configure_resource_grid_method_been_called()); // Assert that the resource grid has NOT been set to zero. - ASSERT_FALSE(grid.has_set_all_zero_method_been_called()); + ASSERT_EQ(rg_pool.get_getter_count(), 0); // Increase the slots. ASSERT_FALSE(dl_processor_pool.processor(slot).has_finish_processing_pdus_method_been_called()); diff --git a/tests/unittests/ofh/ofh_uplane_rx_symbol_notifier_test_doubles.h b/tests/unittests/ofh/ofh_uplane_rx_symbol_notifier_test_doubles.h index 961d0beb08..769f6edd9e 100644 --- a/tests/unittests/ofh/ofh_uplane_rx_symbol_notifier_test_doubles.h +++ b/tests/unittests/ofh/ofh_uplane_rx_symbol_notifier_test_doubles.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" +#include "srsran/phy/support/shared_resource_grid.h" namespace srsran { namespace ofh { @@ -24,7 +25,7 @@ class uplane_rx_symbol_notifier_spy : public uplane_rx_symbol_notifier public: // See interface for documentation. - void on_new_uplink_symbol(const uplane_rx_symbol_context& context, const resource_grid_reader& grid) override + void on_new_uplink_symbol(const uplane_rx_symbol_context& context, shared_resource_grid grid) override { new_uplink_symbol_function_called = true; } diff --git a/tests/unittests/ofh/receiver/helpers.h b/tests/unittests/ofh/receiver/helpers.h index e47dfa8c99..ba24f3b72d 100644 --- a/tests/unittests/ofh/receiver/helpers.h +++ b/tests/unittests/ofh/receiver/helpers.h @@ -78,7 +78,7 @@ class resource_grid_writer_bool_spy : public resource_grid_writer } unsigned get_nof_ports() const override { return 1; }; - unsigned get_nof_subc() const override { return 51 * NOF_SUBCARRIERS_PER_RB; }; + unsigned get_nof_subc() const override { return grid_data.size(); }; unsigned get_nof_symbols() const override { return MAX_NSYMB_PER_SLOT; }; span put(unsigned port, @@ -141,24 +141,6 @@ class resource_grid_writer_bool_spy : public resource_grid_writer } }; -class resource_grid_dummy_with_spy_writer : public resource_grid -{ - resource_grid_writer_bool_spy& writer; - resource_grid_reader_spy reader; - resource_grid_mapper_dummy mapper; - -public: - explicit resource_grid_dummy_with_spy_writer(resource_grid_writer_bool_spy& writer_) : - writer(writer_), reader(1, 14, 51) - { - } - - void set_all_zero() override {} - resource_grid_writer& get_writer() override { return writer; } - const resource_grid_reader& get_reader() const override { return reader; } - resource_grid_mapper& get_mapper() override { return mapper; } -}; - } // namespace testing } // namespace ofh } // namespace srsran diff --git a/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp b/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp index 8d226c839d..78a1f6e759 100644 --- a/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp @@ -45,7 +45,9 @@ class data_flow_uplane_uplink_data_impl_fixture : public ::testing::Test unsigned sector = 0; unsigned eaxc = 5; resource_grid_writer_bool_spy rg_writer; - resource_grid_dummy_with_spy_writer grid; + resource_grid_reader_spy rg_reader; + resource_grid_spy grid; + shared_resource_grid_spy shared_grid; uplane_rx_symbol_notifier_spy* notifier; std::shared_ptr ul_cplane_context_repo_ptr = std::make_shared(1); @@ -55,7 +57,12 @@ class data_flow_uplane_uplink_data_impl_fixture : public ::testing::Test public: data_flow_uplane_uplink_data_impl_fixture() : - slot(0, 0, 1), rg_writer(nof_prbs), grid(rg_writer), data_flow(get_config(), get_dependencies()) + slot(0, 0, 1), + rg_writer(nof_prbs), + rg_reader(rg_writer.get_nof_ports(), rg_writer.get_nof_symbols(), nof_prbs), + grid(rg_reader, rg_writer), + shared_grid(grid), + data_flow(get_config(), get_dependencies()) { ul_cplane_context context; context.prb_start = 0; @@ -68,7 +75,7 @@ class data_flow_uplane_uplink_data_impl_fixture : public ::testing::Test // Fill the contexts ul_cplane_context_repo_ptr->add(slot, eaxc, context); - ul_context_repo->add({slot, sector}, grid, {context.radio_hdr.start_symbol, context.nof_symbols}); + ul_context_repo->add({slot, sector}, shared_grid.get_grid(), {context.radio_hdr.start_symbol, context.nof_symbols}); } data_flow_uplane_uplink_data_impl_config get_config() diff --git a/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp b/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp index 9617e420fa..6af0cbe3ca 100644 --- a/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp @@ -16,6 +16,7 @@ #include "../compression/ofh_iq_decompressor_test_doubles.h" #include "srsran/ofh/ethernet/ethernet_unique_buffer.h" #include "srsran/ofh/ofh_factories.h" +#include "srsran/phy/support/shared_resource_grid.h" #include using namespace srsran; @@ -28,7 +29,7 @@ namespace { class dummy_uplane_rx_symbol_notifier : public uplane_rx_symbol_notifier { public: - void on_new_uplink_symbol(const uplane_rx_symbol_context& context, const resource_grid_reader& grid) override {} + void on_new_uplink_symbol(const uplane_rx_symbol_context& context, shared_resource_grid grid) override {} void on_new_prach_window_data(const prach_buffer_context& context, const prach_buffer& buffer) override {} }; diff --git a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp index 6c275d9ccf..a1ccf98973 100644 --- a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp @@ -17,7 +17,20 @@ using namespace srsran; using namespace ofh; using namespace ofh::testing; -static constexpr ofdm_symbol_range symbol_range = {0, 14}; +static constexpr ofdm_symbol_range symbol_range = {0, 14}; +static constexpr unsigned nof_prb = MAX_NOF_PRBS; +static constexpr unsigned nof_ports = 2; +static constexpr unsigned nof_ofdm_symbols = symbol_range.stop(); + +static shared_resource_grid get_resource_grid() +{ + static resource_grid_reader_spy reader_spy(nof_ports, nof_ofdm_symbols, nof_prb); + static resource_grid_writer_spy writer_spy(nof_ports, nof_ofdm_symbols, nof_prb); + static resource_grid_spy grid(reader_spy, writer_spy); + static shared_resource_grid_spy shared_grid(grid); + + return shared_grid.get_grid(); +} TEST(ofh_data_flow_uplane_rx_symbol_notifier, empty_context_does_not_notify) { @@ -42,9 +55,8 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, unwritten_grid_does_not_notify) slot_point slot(0, 0, 1); unsigned symbol = 0; unsigned sector = 0; - resource_grid_spy grid(2, 14, 273); - repo->add({slot, sector}, grid, symbol_range); + repo->add({slot, sector}, get_resource_grid(), symbol_range); sender.notify_received_symbol(slot, symbol); ASSERT_FALSE(repo->get(slot, symbol).empty()); @@ -60,14 +72,13 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, completed_resource_grid_triggers_n slot_point slot(0, 0, 1); unsigned symbol = 0; unsigned sector = 0; - resource_grid_spy grid(2, 14, 273); - static_vector samples(grid.get_writer().get_nof_subc()); - repo->add({slot, sector}, grid, symbol_range); + std::vector samples(nof_prb * NOF_SUBCARRIERS_PER_RB); + repo->add({slot, sector}, get_resource_grid(), symbol_range); ASSERT_FALSE(repo->get(slot, symbol).empty()); // Fill the grid. - for (unsigned port = 0, port_end = grid.get_writer().get_nof_ports(); port != port_end; ++port) { + for (unsigned port = 0; port != nof_ports; ++port) { repo->write_grid(slot, port, symbol, 0, samples); } @@ -89,10 +100,9 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, uncompleted_port_does_not_notify) slot_point slot(0, 0, 1); unsigned symbol = 0; unsigned sector = 0; - resource_grid_spy grid(2, 14, 273); - static_vector samples(grid.get_writer().get_nof_subc()); - repo->add({slot, sector}, grid, symbol_range); + std::vector samples(nof_prb * NOF_SUBCARRIERS_PER_RB); + repo->add({slot, sector}, get_resource_grid(), symbol_range); // Fill the grid. repo->write_grid(slot, 0, symbol, 0, samples); @@ -112,10 +122,9 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, uncompleted_prbs_does_not_notify) slot_point slot(0, 0, 1); unsigned symbol = 0; unsigned sector = 0; - resource_grid_spy grid(1, 14, 273); - static_vector samples(grid.get_writer().get_nof_subc() - 1); - repo->add({slot, sector}, grid, symbol_range); + std::vector samples(nof_prb * NOF_SUBCARRIERS_PER_RB); + repo->add({slot, sector}, get_resource_grid(), symbol_range); // Fill the grid. repo->write_grid(slot, 0, symbol, 0, samples); diff --git a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp index 92057ddb02..d376279258 100644 --- a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp @@ -20,20 +20,28 @@ using namespace ofh::testing; class ofh_uplane_rx_symbol_data_flow_writer_fixture : public ::testing::Test { protected: - const ofdm_symbol_range symbol_range = {0, 14}; - static_vector eaxc = {0, 1, 2, 3}; - std::shared_ptr repo = std::make_shared(1); - unsigned sector = 0; - slot_point slot; - unsigned symbol_id = 0; - resource_grid_writer_bool_spy rg_writer; - resource_grid_dummy_with_spy_writer grid; - uplane_message_decoder_results results; - uplane_rx_symbol_data_flow_writer writer; + static constexpr ofdm_symbol_range symbol_range = {0, 14}; + static constexpr unsigned nof_ports = 1; + static constexpr unsigned nof_prb = 51; + static constexpr unsigned sector = 0; + static constexpr unsigned symbol_id = 0; + static constexpr std::array eaxc = {0, 1, 2, 3}; + static constexpr slot_point slot = {0, 0, 1}; + resource_grid_writer_bool_spy rg_writer; + resource_grid_reader_spy rg_reader; + resource_grid_spy grid; + shared_resource_grid_spy shared_grid; + std::shared_ptr repo = std::make_shared(1); + uplane_message_decoder_results results; + uplane_rx_symbol_data_flow_writer writer; public: ofh_uplane_rx_symbol_data_flow_writer_fixture() : - slot(0, 0, 1), rg_writer(MAX_NOF_PRBS), grid(rg_writer), writer(eaxc, srslog::fetch_basic_logger("TEST"), repo) + rg_writer(nof_prb), + rg_reader(nof_ports, symbol_range.stop(), nof_prb), + grid(rg_reader, rg_writer), + shared_grid(grid), + writer(eaxc, srslog::fetch_basic_logger("TEST"), repo) { results.params.slot = slot; results.params.symbol_id = symbol_id; @@ -54,7 +62,7 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, death_test_no_eaxc_found) { unsigned invalid_eaxc = 4; - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_DEATH(writer.write_to_resource_grid(invalid_eaxc, results), ""); @@ -65,17 +73,17 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, decoded_prbs_outside_grid_ { auto& section = results.sections.back(); section.nof_prbs = 50; - section.start_prb = 51; + section.start_prb = nof_prb; section.iq_samples.resize(section.nof_prbs * NOF_SUBCARRIERS_PER_RB); - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); writer.write_to_resource_grid(eaxc[0], results); ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_FALSE(rg_writer.has_grid_been_written()); - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [](const auto& port) { return port.none(); })); } @@ -86,15 +94,15 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, decoded_prbs_match_grid_pr section.start_prb = 0; section.iq_samples.resize(section.nof_prbs * NOF_SUBCARRIERS_PER_RB); - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); writer.write_to_resource_grid(eaxc[0], results); ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_TRUE(rg_writer.has_grid_been_written()); ASSERT_EQ(section.nof_prbs, rg_writer.get_nof_prbs_written()); - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [](const auto& port) { return port.all(); })); } @@ -105,15 +113,15 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, decoded_prbs_bigger_than_g section.start_prb = 0; section.iq_samples.resize(section.nof_prbs * NOF_SUBCARRIERS_PER_RB); - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); writer.write_to_resource_grid(eaxc[0], results); ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_TRUE(rg_writer.has_grid_been_written()); ASSERT_EQ(rg_writer.get_nof_subc() / NOF_SUBCARRIERS_PER_RB, rg_writer.get_nof_prbs_written()); - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [](const auto& port) { return port.all(); })); } @@ -124,15 +132,15 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, segmented_prbs_inside_the_ section.start_prb = 0; section.iq_samples.resize(section.nof_prbs * NOF_SUBCARRIERS_PER_RB); - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); writer.write_to_resource_grid(eaxc[0], results); ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_TRUE(rg_writer.has_grid_been_written()); ASSERT_EQ(section.nof_prbs, rg_writer.get_nof_prbs_written()); - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [§ion](const auto& port) { return port.all(0, (section.nof_prbs - 1) * NOF_SUBCARRIERS_PER_RB); })); @@ -145,15 +153,15 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, segmented_prbs_write_the_p section.start_prb = 40; section.iq_samples.resize(section.nof_prbs * NOF_SUBCARRIERS_PER_RB); - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); writer.write_to_resource_grid(eaxc[0], results); ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_TRUE(rg_writer.has_grid_been_written()); ASSERT_EQ(11, rg_writer.get_nof_prbs_written()); - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [](const auto& port) { return port.all(40 * NOF_SUBCARRIERS_PER_RB, 50 * NOF_SUBCARRIERS_PER_RB); })); @@ -166,12 +174,12 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, segmented_prbs_fill_the_gr section.start_prb = 0; section.iq_samples.resize(section.nof_prbs * NOF_SUBCARRIERS_PER_RB); - repo->add({results.params.slot, sector}, grid, symbol_range); + repo->add({results.params.slot, sector}, shared_grid.get_grid(), symbol_range); writer.write_to_resource_grid(eaxc[0], results); ASSERT_EQ(section.nof_prbs, rg_writer.get_nof_prbs_written()); { - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [§ion](const auto& port) { return port.all(0, (section.nof_prbs - 1) * NOF_SUBCARRIERS_PER_RB); })); @@ -189,7 +197,7 @@ TEST_F(ofh_uplane_rx_symbol_data_flow_writer_fixture, segmented_prbs_fill_the_gr ASSERT_FALSE(repo->get(results.params.slot, results.params.symbol_id).empty()); ASSERT_TRUE(rg_writer.has_grid_been_written()); ASSERT_EQ(nof_prbs, rg_writer.get_nof_prbs_written()); - uplink_context context = repo->get(slot, symbol_id); - const auto& sym_data = context.get_re_written_mask(); + const uplink_context& context = repo->get(slot, symbol_id); + const auto& sym_data = context.get_re_written_mask(); ASSERT_TRUE(std::all_of(sym_data.begin(), sym_data.end(), [](const auto& port) { return port.all(); })); } diff --git a/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp index 7dca2785ba..ef39c978e3 100644 --- a/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp @@ -78,13 +78,18 @@ class ofh_data_flow_uplane_downlink_data_impl_fixture : public ::testing::TestWi ecpri::testing::packet_builder_spy* ecpri_builder; ofh_uplane_packet_builder_spy* uplane_builder; resource_grid_reader_spy rg_reader_spy; + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy; + shared_resource_grid_spy shared_rg_spy; ofh_data_flow_uplane_downlink_data_impl_fixture() : nof_symbols(3), ru_nof_prbs(273), du_nof_prbs(273), data_flow(get_config(), generate_data_flow_dependencies()), - rg_reader_spy(1, nof_symbols, du_nof_prbs) + rg_reader_spy(1, nof_symbols, du_nof_prbs), + rg_spy(rg_reader_spy, rg_writer_spy), + shared_rg_spy(rg_spy) { initialize_grid_reader(); } @@ -153,7 +158,7 @@ TEST_P(ofh_data_flow_uplane_downlink_data_impl_fixture, calling_enqueue_section_ context.eaxc = 2; context.symbol_range = {0, 3}; - data_flow.enqueue_section_type_1_message(context, rg_reader_spy); + data_flow.enqueue_section_type_1_message(context, shared_rg_spy.get_grid()); // Assert VLAN parameters. const ether::vlan_frame_params& vlan = vlan_builder->get_vlan_frame_params(); @@ -261,9 +266,12 @@ TEST(ofh_data_flow_uplane_downlink_data_impl, resource_grid_reader_spy::expected_entry_t{0, symbol, k, (k > 200) ? cf_t{1, 1} : cf_t{1, 0}}); } } + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy shared_rg_spy(rg_spy); data_flow_uplane_downlink_data_impl data_flow(config, std::move(dependencies)); - data_flow.enqueue_section_type_1_message(context, rg_reader_spy); + data_flow.enqueue_section_type_1_message(context, shared_rg_spy.get_grid()); // Assert number of packets. ASSERT_EQ(uplane_builder->nof_built_packets(), context.symbol_range.length()); @@ -314,9 +322,12 @@ TEST(ofh_data_flow_uplane_downlink_data_impl, frame_buffer_size_of_nof_prbs_gene resource_grid_reader_spy::expected_entry_t{0, symbol, k, (k > 200) ? cf_t{1, 1} : cf_t{1, 0}}); } } + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy shared_rg_spy(rg_spy); data_flow_uplane_downlink_data_impl data_flow(config, std::move(dependencies)); - data_flow.enqueue_section_type_1_message(context, rg_reader_spy); + data_flow.enqueue_section_type_1_message(context, shared_rg_spy.get_grid()); // Assert number of packets. As the packet should not fit in the frame, check that it generated 2 packets per symbol. ASSERT_EQ(uplane_builder->nof_built_packets(), context.symbol_range.length() * 2); diff --git a/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp index e471e2e29a..2c8be49c4a 100644 --- a/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp @@ -11,9 +11,10 @@ #include "../../../../lib/ofh/transmitter/helpers.h" #include "../../../../lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data.h" #include "../../../../lib/ofh/transmitter/ofh_downlink_handler_impl.h" +#include "../../phy/support/resource_grid_test_doubles.h" #include "ofh_data_flow_cplane_scheduling_commands_test_doubles.h" #include "srsran/phy/support/resource_grid_context.h" -#include "srsran/phy/support/resource_grid_reader_empty.h" +#include "srsran/phy/support/shared_resource_grid.h" #include using namespace srsran; @@ -32,7 +33,7 @@ class data_flow_uplane_downlink_data_spy : public data_flow_uplane_downlink_data public: // See interface for documentation. void enqueue_section_type_1_message(const data_flow_uplane_resource_grid_context& context, - const resource_grid_reader& grid) override + const shared_resource_grid& grid) override { has_enqueue_section_type_1_message_method_been_called = true; eaxc = context.eaxc; @@ -86,8 +87,11 @@ TEST(ofh_downlink_handler_impl, handling_downlink_data_use_control_and_user_plan downlink_handler_impl handler(config, std::move(dependencies)); - resource_grid_reader_empty rg(1, 1, 1); - resource_grid_context rg_context; + resource_grid_reader_spy rg_reader_spy(1, 1, 1); + resource_grid_writer_spy rg_writer_spy(1, 1, 1); + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy rg(rg_spy); + resource_grid_context rg_context; rg_context.slot = slot_point(1, 1, 1); rg_context.sector = 1; @@ -99,7 +103,7 @@ TEST(ofh_downlink_handler_impl, handling_downlink_data_use_control_and_user_plan (3 * calculate_nof_symbols_before_ota(config.cp, config.scs, config.dl_processing_time, config.tx_timing_params)); handler.get_ota_symbol_boundary_notifier().on_new_symbol(ota_time); - handler.handle_dl_data(rg_context, rg); + handler.handle_dl_data(rg_context, rg.get_grid()); // Assert Control-Plane. ASSERT_TRUE(cplane_spy.has_enqueue_section_type_1_method_been_called()); @@ -132,8 +136,12 @@ TEST(ofh_downlink_handler_impl, late_rg_is_not_handled) downlink_handler_impl handler(config, std::move(dependencies)); - resource_grid_reader_empty rg(1, 1, 1); - resource_grid_context rg_context; + resource_grid_reader_spy rg_reader_spy(1, 1, 1); + resource_grid_writer_spy rg_writer_spy(1, 1, 1); + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy rg(rg_spy); + + resource_grid_context rg_context; rg_context.slot = slot_point(1, 1, 1); rg_context.sector = 1; @@ -146,7 +154,7 @@ TEST(ofh_downlink_handler_impl, late_rg_is_not_handled) handler.get_ota_symbol_boundary_notifier().on_new_symbol(ota_time); - handler.handle_dl_data(rg_context, rg); + handler.handle_dl_data(rg_context, rg.get_grid()); // Assert Control-Plane. ASSERT_FALSE(cplane_spy.has_enqueue_section_type_1_method_been_called()); @@ -171,8 +179,12 @@ TEST(ofh_downlink_handler_impl, same_slot_fails) downlink_handler_impl handler(config, std::move(dependencies)); - resource_grid_reader_empty rg(1, 1, 1); - resource_grid_context rg_context; + resource_grid_reader_spy rg_reader_spy(1, 1, 1); + resource_grid_writer_spy rg_writer_spy(1, 1, 1); + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy rg(rg_spy); + + resource_grid_context rg_context; rg_context.slot = slot_point(1, 1, 1); rg_context.sector = 1; @@ -181,7 +193,7 @@ TEST(ofh_downlink_handler_impl, same_slot_fails) // Same slot and symbol than the resource grid. handler.get_ota_symbol_boundary_notifier().on_new_symbol(ota_time); - handler.handle_dl_data(rg_context, rg); + handler.handle_dl_data(rg_context, rg.get_grid()); // Assert Control-Plane. ASSERT_FALSE(cplane_spy.has_enqueue_section_type_1_method_been_called()); @@ -206,8 +218,12 @@ TEST(ofh_downlink_handler_impl, rg_in_the_frontier_is_handled) downlink_handler_impl handler(config, std::move(dependencies)); - resource_grid_reader_empty rg(1, 1, 1); - resource_grid_context rg_context; + resource_grid_reader_spy rg_reader_spy(1, 1, 1); + resource_grid_writer_spy rg_writer_spy(1, 1, 1); + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy rg(rg_spy); + + resource_grid_context rg_context; rg_context.slot = slot_point(1, 1, 1); rg_context.sector = 1; @@ -220,7 +236,7 @@ TEST(ofh_downlink_handler_impl, rg_in_the_frontier_is_handled) handler.get_ota_symbol_boundary_notifier().on_new_symbol(ota_time); - handler.handle_dl_data(rg_context, rg); + handler.handle_dl_data(rg_context, rg.get_grid()); // Assert Control-Plane. ASSERT_TRUE(cplane_spy.has_enqueue_section_type_1_method_been_called()); diff --git a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp index 41cfaac9e4..464d4db967 100644 --- a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp @@ -9,6 +9,7 @@ */ #include "../../../../lib/ofh/transmitter/ofh_uplink_request_handler_impl.h" +#include "../../phy/support/resource_grid_test_doubles.h" #include "ofh_data_flow_cplane_scheduling_commands_test_doubles.h" #include "srsran/ofh/ofh_uplane_rx_symbol_notifier.h" #include "srsran/phy/support/prach_buffer.h" @@ -35,9 +36,9 @@ class uplane_rx_symbol_notifier_spy : public uplane_rx_symbol_notifier const resource_grid_reader* rg_reader = nullptr; public: - void on_new_uplink_symbol(const uplane_rx_symbol_context& context, const resource_grid_reader& grid) override + void on_new_uplink_symbol(const uplane_rx_symbol_context& context, shared_resource_grid grid) override { - rg_reader = &grid; + rg_reader = &(grid.get_reader()); } void on_new_prach_window_data(const prach_buffer_context& context, const prach_buffer& buffer) override {} @@ -72,105 +73,16 @@ class prach_buffer_dummy : public prach_buffer } }; -class resource_grid_dummy : public resource_grid -{ - class resource_grid_mapper_dummy : public resource_grid_mapper - { - public: - void - map(const re_buffer_reader<>& input, const re_pattern& pattern, const precoding_configuration& precoding) override - { - } - - void map(symbol_buffer& buffer, - const re_pattern_list& pattern, - const re_pattern_list& reserved, - const precoding_configuration& precoding, - unsigned re_skip) override - { - } - }; - - class resource_grid_writer_dummy : public resource_grid_writer - { - public: - unsigned get_nof_ports() const override { return 1; } - unsigned get_nof_subc() const override { return 1; } - unsigned get_nof_symbols() const override { return 14; } - - span put(unsigned port, - unsigned l, - unsigned k_init, - const bounded_bitset& mask, - span symbols) override - { - return {}; - } - - span put(unsigned port, - unsigned l, - unsigned k_init, - const bounded_bitset& mask, - span symbols) override - { - return {}; - } - - void put(unsigned port, unsigned l, unsigned k_init, span symbols) override {} - void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override {} - span get_view(unsigned port, unsigned l) override { return {}; } - }; - - class resource_grid_reader_dummy : public resource_grid_reader - { - public: - unsigned get_nof_ports() const override { return 1; } - unsigned get_nof_subc() const override { return 1; } - unsigned get_nof_symbols() const override { return 14; } - bool is_empty(unsigned port) const override { return true; } - bool is_empty() const override { return true; } - span get(span symbols, - unsigned port, - unsigned l, - unsigned k_init, - const bounded_bitset& mask) const override - { - return {}; - } - span get(span symbols, - unsigned port, - unsigned l, - unsigned k_init, - const bounded_bitset& mask) const override - { - return {}; - } - void get(span symbols, unsigned port, unsigned l, unsigned k_init, unsigned stride) const override {} - void get(span symbols, unsigned port, unsigned l, unsigned k_init) const override {} - - span get_view(unsigned port, unsigned l) const override { return {}; } - }; - - resource_grid_reader_dummy reader; - resource_grid_writer_dummy writer; - resource_grid_mapper_dummy mapper; - -public: - void set_all_zero() override {} - - resource_grid_writer& get_writer() override { return writer; } - - const resource_grid_reader& get_reader() const override { return reader; } - - resource_grid_mapper& get_mapper() override { return mapper; } -}; - class ofh_uplink_request_handler_impl_fixture : public ::testing::Test { protected: const cyclic_prefix cp = {cyclic_prefix::NORMAL}; const tdd_ul_dl_config_common ttd_pattern = {subcarrier_spacing::kHz30, {10, 6, 6, 3, 3}, {}}; uplink_request_handler_impl_config cfg; + resource_grid_reader_spy reader_spy; + resource_grid_writer_spy writer_spy; + resource_grid_spy grid; + shared_resource_grid_spy shared_grid; std::shared_ptr ul_slot_repo; std::shared_ptr ul_prach_repo; data_flow_cplane_scheduling_commands_spy* data_flow; @@ -179,6 +91,10 @@ class ofh_uplink_request_handler_impl_fixture : public ::testing::Test uplink_request_handler_impl handler_prach_cp_en; explicit ofh_uplink_request_handler_impl_fixture() : + reader_spy(1, 14, 1), + writer_spy(1, 14, 1), + grid(reader_spy, writer_spy), + shared_grid(grid), ul_slot_repo(std::make_shared(REPOSITORY_SIZE)), ul_prach_repo(std::make_shared(REPOSITORY_SIZE)), handler(get_config_prach_cp_disabled(), get_dependencies_prach_cp_disabled()), @@ -284,12 +200,11 @@ TEST_F(ofh_uplink_request_handler_impl_fixture, handle_prach_request_generates_c TEST_F(ofh_uplink_request_handler_impl_fixture, handle_uplink_slot_generates_cplane_message) { - resource_grid_dummy rg; resource_grid_context rg_context; rg_context.slot = slot_point(1, 1, 7); rg_context.sector = 1; - handler.handle_new_uplink_slot(rg_context, rg); + handler.handle_new_uplink_slot(rg_context, shared_grid.get_grid()); // Assert data flow. ASSERT_TRUE(data_flow->has_enqueue_section_type_1_method_been_called()); @@ -299,25 +214,24 @@ TEST_F(ofh_uplink_request_handler_impl_fixture, handle_uplink_slot_generates_cpl ASSERT_EQ(data_direction::uplink, info.direction); const ofdm_symbol_range symbol_range = get_active_tdd_ul_symbols(ttd_pattern, rg_context.slot.slot_index(), cp); - for (unsigned i = 0, e = rg.get_writer().get_nof_symbols(); i != e; ++i) { + for (unsigned i = 0, e = writer_spy.get_nof_symbols(); i != e; ++i) { ASSERT_FALSE(ul_slot_repo->get(rg_context.slot, i).empty()); } // Assert that the symbol range equals the number of symbols of the grid. ASSERT_EQ(0, symbol_range.start()); - ASSERT_EQ(rg.get_writer().get_nof_symbols(), symbol_range.stop()); + ASSERT_EQ(writer_spy.get_nof_symbols(), symbol_range.stop()); } TEST_F(ofh_uplink_request_handler_impl_fixture, handle_uplink_in_special_slot_generates_cplane_message_with_valid_symbols) { - resource_grid_dummy rg; resource_grid_context rg_context; // Use special slot. rg_context.slot = slot_point(1, 1, 6); rg_context.sector = 1; - handler.handle_new_uplink_slot(rg_context, rg); + handler.handle_new_uplink_slot(rg_context, shared_grid.get_grid()); // Assert data flow. ASSERT_TRUE(data_flow->has_enqueue_section_type_1_method_been_called()); @@ -327,7 +241,7 @@ TEST_F(ofh_uplink_request_handler_impl_fixture, ASSERT_EQ(data_direction::uplink, info.direction); const ofdm_symbol_range symbol_range = get_active_tdd_ul_symbols(ttd_pattern, rg_context.slot.slot_index(), cp); - for (unsigned i = 0, e = rg.get_writer().get_nof_symbols(); i != e; ++i) { + for (unsigned i = 0, e = writer_spy.get_nof_symbols(); i != e; ++i) { if (i >= symbol_range.start() && i < symbol_range.stop()) { ASSERT_FALSE(ul_slot_repo->get(rg_context.slot, i).empty()); } else { diff --git a/tests/unittests/phy/lower/lower_phy_test.cpp b/tests/unittests/phy/lower/lower_phy_test.cpp index 243308cdcf..ff5be187fc 100644 --- a/tests/unittests/phy/lower/lower_phy_test.cpp +++ b/tests/unittests/phy/lower/lower_phy_test.cpp @@ -629,13 +629,16 @@ TEST_P(LowerPhyFixture, RxSymbolNotifiers) context.sector = sector_id_dist(rgen); context.slot = slot_point(to_numerology_value(scs), slot_dist(rgen)); context.nof_symbols = 123; - resource_grid_reader_spy rg_spy; - puxch_notifier->on_rx_symbol(rg_spy, context); + resource_grid_reader_spy rg_reader_spy; + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy shared_rg(rg_spy); + puxch_notifier->on_rx_symbol(shared_rg.get_grid(), context); auto& entries = rx_symbol_notifier_spy.get_rx_symbol_events(); ASSERT_EQ(entries.size(), 1); ASSERT_EQ(context, entries.back().context); - ASSERT_EQ(&rg_spy, entries.back().grid); - ASSERT_EQ(rg_spy.get_count(), 0); + ASSERT_EQ(&rg_reader_spy, entries.back().grid); + ASSERT_EQ(rg_reader_spy.get_count(), 0); } // Assert only two error events. @@ -657,18 +660,23 @@ TEST_P(LowerPhyFixture, RgHandler) context.slot = slot_point(to_numerology_value(scs), slot_dist(rgen)); // Prepare RG spy. - resource_grid_reader_spy rg_spy; + resource_grid_reader_spy rg_reader_spy; + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy unique_rg_spy(rg_spy); // Handle RG. - rg_handler.handle_resource_grid(context, rg_spy); + rg_handler.handle_resource_grid(context, unique_rg_spy.get_grid()); // Assert RG. auto& pdxch_entries = pdxch_proc_spy.get_entries(); ASSERT_EQ(pdxch_entries.size(), 1); auto& pdxch_entry = pdxch_entries.back(); ASSERT_EQ(pdxch_entry.context, context); - ASSERT_EQ(pdxch_entry.grid, &rg_spy); - ASSERT_EQ(rg_spy.get_count(), 0); + ASSERT_EQ(pdxch_entry.grid, &rg_reader_spy); + ASSERT_EQ(rg_reader_spy.get_count(), 0); + ASSERT_EQ(rg_writer_spy.get_count(), 0); + ASSERT_EQ(rg_spy.get_all_zero_count(), 0); } TEST_P(LowerPhyFixture, PrachRequestHandler) @@ -722,10 +730,13 @@ TEST_P(LowerPhyFixture, PuxchRequestHandler) context.slot = slot_point(to_numerology_value(scs), slot_dist(rgen)); // Prepare RG spy. - resource_grid_spy rg_spy; + resource_grid_reader_spy rg_reader_spy; + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + shared_resource_grid_spy unique_rg_spy(rg_spy); // Request RG. - request_handler.request_uplink_slot(context, rg_spy); + request_handler.request_uplink_slot(context, unique_rg_spy.get_grid()); // Assert context and RG. auto& puxch_entries = puxch_proc_spy.get_entries(); @@ -735,7 +746,9 @@ TEST_P(LowerPhyFixture, PuxchRequestHandler) ASSERT_EQ(puxch_entry.grid, &rg_spy); // No method of the grid should have been called. - ASSERT_EQ(rg_spy.get_total_count(), 0); + ASSERT_EQ(rg_reader_spy.get_count(), 0); + ASSERT_EQ(rg_writer_spy.get_count(), 0); + ASSERT_EQ(rg_spy.get_all_zero_count(), 0); } TEST_P(LowerPhyFixture, BasebandDownlinkFlow) diff --git a/tests/unittests/phy/lower/lower_phy_test_doubles.h b/tests/unittests/phy/lower/lower_phy_test_doubles.h index 952682391f..d462a5a868 100644 --- a/tests/unittests/phy/lower/lower_phy_test_doubles.h +++ b/tests/unittests/phy/lower/lower_phy_test_doubles.h @@ -126,7 +126,7 @@ class lower_phy_rx_symbol_notifier_spy : public lower_phy_rx_symbol_notifier } // See interface for documentation. - void on_rx_symbol(const lower_phy_rx_symbol_context& context, const resource_grid_reader& grid) override + void on_rx_symbol(const lower_phy_rx_symbol_context& context, const shared_resource_grid& grid) override { logger.debug(context.slot.sfn(), context.slot.slot_index(), @@ -136,7 +136,7 @@ class lower_phy_rx_symbol_notifier_spy : public lower_phy_rx_symbol_notifier rx_symbol_events.emplace_back(); rx_symbol_event& event = rx_symbol_events.back(); event.context = context; - event.grid = &grid; + event.grid = &grid.get_reader(); } // See interface for documentation. diff --git a/tests/unittests/phy/lower/processors/downlink/downlink_processor_test_doubles.h b/tests/unittests/phy/lower/processors/downlink/downlink_processor_test_doubles.h index 6de61befd5..774930a344 100644 --- a/tests/unittests/phy/lower/processors/downlink/downlink_processor_test_doubles.h +++ b/tests/unittests/phy/lower/processors/downlink/downlink_processor_test_doubles.h @@ -30,12 +30,12 @@ class pdxch_processor_request_handler_spy : public pdxch_processor_request_handl resource_grid_context context; }; - void handle_request(const resource_grid_reader& grid, const resource_grid_context& context) override + void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) override { entries.emplace_back(); entry_t& entry = entries.back(); entry.context = context; - entry.grid = &grid; + entry.grid = &grid.get_reader(); } const std::vector& get_entries() const { return entries; } diff --git a/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test.cpp b/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test.cpp index 3108612dbe..f39e795742 100644 --- a/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test.cpp +++ b/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test.cpp @@ -124,6 +124,8 @@ class LowerPhyDownlinkProcessorFixture : public ::testing::TestWithParam ofdm_mod_factory_spy; static std::shared_ptr pdxch_proc_factory; + resource_grid_reader_spy rg_reader_spy; + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy; + shared_resource_grid_spy shared_rg_spy; pdxch_processor_configuration config; std::unique_ptr pdxch_proc = nullptr; ofdm_symbol_modulator_spy* ofdm_mod_spy = nullptr; @@ -275,7 +281,7 @@ TEST_P(LowerPhyDownlinkProcessorFixture, FlowFloodRequest) pdxch_processor_notifier_spy pdxch_proc_notifier_spy; pdxch_proc->connect(pdxch_proc_notifier_spy); - resource_grid_reader_spy rg_spy; + shared_resource_grid shared_rg = shared_rg_spy.get_grid(); // Add a single resource grid entry per port. This makes the grid non-empty on all ports. for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { @@ -284,7 +290,7 @@ TEST_P(LowerPhyDownlinkProcessorFixture, FlowFloodRequest) entry.symbol = 0; entry.subcarrier = 0; entry.value = cf_t(0.0F, 0.0F); - rg_spy.write(entry); + rg_reader_spy.write(entry); } for (unsigned i_frame = 0, i_slot_frame = initial_slot_index; i_frame != nof_frames_test; ++i_frame) { @@ -295,7 +301,7 @@ TEST_P(LowerPhyDownlinkProcessorFixture, FlowFloodRequest) rg_context.sector = dist_sector_id(rgen); // Request resource grid modulation for the current slot. - pdxch_proc->get_request_handler().handle_request(rg_spy, rg_context); + pdxch_proc->get_request_handler().handle_request(shared_rg.copy(), rg_context); for (unsigned i_symbol = 0; i_symbol != nof_symbols_per_slot; ++i_symbol, ++i_symbol_subframe) { unsigned cp_size = cp.get_length(i_symbol_subframe, scs).to_samples(srate.to_Hz()); @@ -321,7 +327,7 @@ TEST_P(LowerPhyDownlinkProcessorFixture, FlowFloodRequest) for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { const auto& ofdm_mod_entry = ofdm_mod_entries[i_port]; ASSERT_EQ(span(ofdm_mod_entry.output), buffer[i_port]); - ASSERT_EQ(static_cast(ofdm_mod_entry.grid), static_cast(&rg_spy)); + ASSERT_EQ(static_cast(ofdm_mod_entry.grid), static_cast(&rg_reader_spy)); ASSERT_EQ(ofdm_mod_entry.port_index, i_port); ASSERT_EQ(ofdm_mod_entry.symbol_index, i_symbol_subframe); } @@ -358,9 +364,7 @@ TEST_P(LowerPhyDownlinkProcessorFixture, LateRequest) unsigned late_slot = 2; unsigned next_slot = 4; - resource_grid_reader_spy initial_rg_spy(nof_tx_ports, 1, 1); - resource_grid_reader_spy late_rg_spy(nof_tx_ports, 1, 1); - resource_grid_reader_spy next_rg_spy(nof_tx_ports, 1, 1); + shared_resource_grid shared_rg = shared_rg_spy.get_grid(); // Add a single resource grid entry per port. This makes the grid non-empty on all ports. for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { @@ -369,28 +373,26 @@ TEST_P(LowerPhyDownlinkProcessorFixture, LateRequest) entry.symbol = 0; entry.subcarrier = 0; entry.value = cf_t(0.0F, 0.0F); - initial_rg_spy.write(entry); - late_rg_spy.write(entry); - next_rg_spy.write(entry); + rg_reader_spy.write(entry); } // Initial request. resource_grid_context initial_rg_context; initial_rg_context.slot = slot_point(to_numerology_value(scs), initial_slot); initial_rg_context.sector = sector_id; - pdxch_proc->get_request_handler().handle_request(initial_rg_spy, initial_rg_context); + pdxch_proc->get_request_handler().handle_request(shared_rg.copy(), initial_rg_context); // Late request. resource_grid_context late_rg_context; late_rg_context.slot = slot_point(to_numerology_value(scs), late_slot); late_rg_context.sector = sector_id; - pdxch_proc->get_request_handler().handle_request(late_rg_spy, late_rg_context); + pdxch_proc->get_request_handler().handle_request(shared_rg.copy(), late_rg_context); // Next request. resource_grid_context next_rg_context; next_rg_context.slot = slot_point(to_numerology_value(scs), next_slot); next_rg_context.sector = sector_id; - pdxch_proc->get_request_handler().handle_request(next_rg_spy, next_rg_context); + pdxch_proc->get_request_handler().handle_request(shared_rg.copy(), next_rg_context); for (unsigned i_subframe = 0; i_subframe != NOF_SUBFRAMES_PER_FRAME; ++i_subframe) { for (unsigned i_slot = 0, i_symbol_subframe = 0; i_slot != nof_slots_per_subframe; ++i_slot) { @@ -421,15 +423,15 @@ TEST_P(LowerPhyDownlinkProcessorFixture, LateRequest) pdxch_proc->get_baseband().process_symbol(buffer.get_writer(), pdxch_context); // Assert OFDM modulator call only for initial and next slot. - const auto& ofdm_mod_entries = ofdm_mod_spy->get_modulate_entries(); - resource_grid_reader_spy* rg_spy = (i_slot == initial_slot) ? &initial_rg_spy : &next_rg_spy; + const auto& ofdm_mod_entries = ofdm_mod_spy->get_modulate_entries(); + resource_grid_reader_spy* rg_reader_spy_ptr = &rg_reader_spy; if (i_slot == initial_slot || i_slot == next_slot) { ASSERT_EQ(ofdm_mod_entries.size(), nof_tx_ports); for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { const auto& ofdm_mod_entry = ofdm_mod_entries[i_port]; ASSERT_EQ(span(ofdm_mod_entry.output), buffer[i_port]); - ASSERT_EQ(static_cast(ofdm_mod_entry.grid), static_cast(rg_spy)); + ASSERT_EQ(static_cast(ofdm_mod_entry.grid), static_cast(rg_reader_spy_ptr)); ASSERT_EQ(ofdm_mod_entry.port_index, i_port); ASSERT_EQ(ofdm_mod_entry.symbol_index, i_symbol_subframe); } @@ -470,8 +472,6 @@ TEST_P(LowerPhyDownlinkProcessorFixture, OverflowRequest) pdxch_processor_notifier_spy pdxch_proc_notifier_spy; pdxch_proc->connect(pdxch_proc_notifier_spy); - resource_grid_reader_spy rg_spy(nof_tx_ports, 1, 1); - // Add a single resource grid entry per port. This makes the grid non-empty on all ports. for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { resource_grid_reader_spy::expected_entry_t entry; @@ -479,15 +479,17 @@ TEST_P(LowerPhyDownlinkProcessorFixture, OverflowRequest) entry.symbol = 0; entry.subcarrier = 0; entry.value = cf_t(0.0F, 0.0F); - rg_spy.write(entry); + rg_reader_spy.write(entry); } + shared_resource_grid shared_rg = shared_rg_spy.get_grid(); + // Generate requests. for (unsigned i_request = 0; i_request != request_queue_size + 1; ++i_request) { resource_grid_context rg_context; rg_context.slot = slot_point(to_numerology_value(scs), initial_slot_index + i_request); rg_context.sector = dist_sector_id(rgen); - pdxch_proc->get_request_handler().handle_request(rg_spy, rg_context); + pdxch_proc->get_request_handler().handle_request(shared_rg.copy(), rg_context); ASSERT_EQ(pdxch_proc_notifier_spy.get_request_late().size(), 0); unsigned nof_expected_overflows = (i_request > request_queue_size) ? (i_request - request_queue_size) : 0; @@ -530,7 +532,7 @@ TEST_P(LowerPhyDownlinkProcessorFixture, OverflowRequest) for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { const auto& ofdm_mod_entry = ofdm_mod_entries[i_port]; ASSERT_EQ(span(ofdm_mod_entry.output), buffer[i_port]); - ASSERT_EQ(static_cast(ofdm_mod_entry.grid), static_cast(&rg_spy)); + ASSERT_EQ(static_cast(ofdm_mod_entry.grid), static_cast(&rg_reader_spy)); ASSERT_EQ(ofdm_mod_entry.port_index, i_port); ASSERT_EQ(ofdm_mod_entry.symbol_index, i_symbol_subframe); } diff --git a/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test_doubles.h b/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test_doubles.h index 48424cce3f..faddc22aa0 100644 --- a/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test_doubles.h +++ b/tests/unittests/phy/lower/processors/downlink/pdxch/pdxch_processor_test_doubles.h @@ -17,6 +17,7 @@ #include "srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_notifier.h" #include "srsran/phy/lower/processors/downlink/pdxch/pdxch_processor_request_handler.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/srslog/srslog.h" #include #include @@ -106,7 +107,7 @@ class pdxch_processor_baseband_spy : public pdxch_processor_baseband class pdxch_processor_request_handler_spy : public pdxch_processor_request_handler { public: - void handle_request(const resource_grid_reader& grid, const resource_grid_context& context) override + void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) override { // TBD. } diff --git a/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_notifier_test_doubles.h b/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_notifier_test_doubles.h index 9a3c00918a..644bcd880d 100644 --- a/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_notifier_test_doubles.h +++ b/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_notifier_test_doubles.h @@ -13,6 +13,7 @@ #include "srsran/phy/lower/lower_phy_rx_symbol_context.h" #include "srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" namespace srsran { @@ -26,10 +27,10 @@ class puxch_processor_notifier_spy : public puxch_processor_notifier void on_puxch_request_late(const resource_grid_context& context) override { request_late.emplace_back(context); } - void on_rx_symbol(const resource_grid_reader& grid, const lower_phy_rx_symbol_context& context) override + void on_rx_symbol(const shared_resource_grid& grid, const lower_phy_rx_symbol_context& context) override { - rx_symbol_entry entry = {&grid, context}; - rx_symbol.emplace_back(std::move(entry)); + rx_symbol_entry entry = rx_symbol_entry{&grid.get_reader(), context}; + rx_symbol.emplace_back(entry); } const std::vector& get_request_late() const { return request_late; } diff --git a/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test.cpp b/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test.cpp index 99dbd507f8..27c30881eb 100644 --- a/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test.cpp +++ b/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test.cpp @@ -126,6 +126,8 @@ class LowerPhyUplinkProcessorFixture : public ::testing::TestWithParam puxch_proc_factory; puxch_processor_configuration config; - std::unique_ptr puxch_proc = nullptr; ofdm_symbol_demodulator_spy* ofdm_demod_spy = nullptr; + resource_grid_reader_spy rg_reader_spy; + resource_grid_writer_spy rg_writer_spy; + resource_grid_spy rg_spy; + shared_resource_grid_spy shared_rg_spy; + std::unique_ptr puxch_proc = nullptr; }; std::mt19937 LowerPhyUplinkProcessorFixture::rgen(0); @@ -293,8 +299,7 @@ TEST_P(LowerPhyUplinkProcessorFixture, FlowFloodRequest) rg_context.sector = dist_sector_id(rgen); // Request resource grid demodulation for the current slot. - resource_grid_spy rg_spy; - puxch_proc->get_request_handler().handle_request(rg_spy, rg_context); + puxch_proc->get_request_handler().handle_request(shared_rg_spy.get_grid(), rg_context); for (unsigned i_symbol = 0; i_symbol != nof_symbols_per_slot; ++i_symbol, ++i_symbol_subframe) { unsigned cp_size = cp.get_length(i_symbol_subframe, scs).to_samples(srate.to_Hz()); @@ -327,7 +332,7 @@ TEST_P(LowerPhyUplinkProcessorFixture, FlowFloodRequest) for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { const auto& ofdm_demod_entry = ofdm_demod_entries[i_port]; ASSERT_EQ(span(ofdm_demod_entry.input), buffer[i_port]); - ASSERT_EQ(static_cast(ofdm_demod_entry.grid), static_cast(&rg_spy.get_writer())); + ASSERT_EQ(static_cast(ofdm_demod_entry.grid), static_cast(&rg_writer_spy)); ASSERT_EQ(ofdm_demod_entry.port_index, i_port); ASSERT_EQ(ofdm_demod_entry.symbol_index, i_symbol_subframe); } @@ -364,27 +369,25 @@ TEST_P(LowerPhyUplinkProcessorFixture, LateRequest) unsigned late_slot = 2; unsigned next_slot = 4; - resource_grid_spy initial_rg_spy(0, 0, 0); - resource_grid_spy late_rg_spy(0, 0, 0); - resource_grid_spy next_rg_spy(0, 0, 0); + shared_resource_grid shared_rg = shared_rg_spy.get_grid(); // Initial request. resource_grid_context initial_rg_context; initial_rg_context.slot = slot_point(to_numerology_value(scs), initial_slot); initial_rg_context.sector = sector_id; - puxch_proc->get_request_handler().handle_request(initial_rg_spy, initial_rg_context); + puxch_proc->get_request_handler().handle_request(shared_rg.copy(), initial_rg_context); // Late request. resource_grid_context late_rg_context; late_rg_context.slot = slot_point(to_numerology_value(scs), late_slot); late_rg_context.sector = sector_id; - puxch_proc->get_request_handler().handle_request(late_rg_spy, late_rg_context); + puxch_proc->get_request_handler().handle_request(shared_rg.copy(), late_rg_context); // Next request. resource_grid_context next_rg_context; next_rg_context.slot = slot_point(to_numerology_value(scs), next_slot); next_rg_context.sector = sector_id; - puxch_proc->get_request_handler().handle_request(next_rg_spy, next_rg_context); + puxch_proc->get_request_handler().handle_request(shared_rg.copy(), next_rg_context); for (unsigned i_subframe = 0; i_subframe != NOF_SUBFRAMES_PER_FRAME; ++i_subframe) { for (unsigned i_slot = 0, i_symbol_subframe = 0; i_slot != nof_slots_per_subframe; ++i_slot) { @@ -417,12 +420,12 @@ TEST_P(LowerPhyUplinkProcessorFixture, LateRequest) // Assert OFDM demodulator call only for initial and next slot. const auto& ofdm_demod_entries = ofdm_demod_spy->get_demodulate_entries(); if ((i_slot == initial_slot) || (i_slot == next_slot)) { - resource_grid_spy* rg_spy = (i_slot == initial_slot) ? &initial_rg_spy : &next_rg_spy; + resource_grid_spy* rg_spy_ptr = &rg_spy; ASSERT_EQ(ofdm_demod_entries.size(), nof_rx_ports); for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { const auto& ofdm_demod_entry = ofdm_demod_entries[i_port]; ASSERT_EQ(span(ofdm_demod_entry.input), buffer[i_port]); - ASSERT_EQ(static_cast(ofdm_demod_entry.grid), static_cast(rg_spy)); + ASSERT_EQ(static_cast(ofdm_demod_entry.grid), static_cast(rg_spy_ptr)); ASSERT_EQ(ofdm_demod_entry.port_index, i_port); ASSERT_EQ(ofdm_demod_entry.symbol_index, i_symbol_subframe); } @@ -463,7 +466,7 @@ TEST_P(LowerPhyUplinkProcessorFixture, OverflowRequest) puxch_processor_notifier_spy puxch_proc_notifier_spy; puxch_proc->connect(puxch_proc_notifier_spy); - resource_grid_spy rg_spy; + shared_resource_grid shared_rg = shared_rg_spy.get_grid(); // Generate requests. slot_point slot(to_numerology_value(scs), 0); @@ -471,7 +474,7 @@ TEST_P(LowerPhyUplinkProcessorFixture, OverflowRequest) resource_grid_context rg_context; rg_context.slot = slot + i_request; rg_context.sector = sector_id; - puxch_proc->get_request_handler().handle_request(rg_spy, rg_context); + puxch_proc->get_request_handler().handle_request(shared_rg.copy(), rg_context); unsigned nof_expected_late = (i_request >= request_queue_size) ? (i_request - request_queue_size + 1) : 0; ASSERT_EQ(puxch_proc_notifier_spy.get_rx_symbol().size(), 0); diff --git a/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test_doubles.h b/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test_doubles.h index 5ca72150e8..7959ee3cd4 100644 --- a/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test_doubles.h +++ b/tests/unittests/phy/lower/processors/uplink/puxch/puxch_processor_test_doubles.h @@ -17,6 +17,7 @@ #include "srsran/phy/lower/processors/uplink/puxch/puxch_processor_notifier.h" #include "srsran/phy/lower/processors/uplink/puxch/puxch_processor_request_handler.h" #include "srsran/phy/support/resource_grid_context.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/srslog/srslog.h" #include @@ -52,15 +53,15 @@ class puxch_processor_request_handler_spy : public puxch_processor_request_handl { public: struct entry_t { - resource_grid* grid; + const resource_grid* grid; resource_grid_context context; }; - void handle_request(resource_grid& grid, const resource_grid_context& context) override + void handle_request(const shared_resource_grid& grid, const resource_grid_context& context) override { entries.emplace_back(); entry_t& entry = entries.back(); - entry.grid = &grid; + entry.grid = &grid.get(); entry.context = context; } diff --git a/tests/unittests/phy/support/resource_grid_pool_test.cpp b/tests/unittests/phy/support/resource_grid_pool_test.cpp index ba0ae259a1..d58b95a937 100644 --- a/tests/unittests/phy/support/resource_grid_pool_test.cpp +++ b/tests/unittests/phy/support/resource_grid_pool_test.cpp @@ -9,55 +9,52 @@ */ #include "resource_grid_test_doubles.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/support/support_factories.h" #include "srsran/support/srsran_test.h" #include using namespace srsran; -void test(unsigned nof_slots, unsigned nof_sectors) +void test(unsigned nof_slots) { - // Create grids + // Create grids. std::vector> grid_pool; - std::vector> grids; + std::vector expected_grids; // Generate resource grids - grids.reserve(nof_slots * nof_sectors); - grids.resize(nof_slots); for (unsigned slot = 0; slot != nof_slots; ++slot) { - grids[slot].resize(nof_sectors); - for (unsigned sector = 0; sector != nof_sectors; ++sector) { - grids[slot][sector] = new resource_grid_dummy; - grid_pool.emplace_back(grids[slot][sector]); - } + grid_pool.emplace_back(std::make_unique()); + expected_grids.emplace_back(grid_pool.back().get()); } // Create resource grid pool std::unique_ptr pool = create_generic_resource_grid_pool(std::move(grid_pool)); // Iterate all parameters and assert grid reference - for (unsigned slot_count = 0; slot_count != nof_slots; ++slot_count) { - for (unsigned sector = 0; sector != nof_sectors; ++sector) { - // Create context - resource_grid_context context = {}; - context.slot = {0, slot_count}; - context.sector = sector; + std::vector reserved_grids; + for (unsigned slot = 0; slot != nof_slots; ++slot) { + // Create context + resource_grid_context context = {}; + context.slot = {0, slot}; + context.sector = 0; + + // Get grid. + shared_resource_grid grid = pool->allocate_resource_grid(context); + TESTASSERT(grid.is_valid()); - // Get grid - const resource_grid& grid = pool->get_resource_grid(context); + // Verify grid reference match + TESTASSERT_EQ(reinterpret_cast(&grid.get()), reinterpret_cast(expected_grids[slot])); - // Verify grid reference match - TESTASSERT_EQ((void*)&grid, (void*)grids[slot_count][sector]); - } + // Move grid to the reserved list to avoid being released. + reserved_grids.emplace_back(std::move(grid)); } } int main() { for (unsigned nof_slots : {40}) { - for (unsigned nof_sectors : {1, 2, 3}) { - test(nof_slots, nof_sectors); - } + test(nof_slots); } return 0; diff --git a/tests/unittests/phy/support/resource_grid_test_doubles.h b/tests/unittests/phy/support/resource_grid_test_doubles.h index e5f2c886f1..3d754fc848 100644 --- a/tests/unittests/phy/support/resource_grid_test_doubles.h +++ b/tests/unittests/phy/support/resource_grid_test_doubles.h @@ -16,6 +16,7 @@ #include "srsran/phy/support/resource_grid_mapper.h" #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/support/resource_grid_writer.h" +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/ran/cyclic_prefix.h" #include "srsran/srslog/srslog.h" #include "srsran/srsvec/copy.h" @@ -50,7 +51,7 @@ class resource_grid_writer_spy : public resource_grid_writer }; /// Constructs a resource spy. - resource_grid_writer_spy(unsigned max_ports_, unsigned max_symb_, unsigned max_prb_) : + resource_grid_writer_spy(unsigned max_ports_ = 0, unsigned max_symb_ = 0, unsigned max_prb_ = 0) : max_ports(max_ports_), max_symb(max_symb_), max_prb(max_prb_), data({max_prb * NRE, max_symb, max_ports}) { } @@ -198,6 +199,8 @@ class resource_grid_writer_spy : public resource_grid_writer /// Get the number of times a \c put method has been called. unsigned get_count() const { return count; } + bool has_grid_been_written() const { return count != 0; } + /// Clears any possible state. void reset() { @@ -392,20 +395,12 @@ class resource_grid_reader_spy : public resource_grid_reader class resource_grid_spy : public resource_grid, private resource_grid_mapper { public: - resource_grid_spy(unsigned max_ports = 0, unsigned max_symb = 0, unsigned max_prb = 0) : - reader(max_ports, max_symb, max_prb), writer(max_ports, max_symb, max_prb) + resource_grid_spy(resource_grid_reader& reader_, resource_grid_writer& writer_) : reader(reader_), writer(writer_) { // Do nothing. } - void set_all_zero() override - { - ++set_all_zero_count; - - // Reset the reader and writer. - reader.reset(); - writer.reset(); - } + void set_all_zero() override { ++set_all_zero_count; } void set_empty(bool empty_) { empty = empty_; } @@ -417,15 +412,10 @@ class resource_grid_spy : public resource_grid, private resource_grid_mapper bool has_set_all_zero_method_been_called() const { return set_all_zero_count > 0; } /// Returns the global number of calls to any method. - unsigned get_total_count() const { return set_all_zero_count + reader.get_count() + writer.get_count(); } + unsigned get_all_zero_count() const { return set_all_zero_count; } /// Resets all counters. - void clear() - { - set_all_zero_count = 0; - reader.reset(); - writer.reset(); - } + void clear() { set_all_zero_count = 0; } resource_grid_mapper& get_mapper() override { return *this; } @@ -446,10 +436,47 @@ class resource_grid_spy : public resource_grid, private resource_grid_mapper } private: - resource_grid_reader_spy reader; - resource_grid_writer_spy writer; - bool empty = true; - unsigned set_all_zero_count = 0; + resource_grid_reader& reader; + resource_grid_writer& writer; + bool empty = true; + unsigned set_all_zero_count = 0; +}; + +class shared_resource_grid_spy : private shared_resource_grid::pool_interface +{ +private: + static constexpr unsigned identifier = 0; + resource_grid& grid; + std::atomic ref_count = {}; + + resource_grid& get(unsigned identifier_) override + { + srsran_assert(ref_count > 0, "The grid must be reserved."); + srsran_assert(identifier == identifier_, "Identifier miss-match."); + return grid; + } + + void notify_release_scope(unsigned identifier_) override + { + srsran_assert(ref_count == 0, "The grid must be reserved."); + srsran_assert(identifier == identifier_, "Identifier miss-match."); + } + +public: + explicit shared_resource_grid_spy(resource_grid& grid_) : grid(grid_) {} + + ~shared_resource_grid_spy() + { + report_fatal_error_if_not(ref_count == 0, "A grid is still active in {} scopes.", ref_count); + } + + shared_resource_grid get_grid() + { + unsigned expected_available_ref_count = 0; + bool available = ref_count.compare_exchange_strong(expected_available_ref_count, 1); + srsran_assert(available, "The grid must NOT be reserved."); + return {*this, ref_count, 0}; + } }; /// \brief Describes a resource grid dummy used for testing classes that handle resource grids but do not use the diff --git a/tests/unittests/phy/upper/downlink_processor_test.cpp b/tests/unittests/phy/upper/downlink_processor_test.cpp index 1e7e580ce5..1d33c3151a 100644 --- a/tests/unittests/phy/upper/downlink_processor_test.cpp +++ b/tests/unittests/phy/upper/downlink_processor_test.cpp @@ -24,6 +24,15 @@ using namespace srsran; static srslog::basic_logger& logger = srslog::fetch_basic_logger("PHY"); +static shared_resource_grid get_dummy_grid() +{ + static resource_grid_reader_spy rg_reader_spy; + static resource_grid_writer_spy rg_writer_spy; + static resource_grid_spy rg_spy(rg_reader_spy, rg_writer_spy); + static shared_resource_grid_spy unique_rg_spy(rg_spy); + return unique_rg_spy.get_grid(); +} + TEST(downlinkProcessorTest, worksInOrder) { upper_phy_rg_gateway_fto gw; @@ -49,8 +58,7 @@ TEST(downlinkProcessorTest, worksInOrder) slot_point slot(1, 2, 1); unsigned sector = 0; - resource_grid_dummy grid; - dl_processor->configure_resource_grid({slot, sector}, grid); + dl_processor->configure_resource_grid({slot, sector}, get_dummy_grid()); ASSERT_FALSE(pdcch_ref.is_process_called()); ASSERT_FALSE(pdsch_ref.is_process_called()); @@ -106,8 +114,7 @@ TEST(downlinkProcessorTest, finishIsCalledBeforeProcessingPdus) slot_point slot(1, 2, 1); unsigned sector = 0; - resource_grid_dummy grid; - dl_processor->configure_resource_grid({slot, sector}, grid); + dl_processor->configure_resource_grid({slot, sector}, get_dummy_grid()); dl_processor->process_ssb({}); pdcch_processor::pdu_t pdu; @@ -164,7 +171,7 @@ TEST(downlinkProcessorTest, processPduAfterFinishProcessingPdusDoesNothing) unsigned sector = 0; resource_grid_dummy grid; - dl_processor->configure_resource_grid({slot, sector}, grid); + dl_processor->configure_resource_grid({slot, sector}, get_dummy_grid()); dl_processor->process_ssb({}); pdcch_processor::pdu_t pdu; @@ -266,7 +273,7 @@ TEST(downlinkProcessorTest, twoConsecutiveSlots) unsigned sector = 0; resource_grid_dummy grid; - dl_processor->configure_resource_grid({slot, sector}, grid); + dl_processor->configure_resource_grid({slot, sector}, get_dummy_grid()); dl_processor->process_ssb({}); pdcch_processor::pdu_t pdu; @@ -283,8 +290,7 @@ TEST(downlinkProcessorTest, twoConsecutiveSlots) slot_point slot2(1, 2, 2); gw.clear_sent(); - resource_grid_dummy grid2; - dl_processor->configure_resource_grid({slot2, sector}, grid2); + dl_processor->configure_resource_grid({slot2, sector}, get_dummy_grid()); dl_processor->process_ssb({}); dl_processor->process_pdcch(pdu); @@ -313,8 +319,7 @@ TEST(downlinkProcessorTest, finishWithoutProcessingPdusSendsTheGrid) slot_point slot(1, 2, 1); unsigned sector = 0; - resource_grid_spy grid(0, 0, 0); - dl_processor->configure_resource_grid({slot, sector}, grid); + dl_processor->configure_resource_grid({slot, sector}, get_dummy_grid()); // By finishing PDUs, the resource grid should be sent. dl_processor->finish_processing_pdus(); diff --git a/tests/unittests/phy/upper/downlink_processor_test_doubles.h b/tests/unittests/phy/upper/downlink_processor_test_doubles.h index 0f1683ec74..48af3454d0 100644 --- a/tests/unittests/phy/upper/downlink_processor_test_doubles.h +++ b/tests/unittests/phy/upper/downlink_processor_test_doubles.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/downlink_processor.h" namespace srsran { @@ -44,7 +45,7 @@ class downlink_processor_spy : public downlink_processor void process_nzp_csi_rs(const nzp_csi_rs_generator::config_t& config) override {} - bool configure_resource_grid(const resource_grid_context& context, resource_grid& grid) override + bool configure_resource_grid(const resource_grid_context& context, shared_resource_grid grid) override { configure_resource_grid_method_called = true; return true; diff --git a/tests/unittests/phy/upper/uplink_processor_test_doubles.h b/tests/unittests/phy/upper/uplink_processor_test_doubles.h index a722f2bad7..e8c65205f0 100644 --- a/tests/unittests/phy/upper/uplink_processor_test_doubles.h +++ b/tests/unittests/phy/upper/uplink_processor_test_doubles.h @@ -32,21 +32,21 @@ class uplink_processor_spy : public uplink_processor void process_pusch(span data, unique_rx_buffer rm_buffer, upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const uplink_processor::pusch_pdu& pdu) override { has_process_pusch_method_called = true; } void process_pucch(upper_phy_rx_results_notifier& notifier, - const resource_grid_reader& grid, + const shared_resource_grid& grid, const pucch_pdu& config) override { has_process_pucch_method_called = true; } void - process_srs(upper_phy_rx_results_notifier& notifier, const resource_grid_reader& grid, const srs_pdu& pdu) override + process_srs(upper_phy_rx_results_notifier& notifier, const shared_resource_grid& grid, const srs_pdu& pdu) override { has_process_srs_method_called = true; } diff --git a/tests/unittests/phy/upper/uplink_request_processor_test_doubles.h b/tests/unittests/phy/upper/uplink_request_processor_test_doubles.h index 6f382ac507..32a501c129 100644 --- a/tests/unittests/phy/upper/uplink_request_processor_test_doubles.h +++ b/tests/unittests/phy/upper/uplink_request_processor_test_doubles.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/uplink_request_processor.h" namespace srsran { @@ -19,7 +20,7 @@ class uplink_request_processor_dummy : public uplink_request_processor { public: void process_prach_request(const prach_buffer_context& context) override {} - void process_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) override {} + void process_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) override {} }; } // namespace srsran diff --git a/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h b/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h index aa49041843..796eb0badf 100644 --- a/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h +++ b/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/upper_phy_rg_gateway.h" namespace srsran { @@ -20,7 +21,7 @@ class upper_phy_rg_gateway_fto : public upper_phy_rg_gateway { public: bool sent = false; - void send(const resource_grid_context& context, const resource_grid_reader& grid) override { sent = true; } + void send(const resource_grid_context& context, const shared_resource_grid& grid) override { sent = true; } void clear_sent() { sent = false; } }; diff --git a/tests/unittests/phy/upper/upper_phy_rx_symbol_handler_test.cpp b/tests/unittests/phy/upper/upper_phy_rx_symbol_handler_test.cpp index 9245f3c619..885ed5c58c 100644 --- a/tests/unittests/phy/upper/upper_phy_rx_symbol_handler_test.cpp +++ b/tests/unittests/phy/upper/upper_phy_rx_symbol_handler_test.cpp @@ -32,6 +32,7 @@ class UpperPhyRxSymbolHandlerFixture : public ::testing::Test upper_phy_rx_symbol_handler_impl rx_handler; prach_buffer_spy buffer_dummy; resource_grid_dummy rg; + shared_resource_grid_spy shared_rg; void handle_prach_symbol() { @@ -59,7 +60,7 @@ class UpperPhyRxSymbolHandlerFixture : public ::testing::Test upper_phy_rx_symbol_context ctx = {}; ctx.symbol = i; ctx.slot = slot_point(0, 0, 0); - rx_handler.handle_rx_symbol(ctx, rg.get_reader()); + rx_handler.handle_rx_symbol(ctx, shared_rg.get_grid()); } } @@ -80,7 +81,7 @@ class UpperPhyRxSymbolHandlerFixture : public ::testing::Test upper_phy_rx_symbol_context ctx = {}; ctx.symbol = i; ctx.slot = slot_point(0, 0, 1); - rx_handler.handle_rx_symbol(ctx, rg.get_reader()); + rx_handler.handle_rx_symbol(ctx, shared_rg.get_grid()); } } @@ -100,7 +101,7 @@ class UpperPhyRxSymbolHandlerFixture : public ::testing::Test upper_phy_rx_symbol_context ctx = {}; ctx.symbol = i; ctx.slot = slot_point(0, 0, 0); - rx_handler.handle_rx_symbol(ctx, rg.get_reader()); + rx_handler.handle_rx_symbol(ctx, shared_rg.get_grid()); } } @@ -108,7 +109,8 @@ class UpperPhyRxSymbolHandlerFixture : public ::testing::Test rm_buffer_pool(create_rx_buffer_pool(rx_buffer_pool_config{16, 2, 2, 16})), ul_processor_pool(create_ul_processor_pool()), pdu_repo(2), - rx_handler(*ul_processor_pool, pdu_repo, rm_buffer_pool->get_pool(), rx_results_wrapper) + rx_handler(*ul_processor_pool, pdu_repo, rm_buffer_pool->get_pool(), rx_results_wrapper), + shared_rg(rg) { srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::warning); srslog::init(); diff --git a/tests/unittests/phy/upper/upper_phy_rx_symbol_request_notifier_test_doubles.h b/tests/unittests/phy/upper/upper_phy_rx_symbol_request_notifier_test_doubles.h index 8c4c796fc9..eb44dcc012 100644 --- a/tests/unittests/phy/upper/upper_phy_rx_symbol_request_notifier_test_doubles.h +++ b/tests/unittests/phy/upper/upper_phy_rx_symbol_request_notifier_test_doubles.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/phy/support/shared_resource_grid.h" #include "srsran/phy/upper/upper_phy_rx_symbol_request_notifier.h" namespace srsran { @@ -23,7 +24,7 @@ class upper_phy_rx_symbol_request_notifier_spy : public upper_phy_rx_symbol_requ { prach_capture_request_notified = true; } - void on_uplink_slot_request(const resource_grid_context& context, resource_grid& grid) override {} + void on_uplink_slot_request(const resource_grid_context& context, const shared_resource_grid& grid) override {} bool has_prach_result_been_notified() const { return prach_capture_request_notified; } }; From df936b8a68d2a5c9ce50ccf023e164bfb9284d04 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 19 Aug 2024 09:30:07 +0200 Subject: [PATCH 307/407] phy: removed unnecessary std:move of grids --- apps/examples/phy/upper_phy_ssb_example.cpp | 2 +- include/srsran/phy/adapters/phy_rg_gateway_adapter.h | 2 +- include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h | 2 +- include/srsran/phy/upper/upper_phy_rg_gateway.h | 4 ++-- include/srsran/ru/ru_adapters.h | 2 +- lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp | 2 +- .../transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp | 2 +- lib/phy/upper/downlink_processor_single_executor_impl.cpp | 3 +-- tests/integrationtests/ofh/ofh_integration_test.cpp | 4 ++-- tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h | 2 +- 10 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/examples/phy/upper_phy_ssb_example.cpp b/apps/examples/phy/upper_phy_ssb_example.cpp index 8f234b6848..ad8f5e4b46 100644 --- a/apps/examples/phy/upper_phy_ssb_example.cpp +++ b/apps/examples/phy/upper_phy_ssb_example.cpp @@ -122,7 +122,7 @@ class upper_phy_example_sw : public upper_phy_ssb_example rx_symb_context.slot = context.slot; shared_resource_grid rg = ul_rg_pool->allocate_resource_grid(rx_symb_context); srsran_assert(rg, "Failed to fetch a resource grid."); - rx_symb_req_notifier->on_uplink_slot_request(rx_symb_context, std::move(rg)); + rx_symb_req_notifier->on_uplink_slot_request(rx_symb_context, rg); } // Request PRACH capture if PRACH processing is enabled. diff --git a/include/srsran/phy/adapters/phy_rg_gateway_adapter.h b/include/srsran/phy/adapters/phy_rg_gateway_adapter.h index 99238412fb..640d1a6f16 100644 --- a/include/srsran/phy/adapters/phy_rg_gateway_adapter.h +++ b/include/srsran/phy/adapters/phy_rg_gateway_adapter.h @@ -27,7 +27,7 @@ class phy_rg_gateway_adapter : public upper_phy_rg_gateway void connect(lower_phy_rg_handler* handler) { rg_handler = handler; } // See interface for documentation. - void send(const resource_grid_context& context, const shared_resource_grid& grid) override + void send(const resource_grid_context& context, shared_resource_grid grid) override { report_fatal_error_if_not(rg_handler, "Adapter is not connected."); rg_handler->handle_resource_grid(context, grid); diff --git a/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h b/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h index 0c4bffb456..5969a401df 100644 --- a/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h +++ b/include/srsran/phy/adapters/phy_rx_symbol_request_adapter.h @@ -37,7 +37,7 @@ class phy_rx_symbol_request_adapter : public upper_phy_rx_symbol_request_notifie { report_fatal_error_if_not(rx_symbol_request_handler, "Adapter is not connected."); - rx_symbol_request_handler->request_uplink_slot(context, std::move(grid)); + rx_symbol_request_handler->request_uplink_slot(context, grid); } }; diff --git a/include/srsran/phy/upper/upper_phy_rg_gateway.h b/include/srsran/phy/upper/upper_phy_rg_gateway.h index ebf30c9779..cb9d3292b5 100644 --- a/include/srsran/phy/upper/upper_phy_rg_gateway.h +++ b/include/srsran/phy/upper/upper_phy_rg_gateway.h @@ -26,8 +26,8 @@ class upper_phy_rg_gateway /// \brief Sends the given resource grid through the gateway. /// /// \param[in] context Context the resource grid belongs to. - /// \param[in] grid Resource grid reader instance. - virtual void send(const resource_grid_context& context, const shared_resource_grid& grid) = 0; + /// \param[in] grid Resource grid. + virtual void send(const resource_grid_context& context, shared_resource_grid grid) = 0; }; } // namespace srsran diff --git a/include/srsran/ru/ru_adapters.h b/include/srsran/ru/ru_adapters.h index cb75d4b8f0..a65615b776 100644 --- a/include/srsran/ru/ru_adapters.h +++ b/include/srsran/ru/ru_adapters.h @@ -29,7 +29,7 @@ class upper_ru_dl_rg_adapter : public upper_phy_rg_gateway { public: // See interface for documentation. - void send(const resource_grid_context& context, const shared_resource_grid& grid) override + void send(const resource_grid_context& context, shared_resource_grid grid) override { srsran_assert(dl_handler, "Adapter is not connected."); dl_handler->handle_dl_data(context, grid); diff --git a/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp b/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp index 0731cb5b65..d279f65a5b 100644 --- a/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp +++ b/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp @@ -534,7 +534,7 @@ void fapi_to_phy_translator::ul_tti_request(const fapi::ul_tti_request_message& } // Request to capture uplink slot. - ul_request_processor.process_uplink_slot_request(rg_context, std::move(ul_rg)); + ul_request_processor.process_uplink_slot_request(rg_context, ul_rg); l1_tracer << trace_event("ul_tti_request", tp); } diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp index 3f371d4675..34d7ec6e48 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp @@ -86,7 +86,7 @@ void data_flow_uplane_downlink_data_impl::enqueue_section_type_1_message( const shared_resource_grid& grid) { trace_point tp = ofh_tracer.now(); - enqueue_section_type_1_message_symbol_burst(context, std::move(grid)); + enqueue_section_type_1_message_symbol_burst(context, grid); ofh_tracer << trace_event(formatted_trace_names[context.eaxc].c_str(), tp); } diff --git a/lib/phy/upper/downlink_processor_single_executor_impl.cpp b/lib/phy/upper/downlink_processor_single_executor_impl.cpp index a47c225ddd..823d80ba41 100644 --- a/lib/phy/upper/downlink_processor_single_executor_impl.cpp +++ b/lib/phy/upper/downlink_processor_single_executor_impl.cpp @@ -256,8 +256,7 @@ void downlink_processor_single_executor_impl::send_resource_grid() // Send the resource grid if available. if (current_grid.is_valid()) { - shared_resource_grid grid2 = std::move(current_grid); - gateway.send(rg_context, std::move(grid2)); + gateway.send(rg_context, std::move(current_grid)); } // Update internal state. diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index abbfde4563..d47163f594 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -727,7 +727,7 @@ class test_du_emulator shared_resource_grid dl_grid = dl_rg_pool->allocate_resource_grid(context); srsran_assert(dl_grid, "Failed to get grid."); - dl_handler.handle_dl_data(context, std::move(dl_grid)); + dl_handler.handle_dl_data(context, dl_grid); logger.info("DU emulator pushed DL data in slot {}", slot); } @@ -739,7 +739,7 @@ class test_du_emulator shared_resource_grid ul_grid = ul_rg_pool->allocate_resource_grid(context); srsran_assert(ul_grid, "Failed to get grid."); - ul_handler.handle_new_uplink_slot(context, std::move(ul_grid)); + ul_handler.handle_new_uplink_slot(context, ul_grid); } // Sleep until the end of the slot. diff --git a/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h b/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h index 796eb0badf..bd08d36b94 100644 --- a/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h +++ b/tests/unittests/phy/upper/upper_phy_rg_gateway_test_doubles.h @@ -21,7 +21,7 @@ class upper_phy_rg_gateway_fto : public upper_phy_rg_gateway { public: bool sent = false; - void send(const resource_grid_context& context, const shared_resource_grid& grid) override { sent = true; } + void send(const resource_grid_context& context, shared_resource_grid grid) override { sent = true; } void clear_sent() { sent = false; } }; From 924ddcfebb12f0753d7229299f8f907684521fcd Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 19 Aug 2024 14:04:06 +0200 Subject: [PATCH 308/407] phy: improve readeability of PDxCH processor in the lower PHY --- .../downlink/pdxch/pdxch_processor_impl.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp b/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp index 9663d24e79..58232cd50a 100644 --- a/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp +++ b/lib/phy/lower/processors/downlink/pdxch/pdxch_processor_impl.cpp @@ -35,32 +35,37 @@ bool pdxch_processor_impl::process_symbol(baseband_gateway_buffer_writer& { srsran_assert(notifier != nullptr, "Notifier has not been connected."); - // Check if the slot has changed. + // Update the current resource grid if the slot has changed. if (context.slot != current_slot) { // Update slot. current_slot = context.slot; + // Release current grid. + current_grid.release(); + // Exchange an empty request with the current slot with a stored request. auto request = requests.exchange({context.slot, shared_resource_grid()}); - // Handle the returned request. + // If the request resource grid pointer is invalid, the request is empty. if (!request.grid) { - // If the request resource grid pointer is invalid, the request is empty. - current_grid.release(); return false; } + // If the slot of the request does not match the current slot, then notify a late event. if (current_slot != request.slot) { - // If the slot of the request does not match the current slot, then notify a late event. resource_grid_context late_context; late_context.slot = request.slot; late_context.sector = context.sector; notifier->on_pdxch_request_late(late_context); - current_grid.release(); return false; } - // If the request is valid, then select request grid. + // Discard the resource grid if there is nothing to transmit. + if (request.grid.get_reader().is_empty()) { + return false; + } + + // Update the current grid with the new resource grid. current_grid = std::move(request.grid); } @@ -69,11 +74,6 @@ bool pdxch_processor_impl::process_symbol(baseband_gateway_buffer_writer& return false; } - // Skip processing if the resource grid is empty. - if (current_grid.get_reader().is_empty()) { - return false; - } - // Symbol index within the subframe. unsigned symbol_index_subframe = context.symbol + context.slot.subframe_slot_index() * nof_symbols_per_slot; From 01f1399ae27e635248d7107716ea213ebf192f58 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 20 Aug 2024 14:14:05 +0200 Subject: [PATCH 309/407] ofh: fix OFH integration test grid allocation --- .../ofh/ofh_integration_test.cpp | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index d47163f594..672cfe5547 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -723,9 +723,13 @@ class test_du_emulator // Push downlink data. if (is_dl_slot) { resource_grid_context context{slot, 0}; - - shared_resource_grid dl_grid = dl_rg_pool->allocate_resource_grid(context); - srsran_assert(dl_grid, "Failed to get grid."); + shared_resource_grid dl_grid; + while (!dl_grid) { + dl_grid = dl_rg_pool->allocate_resource_grid(context); + if (!dl_grid) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + } dl_handler.handle_dl_data(context, dl_grid); logger.info("DU emulator pushed DL data in slot {}", slot); @@ -735,9 +739,13 @@ class test_du_emulator if (is_ul_slot) { slot_id = tdd_pattern.dl_ul_tx_period_nof_slots - slot_id - 1; resource_grid_context context{slot, 0}; - - shared_resource_grid ul_grid = ul_rg_pool->allocate_resource_grid(context); - srsran_assert(ul_grid, "Failed to get grid."); + shared_resource_grid ul_grid; + while (!ul_grid) { + ul_grid = ul_rg_pool->allocate_resource_grid(context); + if (!ul_grid) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + } ul_handler.handle_new_uplink_slot(context, ul_grid); } From 446e85f7107528442271f937ed6285b94835c8a0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 20 Aug 2024 18:09:29 +0200 Subject: [PATCH 310/407] phy: avoid resource grid warning during gnb tear down --- lib/phy/support/resource_grid_pool_impl.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/phy/support/resource_grid_pool_impl.cpp b/lib/phy/support/resource_grid_pool_impl.cpp index 1f90c2e39c..cd1fad4462 100644 --- a/lib/phy/support/resource_grid_pool_impl.cpp +++ b/lib/phy/support/resource_grid_pool_impl.cpp @@ -125,11 +125,9 @@ void resource_grid_pool_impl::notify_release_scope(unsigned identifier) // Try to execute the asynchronous housekeeping task. bool success = async_executor->execute(set_all_zero_func); - // Warn about the failure to enqueue the zeroing task. + // Ensure the resource grid is marked as available even if it is not empty. + // Avoid warnings about failure to prevent false alarms during gNb teardown. if (!success) { - logger.warning("Failed to enqueue grid zeroing task."); - - // Make the resource grid available even if it is not empty. grids_scope_count[identifier] = ref_counter_available; } } From 068df2d7bd702ebc40771908bcd1992172f08390 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 20 Aug 2024 16:00:45 +0200 Subject: [PATCH 311/407] f1u,du: DDDS shall always include transmitted (UM/AM) and delivered (AM) PDCP SNs... ...when available. --- .../du_high/du_high_config_translators.cpp | 1 + include/srsran/du/du_qos_config_helpers.h | 5 ++++ include/srsran/f1u/du/f1u_config.h | 12 ++++++-- lib/f1u/du/f1u_bearer_impl.cpp | 30 +++++++++++++++---- lib/f1u/du/f1u_bearer_impl.h | 4 --- .../procedures/ue_configuration_test.cpp | 1 + .../f1u/common/f1u_connector_test.cpp | 1 + tests/unittests/f1u/du/f1u_du_bearer_test.cpp | 30 +++++++++++++++++-- 8 files changed, 69 insertions(+), 15 deletions(-) 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 dad4d59bd2..509ccd5d43 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 @@ -737,6 +737,7 @@ std::map srsran::generate_du_qos_config(const du_high_ // Convert F1-U config auto& out_f1u = out_cfg[qos.five_qi].f1u; + out_f1u.is_am_bearer = qos.rlc.mode == "am"; //< t-Notify out_f1u.t_notify = qos.f1u_du.t_notify; out_f1u.rlc_queue_bytes_limit = diff --git a/include/srsran/du/du_qos_config_helpers.h b/include/srsran/du/du_qos_config_helpers.h index 8ec28ee87b..bcc523f77a 100644 --- a/include/srsran/du/du_qos_config_helpers.h +++ b/include/srsran/du/du_qos_config_helpers.h @@ -59,6 +59,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U + cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC @@ -80,6 +81,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U + cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC @@ -108,6 +110,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.rx.max_sn_per_status = {}; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U + cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC @@ -127,6 +130,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U + cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; cfg.f1u.warn_on_drop = warn_on_drop; @@ -156,6 +160,7 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.rx.max_sn_per_status = {}; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U + cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; cfg.f1u.warn_on_drop = warn_on_drop; diff --git a/include/srsran/f1u/du/f1u_config.h b/include/srsran/f1u/du/f1u_config.h index 7982b5fc29..d08abe4efe 100644 --- a/include/srsran/f1u/du/f1u_config.h +++ b/include/srsran/f1u/du/f1u_config.h @@ -18,14 +18,15 @@ namespace srsran::srs_du { /// \brief Configurable parameters of the F1-U bearer in the DU struct f1u_config { + bool is_am_bearer; ///< Indicates whether this is a RLC AM bearer, i.e. SDU delivery is notified. uint32_t t_notify; ///< Timer used for periodic transmission of uplink notifications uint32_t rlc_queue_bytes_limit; ///< RLC queue limit in bytes. Used for initial report of buffer space to the CU-UP. bool warn_on_drop = true; ///< Log a warning instead of an info message whenever a PDU is dropped bool operator==(const f1u_config& other) const { - return t_notify == other.t_notify and rlc_queue_bytes_limit == other.rlc_queue_bytes_limit and - warn_on_drop == other.warn_on_drop; + return is_am_bearer == other.is_am_bearer and t_notify == other.t_notify and + rlc_queue_bytes_limit == other.rlc_queue_bytes_limit and warn_on_drop == other.warn_on_drop; } }; @@ -45,7 +46,12 @@ struct formatter { template auto format(srsran::srs_du::f1u_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) { - return format_to(ctx.out(), "t_notif={} warn_on_drop={}", cfg.t_notify, cfg.warn_on_drop); + return format_to(ctx.out(), + "is_am_bearer={} t_notify={} rlc_queue_bytes_limit={} warn_on_drop={}", + cfg.is_am_bearer, + cfg.t_notify, + cfg.rlc_queue_bytes_limit, + cfg.warn_on_drop); } }; diff --git a/lib/f1u/du/f1u_bearer_impl.cpp b/lib/f1u/du/f1u_bearer_impl.cpp index 8e3641002b..6b0ab9b6e9 100644 --- a/lib/f1u/du/f1u_bearer_impl.cpp +++ b/lib/f1u/du/f1u_bearer_impl.cpp @@ -142,9 +142,13 @@ bool f1u_bearer_impl::fill_desired_buffer_size_of_data_radio_bearer(nru_dl_data_ bool f1u_bearer_impl::fill_highest_transmitted_pdcp_sn(nru_dl_data_delivery_status& status) { uint32_t cur_highest_transmitted_pdcp_sn = highest_transmitted_pdcp_sn.load(std::memory_order_relaxed); - if (cur_highest_transmitted_pdcp_sn != notif_highest_transmitted_pdcp_sn) { + // TS 38.425 Sec. 5.4.2.1 + // (...) + // In case the DL DATA DELIVERY STATUS frame is sent before any NR PDCP PDU is transferred to lower layers, the + // information on the highest NR PDCP PDU sequence number successfully delivered in sequence to the UE and the highest + // NR PDCP PDU sequence number transmitted to the lower layers may not be provided. + if (cur_highest_transmitted_pdcp_sn != unset_pdcp_sn) { logger.log_debug("Adding highest transmitted pdcp_sn={}", cur_highest_transmitted_pdcp_sn); - notif_highest_transmitted_pdcp_sn = cur_highest_transmitted_pdcp_sn; status.highest_transmitted_pdcp_sn = cur_highest_transmitted_pdcp_sn; return true; } @@ -154,9 +158,13 @@ bool f1u_bearer_impl::fill_highest_transmitted_pdcp_sn(nru_dl_data_delivery_stat bool f1u_bearer_impl::fill_highest_delivered_pdcp_sn(nru_dl_data_delivery_status& status) { uint32_t cur_highest_delivered_pdcp_sn = highest_delivered_pdcp_sn.load(std::memory_order_relaxed); - if (cur_highest_delivered_pdcp_sn != notif_highest_delivered_pdcp_sn) { + // TS 38.425 Sec. 5.4.2.1 + // (...) + // In case the DL DATA DELIVERY STATUS frame is sent before any NR PDCP PDU is transferred to lower layers, the + // information on the highest NR PDCP PDU sequence number successfully delivered in sequence to the UE and the highest + // NR PDCP PDU sequence number transmitted to the lower layers may not be provided. + if (cur_highest_delivered_pdcp_sn != unset_pdcp_sn) { logger.log_debug("Adding highest delivered pdcp_sn={}", cur_highest_delivered_pdcp_sn); - notif_highest_delivered_pdcp_sn = cur_highest_delivered_pdcp_sn; status.highest_delivered_pdcp_sn = cur_highest_delivered_pdcp_sn; return true; } @@ -166,6 +174,7 @@ bool f1u_bearer_impl::fill_highest_delivered_pdcp_sn(nru_dl_data_delivery_status bool f1u_bearer_impl::fill_highest_retransmitted_pdcp_sn(nru_dl_data_delivery_status& status) { uint32_t cur_highest_retransmitted_pdcp_sn = highest_retransmitted_pdcp_sn.load(std::memory_order_relaxed); + // Only fill when value has changed since last time if (cur_highest_retransmitted_pdcp_sn != notif_highest_retransmitted_pdcp_sn) { logger.log_debug("Adding highest retransmitted pdcp_sn={}", cur_highest_retransmitted_pdcp_sn); notif_highest_retransmitted_pdcp_sn = cur_highest_retransmitted_pdcp_sn; @@ -179,6 +188,7 @@ bool f1u_bearer_impl::fill_highest_delivered_retransmitted_pdcp_sn(nru_dl_data_d { uint32_t cur_highest_delivered_retransmitted_pdcp_sn = highest_delivered_retransmitted_pdcp_sn.load(std::memory_order_relaxed); + // Only fill when value has changed since last time if (cur_highest_delivered_retransmitted_pdcp_sn != notif_highest_delivered_retransmitted_pdcp_sn) { logger.log_debug("Adding highest delivered retransmitted pdcp_sn={}", cur_highest_delivered_retransmitted_pdcp_sn); notif_highest_delivered_retransmitted_pdcp_sn = cur_highest_delivered_retransmitted_pdcp_sn; @@ -195,7 +205,17 @@ void f1u_bearer_impl::fill_data_delivery_status(nru_ul_message& msg) status_changed |= fill_desired_buffer_size_of_data_radio_bearer(status); status_changed |= fill_highest_transmitted_pdcp_sn(status); - status_changed |= fill_highest_delivered_pdcp_sn(status); + if (cfg.is_am_bearer) { + // TS 38.425 Sec. 5.4.2.1 + // (...) + // When the corresponding node decides to trigger the Feedback for Downlink Data Delivery procedure it shall report + // as specified in section 5.2: + // a) in case of RLC AM, the highest NR PDCP PDU sequence number successfully delivered in sequence to the UE among + // those NR PDCP PDUs received from the node hosting the NR PDCP entity i.e. excludes those retransmission NR PDCP + // PDUs; + // (...) + status_changed |= fill_highest_delivered_pdcp_sn(status); + } status_changed |= fill_highest_retransmitted_pdcp_sn(status); status_changed |= fill_highest_delivered_retransmitted_pdcp_sn(status); diff --git a/lib/f1u/du/f1u_bearer_impl.h b/lib/f1u/du/f1u_bearer_impl.h index 780e545163..13e306edd6 100644 --- a/lib/f1u/du/f1u_bearer_impl.h +++ b/lib/f1u/du/f1u_bearer_impl.h @@ -88,10 +88,6 @@ class f1u_bearer_impl final : public f1u_bearer, /// Holds the latest information of the available space in the RLC SDU queue that was reported to the upper layers /// (i.e. torward CU-UP) uint32_t notif_desired_buffer_size_for_data_radio_bearer; - /// Holds the last highest transmitted PDCP SN that was reported to upper layers (i.e. towards CU-UP) - uint32_t notif_highest_transmitted_pdcp_sn = unset_pdcp_sn; - /// Holds the last highest delivered PDCP SN that was reported to upper layers (i.e. towards CU-UP) - uint32_t notif_highest_delivered_pdcp_sn = unset_pdcp_sn; /// Holds the last highest retransmitted PDCP SN that was reported to upper layers (i.e. towards CU-UP) uint32_t notif_highest_retransmitted_pdcp_sn = unset_pdcp_sn; /// Holds the last highest delivered retransmitted PDCP SN that was reported to upper layers (i.e. towards CU-UP) diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 9a2c757a7e..49dd953bd3 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -57,6 +57,7 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test new_drb.pdcp_sn_len = drb.pdcp_sn_len; new_drb.s_nssai = drb.qos_info.s_nssai; new_drb.qos = drb.qos_info.drb_qos; + new_drb.f1u.is_am_bearer = new_drb.rlc_cfg.mode == rlc_mode::am; new_drb.f1u.t_notify = 100; new_drb.f1u.warn_on_drop = false; } diff --git a/tests/unittests/f1u/common/f1u_connector_test.cpp b/tests/unittests/f1u/common/f1u_connector_test.cpp index bf55542ae0..35797a3308 100644 --- a/tests/unittests/f1u/common/f1u_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_connector_test.cpp @@ -80,6 +80,7 @@ class f1u_connector_test : public ::testing::Test f1u_conn = std::make_unique(); // prepare F1-U DU bearer config + f1u_du_config.is_am_bearer = true; f1u_du_config.t_notify = 10; f1u_du_config.warn_on_drop = true; diff --git a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp index 8daaa0d4e6..b4aa62eff2 100644 --- a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp +++ b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp @@ -69,6 +69,7 @@ class f1u_du_test : public ::testing::Test, public f1u_trx_test logger.info("Creating F1-U bearer"); tester = std::make_unique(); f1u_config config = {}; + config.is_am_bearer = true; config.t_notify = f1u_ul_notif_time_ms; config.warn_on_drop = true; drb_id_t drb_id = drb_id_t::drb1; @@ -286,7 +287,18 @@ TEST_F(f1u_du_test, tx_pdcp_pdus_with_transmit_notification) ASSERT_FALSE(tester->tx_msg_list.empty()); EXPECT_EQ(tester->tx_msg_list.front().t_pdu.value(), tx_pdcp_pdu2); - EXPECT_FALSE(tester->tx_msg_list.front().data_delivery_status.has_value()); + EXPECT_TRUE(tester->tx_msg_list.front().data_delivery_status.has_value()); + { + nru_dl_data_delivery_status& status = tester->tx_msg_list.front().data_delivery_status.value(); + EXPECT_FALSE(status.final_frame_ind); + EXPECT_FALSE(status.lost_nru_sn_ranges.has_value()); + EXPECT_FALSE(status.highest_delivered_pdcp_sn.has_value()); + EXPECT_FALSE(status.cause_value.has_value()); + EXPECT_FALSE(status.highest_delivered_retransmitted_pdcp_sn.has_value()); + EXPECT_FALSE(status.highest_retransmitted_pdcp_sn.has_value()); + ASSERT_TRUE(status.highest_transmitted_pdcp_sn.has_value()); + EXPECT_EQ(status.highest_transmitted_pdcp_sn.value(), highest_pdcp_sn + 1); + } EXPECT_FALSE(tester->tx_msg_list.front().assistance_information.has_value()); tester->tx_msg_list.pop_front(); @@ -343,7 +355,18 @@ TEST_F(f1u_du_test, tx_pdcp_pdus_with_delivery_notification) ASSERT_FALSE(tester->tx_msg_list.empty()); EXPECT_EQ(tester->tx_msg_list.front().t_pdu.value(), tx_pdcp_pdu2); - EXPECT_FALSE(tester->tx_msg_list.front().data_delivery_status.has_value()); + EXPECT_TRUE(tester->tx_msg_list.front().data_delivery_status.has_value()); + { + nru_dl_data_delivery_status& status = tester->tx_msg_list.front().data_delivery_status.value(); + EXPECT_FALSE(status.final_frame_ind); + EXPECT_FALSE(status.lost_nru_sn_ranges.has_value()); + ASSERT_TRUE(status.highest_delivered_pdcp_sn.has_value()); + EXPECT_EQ(status.highest_delivered_pdcp_sn.value(), highest_pdcp_sn + 1); + EXPECT_FALSE(status.highest_delivered_retransmitted_pdcp_sn.has_value()); + EXPECT_FALSE(status.cause_value.has_value()); + EXPECT_FALSE(status.highest_retransmitted_pdcp_sn.has_value()); + EXPECT_FALSE(status.highest_transmitted_pdcp_sn.has_value()); + } EXPECT_FALSE(tester->tx_msg_list.front().assistance_information.has_value()); tester->tx_msg_list.pop_front(); @@ -369,7 +392,8 @@ TEST_F(f1u_du_test, tx_pdcp_pdus_with_delivery_notification) nru_dl_data_delivery_status& status = tester->tx_msg_list.front().data_delivery_status.value(); EXPECT_FALSE(status.final_frame_ind); EXPECT_FALSE(status.lost_nru_sn_ranges.has_value()); - EXPECT_FALSE(status.highest_delivered_pdcp_sn.has_value()); + ASSERT_TRUE(status.highest_delivered_pdcp_sn.has_value()); + EXPECT_EQ(status.highest_delivered_pdcp_sn.value(), highest_pdcp_sn + 1); EXPECT_FALSE(status.cause_value.has_value()); EXPECT_FALSE(status.highest_delivered_retransmitted_pdcp_sn.has_value()); EXPECT_FALSE(status.highest_retransmitted_pdcp_sn.has_value()); From 0294f2e82afebe812ce9c4aa0594b88c77872e30 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 20 Aug 2024 16:21:13 +0200 Subject: [PATCH 312/407] f1u,du: remove unnecessary is_am_bearer flag... ...because RLC UM bearer never notify delivered PDCP SNs, hence in case of UM the value will stay on the sentinel value so it will not be added to the DDDS. --- .../du_high/du_high_config_translators.cpp | 1 - include/srsran/du/du_qos_config_helpers.h | 5 ----- include/srsran/f1u/du/f1u_config.h | 8 +++----- lib/f1u/du/f1u_bearer_impl.cpp | 18 +++++++----------- .../procedures/ue_configuration_test.cpp | 1 - .../f1u/common/f1u_connector_test.cpp | 1 - tests/unittests/f1u/du/f1u_du_bearer_test.cpp | 1 - 7 files changed, 10 insertions(+), 25 deletions(-) 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 509ccd5d43..dad4d59bd2 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 @@ -737,7 +737,6 @@ std::map srsran::generate_du_qos_config(const du_high_ // Convert F1-U config auto& out_f1u = out_cfg[qos.five_qi].f1u; - out_f1u.is_am_bearer = qos.rlc.mode == "am"; //< t-Notify out_f1u.t_notify = qos.f1u_du.t_notify; out_f1u.rlc_queue_bytes_limit = diff --git a/include/srsran/du/du_qos_config_helpers.h b/include/srsran/du/du_qos_config_helpers.h index bcc523f77a..8ec28ee87b 100644 --- a/include/srsran/du/du_qos_config_helpers.h +++ b/include/srsran/du/du_qos_config_helpers.h @@ -59,7 +59,6 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC @@ -81,7 +80,6 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC @@ -110,7 +108,6 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.rx.max_sn_per_status = {}; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; // MAC @@ -130,7 +127,6 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.um.tx.queue_size_bytes = default_rlc_queue_size_bytes; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; cfg.f1u.warn_on_drop = warn_on_drop; @@ -160,7 +156,6 @@ inline std::map make_default_du_qos_config_list(bool w cfg.rlc.am.rx.max_sn_per_status = {}; cfg.rlc.metrics_period = std::chrono::milliseconds(rlc_metrics_report); // F1-U - cfg.f1u.is_am_bearer = cfg.rlc.mode == rlc_mode::am; cfg.f1u.t_notify = 10; cfg.f1u.rlc_queue_bytes_limit = default_rlc_queue_size_bytes; cfg.f1u.warn_on_drop = warn_on_drop; diff --git a/include/srsran/f1u/du/f1u_config.h b/include/srsran/f1u/du/f1u_config.h index d08abe4efe..c111cfb49a 100644 --- a/include/srsran/f1u/du/f1u_config.h +++ b/include/srsran/f1u/du/f1u_config.h @@ -18,15 +18,14 @@ namespace srsran::srs_du { /// \brief Configurable parameters of the F1-U bearer in the DU struct f1u_config { - bool is_am_bearer; ///< Indicates whether this is a RLC AM bearer, i.e. SDU delivery is notified. uint32_t t_notify; ///< Timer used for periodic transmission of uplink notifications uint32_t rlc_queue_bytes_limit; ///< RLC queue limit in bytes. Used for initial report of buffer space to the CU-UP. bool warn_on_drop = true; ///< Log a warning instead of an info message whenever a PDU is dropped bool operator==(const f1u_config& other) const { - return is_am_bearer == other.is_am_bearer and t_notify == other.t_notify and - rlc_queue_bytes_limit == other.rlc_queue_bytes_limit and warn_on_drop == other.warn_on_drop; + return t_notify == other.t_notify and rlc_queue_bytes_limit == other.rlc_queue_bytes_limit and + warn_on_drop == other.warn_on_drop; } }; @@ -47,8 +46,7 @@ struct formatter { auto format(srsran::srs_du::f1u_config cfg, FormatContext& ctx) -> decltype(std::declval().out()) { return format_to(ctx.out(), - "is_am_bearer={} t_notify={} rlc_queue_bytes_limit={} warn_on_drop={}", - cfg.is_am_bearer, + "t_notify={} rlc_queue_bytes_limit={} warn_on_drop={}", cfg.t_notify, cfg.rlc_queue_bytes_limit, cfg.warn_on_drop); diff --git a/lib/f1u/du/f1u_bearer_impl.cpp b/lib/f1u/du/f1u_bearer_impl.cpp index 6b0ab9b6e9..515e306113 100644 --- a/lib/f1u/du/f1u_bearer_impl.cpp +++ b/lib/f1u/du/f1u_bearer_impl.cpp @@ -160,6 +160,12 @@ bool f1u_bearer_impl::fill_highest_delivered_pdcp_sn(nru_dl_data_delivery_status uint32_t cur_highest_delivered_pdcp_sn = highest_delivered_pdcp_sn.load(std::memory_order_relaxed); // TS 38.425 Sec. 5.4.2.1 // (...) + // When the corresponding node decides to trigger the Feedback for Downlink Data Delivery procedure it shall report + // as specified in section 5.2: + // a) in case of RLC AM, the highest NR PDCP PDU sequence number successfully delivered in sequence to the UE among + // those NR PDCP PDUs received from the node hosting the NR PDCP entity i.e. excludes those retransmission NR PDCP + // PDUs; + // (...) // In case the DL DATA DELIVERY STATUS frame is sent before any NR PDCP PDU is transferred to lower layers, the // information on the highest NR PDCP PDU sequence number successfully delivered in sequence to the UE and the highest // NR PDCP PDU sequence number transmitted to the lower layers may not be provided. @@ -205,17 +211,7 @@ void f1u_bearer_impl::fill_data_delivery_status(nru_ul_message& msg) status_changed |= fill_desired_buffer_size_of_data_radio_bearer(status); status_changed |= fill_highest_transmitted_pdcp_sn(status); - if (cfg.is_am_bearer) { - // TS 38.425 Sec. 5.4.2.1 - // (...) - // When the corresponding node decides to trigger the Feedback for Downlink Data Delivery procedure it shall report - // as specified in section 5.2: - // a) in case of RLC AM, the highest NR PDCP PDU sequence number successfully delivered in sequence to the UE among - // those NR PDCP PDUs received from the node hosting the NR PDCP entity i.e. excludes those retransmission NR PDCP - // PDUs; - // (...) - status_changed |= fill_highest_delivered_pdcp_sn(status); - } + status_changed |= fill_highest_delivered_pdcp_sn(status); status_changed |= fill_highest_retransmitted_pdcp_sn(status); status_changed |= fill_highest_delivered_retransmitted_pdcp_sn(status); diff --git a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp index 49dd953bd3..9a2c757a7e 100644 --- a/tests/unittests/du_manager/procedures/ue_configuration_test.cpp +++ b/tests/unittests/du_manager/procedures/ue_configuration_test.cpp @@ -57,7 +57,6 @@ class ue_config_tester : public du_manager_proc_tester, public ::testing::Test new_drb.pdcp_sn_len = drb.pdcp_sn_len; new_drb.s_nssai = drb.qos_info.s_nssai; new_drb.qos = drb.qos_info.drb_qos; - new_drb.f1u.is_am_bearer = new_drb.rlc_cfg.mode == rlc_mode::am; new_drb.f1u.t_notify = 100; new_drb.f1u.warn_on_drop = false; } diff --git a/tests/unittests/f1u/common/f1u_connector_test.cpp b/tests/unittests/f1u/common/f1u_connector_test.cpp index 35797a3308..bf55542ae0 100644 --- a/tests/unittests/f1u/common/f1u_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_connector_test.cpp @@ -80,7 +80,6 @@ class f1u_connector_test : public ::testing::Test f1u_conn = std::make_unique(); // prepare F1-U DU bearer config - f1u_du_config.is_am_bearer = true; f1u_du_config.t_notify = 10; f1u_du_config.warn_on_drop = true; diff --git a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp index b4aa62eff2..5a209729b3 100644 --- a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp +++ b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp @@ -69,7 +69,6 @@ class f1u_du_test : public ::testing::Test, public f1u_trx_test logger.info("Creating F1-U bearer"); tester = std::make_unique(); f1u_config config = {}; - config.is_am_bearer = true; config.t_notify = f1u_ul_notif_time_ms; config.warn_on_drop = true; drb_id_t drb_id = drb_id_t::drb1; From e8dc475db1b8eb811b41ce3f314b047815b8c98c Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 21 Aug 2024 07:05:32 +0200 Subject: [PATCH 313/407] f1u,cu: ignore duplicate notification of transmitted and delivered PDCP SNs --- lib/f1u/cu_up/f1u_bearer_impl.cpp | 20 +++++++++++++++----- lib/f1u/cu_up/f1u_bearer_impl.h | 8 ++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/f1u/cu_up/f1u_bearer_impl.cpp b/lib/f1u/cu_up/f1u_bearer_impl.cpp index b0b9954f91..79eac91b94 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.cpp +++ b/lib/f1u/cu_up/f1u_bearer_impl.cpp @@ -67,16 +67,26 @@ void f1u_bearer_impl::handle_pdu_impl(nru_ul_message msg) nru_dl_data_delivery_status& status = msg.data_delivery_status.value(); // Highest transmitted PDCP SN if (status.highest_transmitted_pdcp_sn.has_value()) { - ue_inactivity_timer.run(); // restart inactivity timer due to confirmed transmission of DL PDU uint32_t pdcp_sn = status.highest_transmitted_pdcp_sn.value(); - logger.log_debug("Notifying highest transmitted pdcp_sn={}", pdcp_sn); - rx_delivery_notifier.on_transmit_notification(pdcp_sn); + if (pdcp_sn != notif_highest_transmitted_pdcp_sn) { + ue_inactivity_timer.run(); // restart inactivity timer due to confirmed transmission of DL PDU + logger.log_debug("Notifying highest transmitted pdcp_sn={}", pdcp_sn); + notif_highest_transmitted_pdcp_sn = pdcp_sn; + rx_delivery_notifier.on_transmit_notification(pdcp_sn); + } else { + logger.log_debug("Ignored duplicate notification of highest transmitted pdcp_sn={}", pdcp_sn); + } } // Highest successfully delivered PDCP SN if (status.highest_delivered_pdcp_sn.has_value()) { uint32_t pdcp_sn = status.highest_delivered_pdcp_sn.value(); - logger.log_debug("Notifying highest successfully delivered pdcp_sn={}", pdcp_sn); - rx_delivery_notifier.on_delivery_notification(pdcp_sn); + if (pdcp_sn != notif_highest_delivered_pdcp_sn) { + logger.log_debug("Notifying highest successfully delivered pdcp_sn={}", pdcp_sn); + notif_highest_delivered_pdcp_sn = pdcp_sn; + rx_delivery_notifier.on_delivery_notification(pdcp_sn); + } else { + logger.log_debug("Ignored duplicate notification of highest successfully delivered pdcp_sn={}", pdcp_sn); + } } // Highest retransmitted PDCP SN if (status.highest_retransmitted_pdcp_sn.has_value()) { diff --git a/lib/f1u/cu_up/f1u_bearer_impl.h b/lib/f1u/cu_up/f1u_bearer_impl.h index 261c47b8b0..b9c12f33af 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.h +++ b/lib/f1u/cu_up/f1u_bearer_impl.h @@ -72,6 +72,9 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ up_transport_layer_info ul_tnl_info; task_executor& ul_exec; + /// Sentinel value representing a not-yet set PDCP SN + static constexpr uint32_t unset_pdcp_sn = UINT32_MAX; + /// Downlink notification timer that triggers periodic transmission of discard blocks towards lower layers. The /// purpose of this timer is to avoid excessive downlink notifications for every PDCP SN that is discarded by upper /// layers. @@ -81,6 +84,11 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ /// The timer shall be restarted on each UL PDU (= UL activity) and on each transmit notification (= DL activity). unique_timer& ue_inactivity_timer; + /// Holds the last highest transmitted PDCP SN that was reported to upper layers + uint32_t notif_highest_transmitted_pdcp_sn = unset_pdcp_sn; + /// Holds the last highest delivered PDCP SN that was reported to upper layers + uint32_t notif_highest_delivered_pdcp_sn = unset_pdcp_sn; + /// Collection of pending \c nru_pdcp_sn_discard_block objects. nru_pdcp_sn_discard_blocks discard_blocks; From 8cc7b87879808cbe7765794292bd6daca54b0696 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 20 Aug 2024 17:52:11 +0200 Subject: [PATCH 314/407] du_high: fix du_high_benchmark failure due to lack of RLC metric notifier --- lib/du_manager/converters/rlc_config_helpers.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/du_manager/converters/rlc_config_helpers.cpp b/lib/du_manager/converters/rlc_config_helpers.cpp index 1246b62665..612bfbab4c 100644 --- a/lib/du_manager/converters/rlc_config_helpers.cpp +++ b/lib/du_manager/converters/rlc_config_helpers.cpp @@ -72,5 +72,8 @@ srsran::srs_du::make_rlc_entity_creation_message(gnb_du_id_t msg, gnb_du_id, ue_index, pcell_index, bearer, rlc_cfg, du_services, rlc_rlf_notifier, pcap_writer); msg.rb_id = bearer.drb_id; msg.rlc_metrics_notif = rlc_metrics_notifier_; + if (msg.rlc_metrics_notif == nullptr) { + msg.config.metrics_period = timer_duration{0}; + } return msg; } From 64d8cfed453d3acbf643f595ab7c5a467aadb258 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 19:26:32 +0200 Subject: [PATCH 315/407] du_high: reduce number of UEs in du_high_many_ues_test --- .../du_high/du_high_many_ues_test.cpp | 58 ++++++++++++++++++- .../test_utils/du_high_env_simulator.cpp | 7 ++- .../test_utils/du_high_env_simulator.h | 6 +- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index 3c920d5a70..fa971e4432 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -20,6 +20,13 @@ static du_high_env_sim_params create_custom_params() { du_high_env_sim_params params; // Reduce number of PUCCH resources, so we do not have to create so many UEs to reach the saturation point. + params.builder_params.emplace(); + params.builder_params.value().scs_common = subcarrier_spacing::kHz30; + params.builder_params.value().dl_f_ref_arfcn = 520002; + params.builder_params.value().band = + band_helper::get_band_from_dl_arfcn(params.builder_params.value().dl_f_ref_arfcn); + params.builder_params.value().tdd_ul_dl_cfg_common = + tdd_ul_dl_config_common{subcarrier_spacing::kHz30, {10, 8, 5, 1, 4}}; params.pucch_cfg.emplace(); params.pucch_cfg->nof_ue_pucch_f0_or_f1_res_harq = 8; params.pucch_cfg->nof_ue_pucch_f2_res_harq = 8; @@ -50,6 +57,7 @@ TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_bei if (container.empty()) { // When DU-to-CU container is empty, it means that the DU could not allocate resources for the UE. + test_logger.info("rnti={}: UE rejected due to lack of DU resources", rnti); ASSERT_TRUE(this->run_rrc_reject(rnti)) << "RRC Reject not scheduled"; break; @@ -58,7 +66,7 @@ TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_bei ASSERT_TRUE(this->run_rrc_setup(rnti)); } - ASSERT_GT(ue_count, 30) << "The number of UEs accepted by DU was too low"; + ASSERT_GT(ue_count, 5) << "The number of UEs accepted by DU was too low"; ASSERT_LT(ue_count, MAX_NOF_DU_UES) << "The DU is accepting UEs past its number of PUCCH resources"; // If we try to add more UEs, they also fail. @@ -72,3 +80,51 @@ TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_bei container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); ASSERT_FALSE(container.empty()) << "The resources of the released UE were not correctly cleaned up"; } + +TEST_F(du_high_many_ues_tester, when_du_releases_all_ues_then_all_resources_are_available_again) +{ + unsigned ue_count = 0; + for (; ue_count != MAX_NOF_DU_UES; ++ue_count) { + rnti_t rnti = to_rnti(next_rnti++); + ASSERT_TRUE(this->add_ue(rnti)); + + byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); + if (container.empty()) { + // When DU-to-CU container is empty, it means that the DU could not allocate resources for the UE. + + test_logger.info("rnti={}: UE rejected due to lack of DU resources", rnti); + ASSERT_TRUE(this->run_rrc_reject(rnti)) << "RRC Reject not scheduled"; + + break; + } + + ASSERT_TRUE(this->run_rrc_setup(rnti)); + } + + ASSERT_GT(ue_count, 5) << "The number of UEs accepted by DU was too low"; + ASSERT_LT(ue_count, MAX_NOF_DU_UES) << "The DU is accepting UEs past its number of PUCCH resources"; + + for (unsigned i = 0; i != ue_count; ++i) { + ASSERT_TRUE(this->run_ue_context_release(to_rnti(0x4601 + i))); + } + + unsigned prev_ue_count = ue_count; + ue_count = 0; + for (; ue_count != MAX_NOF_DU_UES; ++ue_count) { + rnti_t rnti = to_rnti(next_rnti++); + ASSERT_TRUE(this->add_ue(rnti)); + + byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); + if (container.empty()) { + // When DU-to-CU container is empty, it means that the DU could not allocate resources for the UE. + + ASSERT_TRUE(this->run_rrc_reject(rnti)) << "RRC Reject not scheduled"; + + break; + } + + ASSERT_TRUE(this->run_rrc_setup(rnti)); + } + + ASSERT_EQ(ue_count, prev_ue_count); +} diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 036f668d63..34a3143ae2 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -164,7 +164,8 @@ du_high_env_simulator::du_high_env_simulator(du_high_env_sim_params params) : cfg.ran.sched_cfg.log_broadcast_messages = false; cfg.ran.cells.reserve(params.nof_cells); - cell_config_builder_params builder_params; + auto builder_params = + params.builder_params.has_value() ? params.builder_params.value() : cell_config_builder_params{}; for (unsigned i = 0; i < params.nof_cells; ++i) { builder_params.pci = (pci_t)i; cfg.ran.cells.push_back(config_helpers::make_default_du_cell_config(builder_params)); @@ -183,7 +184,9 @@ du_high_env_simulator::du_high_env_simulator(du_high_env_sim_params params) : return cfg; }()), du_hi(make_du_high(du_high_cfg)), - next_slot(0, test_rgen::uniform_int(0, 10239)) + next_slot(to_numerology_value(du_high_cfg.ran.cells[0].scs_common), + test_rgen::uniform_int(0, 10239) * + get_nof_slots_per_subframe(du_high_cfg.ran.cells[0].scs_common)) { // Start DU and try to connect to CU. du_hi->start(); diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h index bce5591807..b432c98e7d 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.h @@ -17,6 +17,7 @@ #include "srsran/du_high/du_high.h" #include "srsran/du_high/du_high_configuration.h" #include "srsran/f1ap/common/f1ap_ue_id.h" +#include "srsran/scheduler/config/cell_config_builder_params.h" namespace srsran { namespace srs_du { @@ -42,8 +43,9 @@ bool is_ue_context_release_complete_valid(const f1ap_message& msg, /// Parameters to set the DU-high environment simulator. struct du_high_env_sim_params { - unsigned nof_cells = 1; - std::optional pucch_cfg; + unsigned nof_cells = 1; + std::optional builder_params; + std::optional pucch_cfg; }; class du_high_env_simulator From 6624b1bdc676051f6d525e71a7c9324d79659c8f Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Aug 2024 20:49:59 +0200 Subject: [PATCH 316/407] sched: refactor and clean logs of inability to find PUCCH in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 142 +++++++++--------- .../du_high/du_high_many_ues_test.cpp | 48 ------ 2 files changed, 73 insertions(+), 117 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 4f3705b1e0..a32d42a9a9 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -519,17 +519,54 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_a } // No resource found in UE's carriers and Search spaces. - slot_point pdcch_slot = res_alloc[0].slot; logger.debug("rnti={}: Skipped {} allocation in slots:[{},{}). Cause: no PDCCH/PDSCH/PUCCH resources available", u.crnti, not is_srb0.has_value() ? "ConRes CE" : *is_srb0 ? "SRB0 PDU" : "SRB1 PDU", - pdcch_slot, - pdcch_slot + max_dl_slots_ahead_sched + 1); + starting_slot, + sched_ref_slot + max_dl_slots_ahead_sched + 1); return dl_sched_outcome::next_ue; } +static std::pair, std::optional> +allocate_common_pucch(ue& u, + cell_resource_allocator& res_alloc, + pucch_allocator& pucch_alloc, + const pdcch_dl_information& pdcch_info, + span k1_values, + slot_point pdsch_slot, + slot_point min_ack_slot, + bool common_and_ded_alloc) +{ + const uint8_t min_k1 = min_ack_slot - pdsch_slot; + const unsigned pdsch_delay = pdsch_slot - res_alloc.slot_tx(); + + std::optional last_valid_k1; + for (uint8_t k1_candidate : k1_values) { + if (k1_candidate <= min_k1) { + // Skip k1 values that would result in a PUCCH transmission in a slot that is older than the most recent ACK slot. + continue; + } + slot_point uci_slot = pdsch_slot + k1_candidate; + if (not res_alloc.cfg.is_fully_ul_enabled(uci_slot)) { + // If it is not UL-enabled slot. + continue; + } + last_valid_k1 = k1_candidate; + + std::optional pucch_res_indicator = + common_and_ded_alloc + ? pucch_alloc.alloc_common_and_ded_harq_res( + res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate, pdcch_info) + : pucch_alloc.alloc_common_pucch_harq_ack_ue(res_alloc, u.crnti, pdsch_delay, k1_candidate, pdcch_info); + if (pucch_res_indicator.has_value()) { + return std::make_pair(*pucch_res_indicator, k1_candidate); + } + } + return std::make_pair(std::nullopt, last_valid_k1); +} + ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, cell_resource_allocator& res_alloc, @@ -647,28 +684,15 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, } // Allocate PUCCH resources. - unsigned k1 = dci_1_0_k1_values.front(); - // Minimum k1 value supported is 4. - std::optional pucch_res_indicator; - for (const auto k1_candidate : dci_1_0_k1_values) { - // Skip k1 values that would result in a PUCCH transmission in a slot that is older than the most recent ACK slot. - if (pdsch_alloc.slot + k1_candidate <= most_recent_ack_slot) { - continue; - } - pucch_res_indicator = - is_retx ? pucch_alloc.alloc_common_and_ded_harq_res( - res_alloc, u.crnti, u.get_pcell().cfg(), slot_offset + pdsch_td_cfg.k0, k1_candidate, *pdcch) - : pucch_alloc.alloc_common_pucch_harq_ack_ue( - res_alloc, u.crnti, slot_offset + pdsch_td_cfg.k0, k1_candidate, *pdcch); - if (pucch_res_indicator.has_value()) { - k1 = k1_candidate; - break; - } - } + auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch( + u, res_alloc, pucch_alloc, *pdcch, dci_1_0_k1_values, pdsch_alloc.slot, most_recent_ack_slot, is_retx); if (not pucch_res_indicator.has_value()) { - logger.debug("rnti={}: Failed to allocate PDSCH for ConRes CE for slot={}. Cause: No space in PUCCH", - u.crnti, - pdsch_alloc.slot); + if (chosen_k1.has_value()) { + // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. + logger.debug("rnti={}: Failed to allocate PDSCH for ConRes CE for slot={}. Cause: No space in PUCCH", + u.crnti, + pdsch_alloc.slot); + } pdcch_sch.cancel_last_pdcch(pdcch_alloc); return {}; } @@ -684,7 +708,7 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, pdsch_alloc.result.dl.ue_grants.emplace_back(), pucch_res_indicator.value(), pdsch_time_res, - k1, + chosen_k1.value(), mcs_idx, ue_grant_crbs, pdsch_cfg, @@ -860,27 +884,15 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 } // Allocate PUCCH resources. - unsigned k1 = dci_1_0_k1_values.front(); - // Minimum k1 value supported is 4. - std::optional pucch_res_indicator; - for (const auto k1_candidate : dci_1_0_k1_values) { - // Skip k1 values that would result in a PUCCH transmission in a slot that is older than the most recent ACK slot. - if (pdsch_alloc.slot + k1_candidate <= most_recent_ack_slot) { - continue; - } - pucch_res_indicator = - is_retx ? pucch_alloc.alloc_common_and_ded_harq_res( - res_alloc, u.crnti, u.get_pcell().cfg(), slot_offset + pdsch_td_cfg.k0, k1_candidate, *pdcch) - : pucch_alloc.alloc_common_pucch_harq_ack_ue( - res_alloc, u.crnti, slot_offset + pdsch_td_cfg.k0, k1_candidate, *pdcch); - if (pucch_res_indicator.has_value()) { - k1 = k1_candidate; - break; - } - } + auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch( + u, res_alloc, pucch_alloc, *pdcch, dci_1_0_k1_values, pdsch_alloc.slot, most_recent_ack_slot, is_retx); if (not pucch_res_indicator.has_value()) { - logger.debug( - "rnti={}: Failed to allocate PDSCH for SRB0 for slot={}. Cause: No space in PUCCH", u.crnti, pdsch_alloc.slot); + if (chosen_k1.has_value()) { + // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. + logger.debug("rnti={}: Failed to allocate PDSCH for SRB0 for slot={}. Cause: No space in PUCCH", + u.crnti, + pdsch_alloc.slot); + } pdcch_sch.cancel_last_pdcch(pdcch_alloc); return {}; } @@ -900,7 +912,7 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 pdsch_alloc.result.dl.ue_grants.emplace_back(), pucch_res_indicator.value(), pdsch_time_res, - k1, + chosen_k1.value(), mcs_idx, ue_grant_crbs, pdsch_cfg, @@ -1084,29 +1096,21 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 } // Allocate PUCCH resources. - unsigned k1 = dci_1_0_k1_values.front(); - // Minimum k1 value supported is 4. - std::optional pucch_res_indicator; - const bool allocate_common_and_ded_pucch = dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0 or is_retx; - for (const auto k1_candidate : dci_1_0_k1_values) { - // Skip the k1 values that would result in a PUCCH allocation that would overlap with the most recent ACK slot. - if (pdsch_alloc.slot + k1_candidate <= most_recent_ack_slot) { - continue; - } - pucch_res_indicator = - allocate_common_and_ded_pucch - ? pucch_alloc.alloc_common_and_ded_harq_res( - res_alloc, u.crnti, u.get_pcell().cfg(), slot_offset + pdsch_td_cfg.k0, k1_candidate, *pdcch) - : pucch_alloc.alloc_common_pucch_harq_ack_ue( - res_alloc, u.crnti, slot_offset + pdsch_td_cfg.k0, k1_candidate, *pdcch); - if (pucch_res_indicator.has_value()) { - k1 = k1_candidate; - break; - } - } + const bool alloc_common_and_ded_pucch = dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0 or is_retx; + auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + alloc_common_and_ded_pucch); if (not pucch_res_indicator.has_value()) { - logger.debug( - "rnti={}: Failed to allocate PDSCH for SRB1 for slot={}. Cause: No space in PUCCH", u.crnti, pdsch_alloc.slot); + if (chosen_k1.has_value()) { + logger.debug("rnti={}: Failed to allocate PDSCH for SRB1 for slot={}. Cause: No space in PUCCH", + u.crnti, + pdsch_alloc.slot); + } pdcch_sch.cancel_last_pdcch(pdcch_alloc); return {}; } @@ -1122,7 +1126,7 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 pdsch_alloc.result.dl.ue_grants.emplace_back(), pucch_res_indicator.value(), pdsch_time_res, - k1, + chosen_k1.value(), final_mcs_tbs.mcs, ue_grant_crbs, pdsch_cfg, diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index fa971e4432..a6a0eab4bb 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -80,51 +80,3 @@ TEST_F(du_high_many_ues_tester, when_du_runs_out_of_resources_then_ues_start_bei container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); ASSERT_FALSE(container.empty()) << "The resources of the released UE were not correctly cleaned up"; } - -TEST_F(du_high_many_ues_tester, when_du_releases_all_ues_then_all_resources_are_available_again) -{ - unsigned ue_count = 0; - for (; ue_count != MAX_NOF_DU_UES; ++ue_count) { - rnti_t rnti = to_rnti(next_rnti++); - ASSERT_TRUE(this->add_ue(rnti)); - - byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); - if (container.empty()) { - // When DU-to-CU container is empty, it means that the DU could not allocate resources for the UE. - - test_logger.info("rnti={}: UE rejected due to lack of DU resources", rnti); - ASSERT_TRUE(this->run_rrc_reject(rnti)) << "RRC Reject not scheduled"; - - break; - } - - ASSERT_TRUE(this->run_rrc_setup(rnti)); - } - - ASSERT_GT(ue_count, 5) << "The number of UEs accepted by DU was too low"; - ASSERT_LT(ue_count, MAX_NOF_DU_UES) << "The DU is accepting UEs past its number of PUCCH resources"; - - for (unsigned i = 0; i != ue_count; ++i) { - ASSERT_TRUE(this->run_ue_context_release(to_rnti(0x4601 + i))); - } - - unsigned prev_ue_count = ue_count; - ue_count = 0; - for (; ue_count != MAX_NOF_DU_UES; ++ue_count) { - rnti_t rnti = to_rnti(next_rnti++); - ASSERT_TRUE(this->add_ue(rnti)); - - byte_buffer container = test_helpers::get_du_to_cu_container(cu_notifier.last_f1ap_msgs.back()); - if (container.empty()) { - // When DU-to-CU container is empty, it means that the DU could not allocate resources for the UE. - - ASSERT_TRUE(this->run_rrc_reject(rnti)) << "RRC Reject not scheduled"; - - break; - } - - ASSERT_TRUE(this->run_rrc_setup(rnti)); - } - - ASSERT_EQ(ue_count, prev_ue_count); -} From 8f96fbf449926de881ed6d373218f9e9e478d468 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 20 Aug 2024 15:44:47 +0200 Subject: [PATCH 317/407] sched: fix common PUCCH scheduling in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 36 +++++++++---------- .../ue_scheduling/ue_fallback_scheduler.h | 1 - .../du_high/du_high_many_ues_test.cpp | 3 ++ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index a32d42a9a9..74c7a98df6 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -529,6 +529,18 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_a return dl_sched_outcome::next_ue; } +// Helper to determine DCI type to use in PDSCH. +static dci_dl_rnti_config_type get_dci_type(const ue& u, const dl_harq_process& h_dl) +{ + if (h_dl.has_pending_retx()) { + return h_dl.last_alloc_params().dci_cfg_type; + } else if (u.is_conres_ce_pending()) { + return dci_dl_rnti_config_type::tc_rnti_f1_0; + } + return dci_dl_rnti_config_type::c_rnti_f1_0; +} + +// Helper to allocate common (and optionally dedicated) PUCCH. static std::pair, std::optional> allocate_common_pucch(ue& u, cell_resource_allocator& res_alloc, @@ -539,12 +551,11 @@ allocate_common_pucch(ue& u, slot_point min_ack_slot, bool common_and_ded_alloc) { - const uint8_t min_k1 = min_ack_slot - pdsch_slot; const unsigned pdsch_delay = pdsch_slot - res_alloc.slot_tx(); std::optional last_valid_k1; for (uint8_t k1_candidate : k1_values) { - if (k1_candidate <= min_k1) { + if (pdsch_slot + k1_candidate <= min_ack_slot) { // Skip k1 values that would result in a PUCCH transmission in a slot that is older than the most recent ACK slot. continue; } @@ -588,8 +599,7 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, return {}; } - dci_dl_rnti_config_type dci_type = - is_retx ? h_dl_retx->last_alloc_params().dci_cfg_type : dci_dl_rnti_config_type::tc_rnti_f1_0; + dci_dl_rnti_config_type dci_type = get_dci_type(u, *h_dl); srsran_assert(dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0, "Only DCI 1_0 with TC-RNTI is supported for ConRes CE scheduling"); @@ -742,14 +752,7 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 return {}; } - dci_dl_rnti_config_type dci_type = dci_dl_rnti_config_type::c_rnti_f1_0; - if (is_retx) { - dci_type = h_dl->last_alloc_params().dci_cfg_type; - } else if (u.is_conres_ce_pending()) { - dci_type = dci_dl_rnti_config_type::tc_rnti_f1_0; - } - srsran_assert(dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 or dci_type == dci_dl_rnti_config_type::c_rnti_f1_0, - "Only DCI 1_0 with TC-RNTI or C-RNTI is supported for SRB0 scheduling"); + dci_dl_rnti_config_type dci_type = get_dci_type(u, *h_dl); pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) @@ -945,14 +948,7 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 return {}; } - dci_dl_rnti_config_type dci_type = dci_dl_rnti_config_type::c_rnti_f1_0; - if (is_retx) { - dci_type = h_dl->last_alloc_params().dci_cfg_type; - } else if (u.is_conres_ce_pending()) { - dci_type = dci_dl_rnti_config_type::tc_rnti_f1_0; - } - srsran_assert(dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 or dci_type == dci_dl_rnti_config_type::c_rnti_f1_0, - "Only DCI 1_0 with TC-RNTI or C-RNTI is supported for SRB1 scheduling"); + dci_dl_rnti_config_type dci_type = get_dci_type(u, *h_dl); pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 3e99678f4e..90355c0ddf 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -15,7 +15,6 @@ #include "../support/slot_event_list.h" #include "ue_repository.h" #include "srsran/scheduler/scheduler_configurator.h" -#include #include namespace srsran { diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index a6a0eab4bb..1791e0d56c 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -11,8 +11,11 @@ #include "tests/integrationtests/du_high/test_utils/du_high_env_simulator.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/unittests/f1ap/du/f1ap_du_test_helpers.h" +#include "srsran/support/test_utils.h" #include +TEST_RGEN_SET_SEED(3); + using namespace srsran; using namespace srs_du; From 7fc4290e96a4a6ee3d1c7bf930bfba84842dbb74 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Aug 2024 00:10:58 +0200 Subject: [PATCH 318/407] sched: optimize computation of nof UEs to schedule per slot --- lib/scheduler/policy/scheduler_time_rr.cpp | 94 +++++++++++++++------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 59a54f78d6..8ec6975dda 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -14,11 +14,15 @@ using namespace srsran; +namespace { + struct scheduler_alloc_limits { unsigned max_nof_ues_with_new_tx; unsigned nof_ues_to_be_scheduled_per_slot; }; +} // namespace + // [Implementation-defined] The following lookup of nof. UEs to be scheduled per slot is based on simple heuristic // and to ensure multiple UEs are scheduled per slot rather than single UE hogging all the resource in a slot under // full buffer scenario. @@ -30,6 +34,28 @@ static const std::vector scheduler_alloc_limits_lookup = {MAX_NOF_DU_UES, 8}, }; +static unsigned get_max_ues_to_be_sched(const slice_ue_repository& ues, bool is_dl) +{ + unsigned nof_ue_with_new_tx = 0; + unsigned lookup_idx = 0; + for (const auto& u : ues) { + if ((is_dl and u.has_pending_dl_newtx_bytes()) or (not is_dl and u.pending_ul_newtx_bytes() > 0)) { + // count UEs with pending data. + ++nof_ue_with_new_tx; + + // check if we surpassed a limit of the lookup table. + if (nof_ue_with_new_tx > scheduler_alloc_limits_lookup[lookup_idx].max_nof_ues_with_new_tx) { + lookup_idx++; + if (lookup_idx == scheduler_alloc_limits_lookup.size() - 1) { + // no need to continue the search as we reached the maximum position of the lookup. + break; + } + } + } + } + return scheduler_alloc_limits_lookup[lookup_idx].nof_ues_to_be_scheduled_per_slot; +} + /// \brief Computes maximum nof. RBs to allocate per UE per slot for newTx. /// \param[in] ues Map of UEs belonging to a slice. /// \param[in] is_dl Flag indicating whether the computation is DL or UL. @@ -47,13 +73,13 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& return 0; } - unsigned nof_ue_with_new_tx = 0; - unsigned nof_ues_to_be_scheduled_per_slot = 0; + unsigned nof_ues_to_be_scheduled_per_slot = get_max_ues_to_be_sched(ues, is_dl); - for (const auto& u : ues) { - if ((is_dl and u.has_pending_dl_newtx_bytes()) or (not is_dl and u.pending_ul_newtx_bytes() > 0)) { - ++nof_ue_with_new_tx; - } + // > 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); + } else { + nof_ues_to_be_scheduled_per_slot = std::min(expert_cfg.max_puschs_per_slot, nof_ues_to_be_scheduled_per_slot); } // NOTE: All UEs use the same dedicated SearchSpace configuration. @@ -75,21 +101,6 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& bwp_crb_limits = ss_info->ul_crb_lims; } - // > Fetch nof. UEs to be scheduled per slot based on the lookup. - for (const auto& lims : scheduler_alloc_limits_lookup) { - if (nof_ue_with_new_tx <= lims.max_nof_ues_with_new_tx) { - nof_ues_to_be_scheduled_per_slot = lims.nof_ues_to_be_scheduled_per_slot; - break; - } - } - - // > 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); - } else { - nof_ues_to_be_scheduled_per_slot = std::min(expert_cfg.max_puschs_per_slot, nof_ues_to_be_scheduled_per_slot); - } - // > Compute maximum nof. PDCCH candidates allowed for each direction. // [Implementation-defined] // - Assume aggregation level 2 while computing nof. candidates that can be fit in CORESET. @@ -225,13 +236,13 @@ static static_vector get_ue_ul_harq_candi /// \param[in] ue_db Map of UEs belonging to a slice. /// \param[in] next_ue_index UE index with the highest priority to be allocated. /// \param[in] alloc_ue callable with signature "bool(ue&)" that returns true if UE allocation was successful. -/// \return Index of next UE to allocate. +/// \return Index of next UE to allocate and the allocation status. template -du_ue_index_t +static std::pair round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue) { if (ue_db.empty()) { - return next_ue_index; + return std::make_pair(next_ue_index, alloc_status::skip_slot); } auto it = ue_db.lower_bound(next_ue_index); bool first_alloc = true; @@ -244,7 +255,7 @@ round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, const alloc_result result = alloc_ue(u); if (result.status == alloc_status::skip_slot) { // Grid allocator directed policy to stop allocations for this slot. - break; + return std::make_pair(next_ue_index, result.status); } if (result.status == alloc_status::success and first_alloc) { @@ -256,7 +267,7 @@ round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, first_alloc = false; } } - return next_ue_index; + return std::make_pair(next_ue_index, alloc_status::success); } /// Allocate UE PDSCH grant. @@ -389,7 +400,11 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, auto retx_ue_function = [this, &res_grid, &pdsch_alloc, slice_id](const slice_ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, true, logger, slice_id); }; - next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, retx_ue_function); + auto result = round_robin_apply(ues, next_dl_ue_index, retx_ue_function); + next_dl_ue_index = result.first; + if (result.second == alloc_status::skip_slot) { + return; + } const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg, max_rbs); @@ -399,7 +414,11 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, false, logger, slice_id, dl_new_tx_max_nof_rbs_per_ue_per_slot); }; - next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); + result = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); + next_dl_ue_index = result.first; + if (result.second == alloc_status::skip_slot) { + return; + } } } @@ -416,19 +435,28 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, return; } + // Prioritize UEs with pending SRs. const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. auto sr_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { return alloc_ul_ue(u, pusch_alloc, false, true, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; - next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); + auto result = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); + next_ul_ue_index = result.first; + if (result.second == alloc_status::skip_slot) { + return; + } // Second, schedule UEs with re-transmissions. auto data_retx_ue_function = [this, &pusch_alloc, slice_id](const slice_ue& u) { return alloc_ul_ue(u, pusch_alloc, true, false, logger, slice_id); }; - next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); + result = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); + next_ul_ue_index = result.first; + if (result.second == alloc_status::skip_slot) { + return; + } // Then, schedule UEs with new transmissions. if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { @@ -436,6 +464,10 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { return alloc_ul_ue(u, pusch_alloc, false, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; - next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); + result = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); + next_ul_ue_index = result.first; + if (result.second == alloc_status::skip_slot) { + return; + } } } From dd6e45c6defcde46bbcc44a3f334bac3f18eef74 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Aug 2024 11:17:45 +0200 Subject: [PATCH 319/407] du_high: in du_high_benchmark log metrics of sched latency --- .../benchmarks/du_high/du_high_benchmark.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index cabaaf5d08..4011be55e0 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -216,6 +216,11 @@ static void print_args(const bench_params& params) class dummy_metrics_handler : public scheduler_metrics_notifier { public: + dummy_metrics_handler() : + logger(srslog::fetch_basic_logger("METRICS")), pending_metrics(logger.info.enabled() ? 128 : 1) + { + } + void report_metrics(const scheduler_cell_metrics& metrics) override { unsigned sum_dl_bs = 0; @@ -223,11 +228,37 @@ class dummy_metrics_handler : public scheduler_metrics_notifier sum_dl_bs += ue.dl_bs; } tot_dl_bs.store(sum_dl_bs, std::memory_order_relaxed); + + if (logger.info.enabled()) { + auto metrics_copy = metrics; + pending_metrics.try_push(std::move(metrics_copy)); + } + } + + void log() + { + if (not logger.info.enabled()) { + return; + } + scheduler_cell_metrics metrics; + while (pending_metrics.try_pop(metrics)) { + fmt::format_to(fmtbuf, "Latency=[{}]", fmt::join(metrics.latency_histogram, ", ")); + logger.info("cell metrics: {}\n", to_c_str(fmtbuf)); + fmtbuf.clear(); + } } + srslog::basic_logger& logger; + // This metric is used by benchmark to determine whether to push more traffic to DU F1-U. Therefore, it needs to be // protected. std::atomic tot_dl_bs{0}; + + concurrent_queue + pending_metrics; + fmt::memory_buffer fmtbuf; }; /// \brief Simulator of the CU-CP from the perspective of the DU. This class should reply to the F1AP messages @@ -741,6 +772,9 @@ class du_high_bench // Process PHY metrics. sim_phy.process_results(); + // Run metrics logger. + metrics_handler.log(); + // Advance slot. ++next_sl_tx; } @@ -1264,6 +1298,7 @@ int main(int argc, char** argv) srslog::fetch_basic_logger("DU-F1-U").set_level(test_log_level); srslog::fetch_basic_logger("UE-MNG").set_level(test_log_level); srslog::fetch_basic_logger("DU-MNG").set_level(test_log_level); + srslog::fetch_basic_logger("METRICS").set_level(srslog::basic_levels::warning); srslog::init(); std::string tracing_filename = ""; From 755d5537e742fc930201d4ae6d8bc9b040eeb893 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 22 Aug 2024 10:21:21 +0200 Subject: [PATCH 320/407] ci: add extra kubeconfig --- .gitlab/ci/e2e.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index de7c91aa20..245283b28b 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -77,12 +77,15 @@ load retina variables: .prepare_test: variables: KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" before_script: - | - eval K_PATH="\$$KUBECONFIG_VAR_NAME" export FORCE_COLOR=1 + eval K_PATH="\$$KUBECONFIG_VAR_NAME" export KUBECONFIG=$K_PATH + eval K_PATH_EXTRA="\$$KUBECONFIG_VAR_NAME_EXTRA" + export KUBECONFIG_EXTRA=$K_PATH_EXTRA e2e request and config validation: stage: static extends: @@ -123,6 +126,7 @@ e2e request and config validation: KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "20G" KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "20G" KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" GROUP: zmq tags: - "${RETINA_TAG}" @@ -586,6 +590,7 @@ android b200: MARKERS: "android" E2E_LOG_LEVEL: "warning" KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" needs: - job: "basic relwithdeb" artifacts: true @@ -600,6 +605,7 @@ android x300: MARKERS: "android_hp" E2E_LOG_LEVEL: "info" KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" needs: - job: "basic relwithdeb" artifacts: true @@ -619,6 +625,7 @@ viavi: MARKERS: "viavi" E2E_LOG_LEVEL: "warning" KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.rlc_rb_type=srb" RETINA_LAUNCHER_ARGS: "--retina-pod-timeout 900" needs: @@ -647,6 +654,7 @@ viavi-debug: MARKERS: "viavi_debug" E2E_LOG_LEVEL: "warning" KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.rlc_rb_type=srb" RETINA_LAUNCHER_ARGS: "--retina-pod-timeout 900" allow_failure: true From b7f6a4f6998a14a2b4b6f8bb2a469aa0208333ce Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 21 Aug 2024 15:43:22 +0200 Subject: [PATCH 321/407] sched,e2sm_kpm: remove nof_prbs from scheduler ue metrics and compute prb metrics correctly --- include/srsran/scheduler/scheduler_metrics.h | 3 +- .../e2sm_kpm_du_meas_provider_impl.cpp | 31 ++++++++++++++----- .../e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h | 1 + .../logging/scheduler_metric_handler.cpp | 7 +++-- .../logging/scheduler_metrics_handler.h | 3 ++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/include/srsran/scheduler/scheduler_metrics.h b/include/srsran/scheduler/scheduler_metrics.h index 5ffa5fe473..11290e7ac9 100644 --- a/include/srsran/scheduler/scheduler_metrics.h +++ b/include/srsran/scheduler/scheduler_metrics.h @@ -23,7 +23,6 @@ namespace srsran { /// \brief Snapshot of the metrics for a UE. struct scheduler_ue_metrics { pci_t pci; - unsigned nof_prbs; rnti_t rnti; sch_mcs_index dl_mcs; double dl_prbs_used; @@ -55,6 +54,8 @@ struct scheduler_cell_metrics { constexpr static unsigned latency_hist_bins = 10; /// Distance between histogram bins. constexpr static unsigned nof_usec_per_bin = 50; + /// Number of cell PRBs. + unsigned nof_prbs = 0; unsigned nof_error_indications = 0; std::chrono::microseconds average_decision_latency{0}; diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index cd72d95d44..e5159d713e 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -122,6 +122,7 @@ bool e2sm_kpm_du_meas_provider_impl::check_e2sm_kpm_metrics_definitions(span 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: RRU.PrbAvailDl supports only NO_LABEL label."); return meas_collected; } + int total_dl_prbs_used = std::accumulate( + last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { + return sum + metric.dl_prbs_used; + }); + meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (ue_metrics.nof_prbs - (int)ue_metrics.dl_prbs_used); + meas_record_item.set_integer() = (nof_cell_prbs - total_dl_prbs_used); items.push_back(meas_record_item); meas_collected = true; @@ -333,14 +338,18 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_avail_ul(const asn1::e2sm::label_in if (last_ue_metrics.size() == 0) { return meas_collected; } - scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: RRU.PrbAvailUl supports only NO_LABEL label."); return meas_collected; } + int total_ul_prbs_used = std::accumulate( + last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { + return sum + metric.ul_prbs_used; + }); + meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (ue_metrics.nof_prbs - (int)ue_metrics.ul_prbs_used); + meas_record_item.set_integer() = (nof_cell_prbs - total_ul_prbs_used); items.push_back(meas_record_item); meas_collected = true; @@ -356,14 +365,17 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_dl(const asn1::e2sm::label if (last_ue_metrics.size() == 0) { return meas_collected; } - scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: RRU.PrbTotDl supports only NO_LABEL label."); return meas_collected; } + int total_dl_prbs_used = std::accumulate( + last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { + return sum + metric.dl_prbs_used; + }); meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (double)ue_metrics.dl_prbs_used * 100 / ue_metrics.nof_prbs; + meas_record_item.set_integer() = (double)total_dl_prbs_used * 100 / nof_cell_prbs; items.push_back(meas_record_item); meas_collected = true; @@ -379,14 +391,17 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_ul(const asn1::e2sm::label if (last_ue_metrics.size() == 0) { return meas_collected; } - scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: RRU.PrbTotUl supports only NO_LABEL label."); return meas_collected; } + int total_ul_prbs_used = std::accumulate( + last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { + return sum + metric.ul_prbs_used; + }); meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (double)ue_metrics.ul_prbs_used * 100 / ue_metrics.nof_prbs; + meas_record_item.set_integer() = (double)total_ul_prbs_used * 100 / nof_cell_prbs; items.push_back(meas_record_item); meas_collected = true; diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h index f1518aef16..63c216e603 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h @@ -102,6 +102,7 @@ class e2sm_kpm_du_meas_provider_impl : public e2sm_kpm_meas_provider, public e2_ srslog::basic_logger& logger; srs_du::f1ap_ue_id_translator& f1ap_ue_id_provider; + unsigned nof_cell_prbs; std::vector last_ue_metrics; std::map> ue_aggr_rlc_metrics; const size_t max_rlc_metrics = 30; diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 26f32de14a..39a4b8f638 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -31,6 +31,7 @@ void cell_metrics_handler::handle_ue_creation(du_ue_index_t ue_index, 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; } void cell_metrics_handler::handle_ue_deletion(du_ue_index_t ue_index) @@ -196,6 +197,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; // Reset cell-wide metric counters. error_indication_counter = 0; @@ -293,9 +295,8 @@ cell_metrics_handler::ue_metric_context::compute_report(std::chrono::millisecond ret.dl_mcs = sch_mcs_index{mcs}; mcs = data.nof_puschs > 0 ? std::roundf(static_cast(data.ul_mcs) / data.nof_puschs) : 0; ret.ul_mcs = sch_mcs_index{mcs}; - ret.nof_prbs = nof_prbs; - ret.dl_prbs_used = data.nof_dl_cws > 0 ? static_cast(data.dl_prbs_used / data.nof_dl_cws) : 0; - ret.ul_prbs_used = data.nof_puschs > 0 ? static_cast(data.ul_prbs_used / data.nof_puschs) : 0; + ret.dl_prbs_used = static_cast(data.dl_prbs_used / (metric_report_period.count())); + ret.ul_prbs_used = static_cast(data.ul_prbs_used / (metric_report_period.count())); ret.dl_brate_kbps = static_cast(data.sum_dl_tb_bytes * 8U) / metric_report_period.count(); ret.ul_brate_kbps = static_cast(data.sum_ul_tb_bytes * 8U) / metric_report_period.count(); ret.dl_nof_ok = data.count_uci_harq_acks; diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index 8e622fd4e3..374ef6b192 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -85,6 +85,9 @@ 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; + /// Counter of number of slots elapsed since the last report. unsigned slot_counter = 0; From c9605491cdb7583cdd10d7c5aa58e7328c7123d1 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 21 Aug 2024 16:15:00 +0200 Subject: [PATCH 322/407] e2sm_kpm: compute prb metrics for ues --- .../e2sm_kpm_du_meas_provider_impl.cpp | 75 +++++++++++++------ 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index e5159d713e..022fe29831 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -321,10 +321,12 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_avail_dl(const asn1::e2sm::label_in return sum + metric.dl_prbs_used; }); - meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (nof_cell_prbs - total_dl_prbs_used); - items.push_back(meas_record_item); - meas_collected = true; + for (size_t i = 0; i < std::max(ues.size(), size_t(1)); ++i) { + meas_record_item_c meas_record_item; + meas_record_item.set_integer() = (nof_cell_prbs - total_dl_prbs_used); + items.push_back(meas_record_item); + meas_collected = true; + } return meas_collected; } @@ -348,10 +350,12 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_avail_ul(const asn1::e2sm::label_in return sum + metric.ul_prbs_used; }); - meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (nof_cell_prbs - total_ul_prbs_used); - items.push_back(meas_record_item); - meas_collected = true; + for (size_t i = 0; i < std::max(ues.size(), size_t(1)); ++i) { + meas_record_item_c meas_record_item; + meas_record_item.set_integer() = (nof_cell_prbs - total_ul_prbs_used); + items.push_back(meas_record_item); + meas_collected = true; + } return meas_collected; } @@ -370,14 +374,26 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_dl(const asn1::e2sm::label logger.debug("Metric: RRU.PrbTotDl supports only NO_LABEL label."); return meas_collected; } - int total_dl_prbs_used = std::accumulate( - last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { - return sum + metric.dl_prbs_used; - }); - meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (double)total_dl_prbs_used * 100 / nof_cell_prbs; - items.push_back(meas_record_item); - meas_collected = true; + + if (ues.size() == 0) { + int total_dl_prbs_used = std::accumulate( + last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { + return sum + metric.dl_prbs_used; + }); + meas_record_item_c meas_record_item; + meas_record_item.set_integer() = (double)total_dl_prbs_used * 100 / nof_cell_prbs; + items.push_back(meas_record_item); + meas_collected = true; + } + + for (auto& ue : ues) { + gnb_cu_ue_f1ap_id_t gnb_cu_ue_f1ap_id = int_to_gnb_cu_ue_f1ap_id(ue.gnb_du_ue_id().gnb_cu_ue_f1ap_id); + uint32_t ue_idx = f1ap_ue_id_provider.get_ue_index(gnb_cu_ue_f1ap_id); + meas_record_item_c meas_record_item; + meas_record_item.set_integer() = (double)last_ue_metrics[ue_idx].dl_prbs_used * 100 / nof_cell_prbs; + items.push_back(meas_record_item); + meas_collected = true; + } return meas_collected; } @@ -396,14 +412,25 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_ul(const asn1::e2sm::label logger.debug("Metric: RRU.PrbTotUl supports only NO_LABEL label."); return meas_collected; } - int total_ul_prbs_used = std::accumulate( - last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { - return sum + metric.ul_prbs_used; - }); - meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (double)total_ul_prbs_used * 100 / nof_cell_prbs; - items.push_back(meas_record_item); - meas_collected = true; + if (ues.size() == 0) { + int total_ul_prbs_used = std::accumulate( + last_ue_metrics.begin(), last_ue_metrics.end(), 0, [](size_t sum, const scheduler_ue_metrics& metric) { + return sum + metric.ul_prbs_used; + }); + meas_record_item_c meas_record_item; + meas_record_item.set_integer() = (double)total_ul_prbs_used * 100 / nof_cell_prbs; + items.push_back(meas_record_item); + meas_collected = true; + } + + for (auto& ue : ues) { + gnb_cu_ue_f1ap_id_t gnb_cu_ue_f1ap_id = int_to_gnb_cu_ue_f1ap_id(ue.gnb_du_ue_id().gnb_cu_ue_f1ap_id); + uint32_t ue_idx = f1ap_ue_id_provider.get_ue_index(gnb_cu_ue_f1ap_id); + meas_record_item_c meas_record_item; + meas_record_item.set_integer() = (double)last_ue_metrics[ue_idx].ul_prbs_used * 100 / nof_cell_prbs; + items.push_back(meas_record_item); + meas_collected = true; + } return meas_collected; } From d3871a766c5138ba77a7f9e91c6d260ef1189db6 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 21 Aug 2024 15:47:27 +0200 Subject: [PATCH 323/407] e2sm_kpm: remove RLC metric buffering --- lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp | 7 +++++++ lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h | 4 +++- tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index 022fe29831..32ac243876 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -89,6 +89,13 @@ e2sm_kpm_du_meas_provider_impl::e2sm_kpm_du_meas_provider_impl(srs_du::f1ap_ue_i check_e2sm_kpm_metrics_definitions(get_e2sm_kpm_oran_metrics()); } +e2sm_kpm_du_meas_provider_impl::e2sm_kpm_du_meas_provider_impl(srs_du::f1ap_ue_id_translator& f1ap_ue_id_translator_, + int max_rlc_metrics_) : + e2sm_kpm_du_meas_provider_impl(f1ap_ue_id_translator_) +{ + max_rlc_metrics = max_rlc_metrics_; +} + bool e2sm_kpm_du_meas_provider_impl::check_e2sm_kpm_metrics_definitions(span metric_defs) { std::string metric_name; diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h index 63c216e603..01e722b4e7 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h @@ -30,6 +30,8 @@ class e2sm_kpm_du_meas_provider_impl : public e2sm_kpm_meas_provider, public e2_ // constructor takes logger as argument e2sm_kpm_du_meas_provider_impl(srs_du::f1ap_ue_id_translator& f1ap_ue_id_translator); + e2sm_kpm_du_meas_provider_impl(srs_du::f1ap_ue_id_translator& f1ap_ue_id_translator, int max_rlc_metrics_); + ~e2sm_kpm_du_meas_provider_impl() = default; /// scheduler_ue_metrics_notifier functions. @@ -105,7 +107,7 @@ class e2sm_kpm_du_meas_provider_impl : public e2sm_kpm_meas_provider, public e2_ unsigned nof_cell_prbs; std::vector last_ue_metrics; std::map> ue_aggr_rlc_metrics; - const size_t max_rlc_metrics = 30; + size_t max_rlc_metrics = 1; std::map supported_metrics; }; diff --git a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp index 4c56323aa2..a2437ee7fd 100644 --- a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp @@ -70,7 +70,7 @@ class e2sm_kpm_meas_provider_test : public ::testing::Test du_metrics = std::make_unique(); f1ap_ue_id_mapper = std::make_unique(); - du_meas_provider = std::make_unique(*f1ap_ue_id_mapper); + du_meas_provider = std::make_unique(*f1ap_ue_id_mapper, 30); e2sm_packer = std::make_unique(*du_meas_provider); e2sm_iface = std::make_unique(test_logger, *e2sm_packer, *du_meas_provider); gw = std::make_unique(); From d71604431457da396607ef30adf79d20ae51011c Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 21 Aug 2024 17:51:54 +0200 Subject: [PATCH 324/407] e2sm_kpm: when Report Style 1 and no meas data available, fill with zeros --- .../e2sm_kpm_du_meas_provider_impl.cpp | 92 ++++++++++++++----- .../e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h | 3 + 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index 32ac243876..5a86fe3389 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -250,14 +250,38 @@ bool e2sm_kpm_du_meas_provider_impl::get_meas_data(const asn1::e2sm::meas_type_c return (this->*metric_meas_getter_func)(label_info_list, ues, cell_global_id, items); } +bool e2sm_kpm_du_meas_provider_impl::handle_no_meas_data_available( + const std::vector& ues, + std::vector& items, + asn1::e2sm::meas_record_item_c::types::options value_type) +{ + if (ues.empty()) { + // Fill with zero if E2 Node Measurement (Report Style 1) + meas_record_item_c meas_record_item; + if (value_type == asn1::e2sm::meas_record_item_c::types::options::integer) { + meas_record_item.set_integer() = 0; + } else if (value_type == asn1::e2sm::meas_record_item_c::types::options::real) { + meas_record_item.set_real(); + meas_record_item.real().value = 0; + } else if (value_type == asn1::e2sm::meas_record_item_c::types::options::not_satisfied) { + meas_record_item.set_not_satisfied(); + } else { + meas_record_item.set_no_value(); + } + items.push_back(meas_record_item); + return true; + } + return false; +} + bool e2sm_kpm_du_meas_provider_impl::get_cqi(const asn1::e2sm::label_info_list_l label_info_list, const std::vector& ues, const std::optional cell_global_id, std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; @@ -277,8 +301,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_rsrp(const asn1::e2sm::label_info_list_ std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; @@ -296,8 +320,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_rsrq(const asn1::e2sm::label_info_list_ std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; @@ -315,8 +339,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_avail_dl(const asn1::e2sm::label_in std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -344,8 +368,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_avail_ul(const asn1::e2sm::label_in std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -373,8 +397,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_dl(const asn1::e2sm::label std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -411,8 +435,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_ul(const asn1::e2sm::label std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -447,8 +471,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_delay_ul(const asn1::e2sm::label_info_l std::vector& items) { bool meas_collected = false; - if (last_ue_metrics.size() == 0) { - return meas_collected; + if (last_ue_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); } scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; if ((label_info_list.size() > 1 or @@ -475,6 +499,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_mean_throughput(const asn1::e2sm std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: DRB.UEThpDl supports only NO_LABEL label."); @@ -482,9 +509,6 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_mean_throughput(const asn1::e2sm } double seconds = 1; std::map ue_throughput; - if (ue_aggr_rlc_metrics.size() == 0) { - return meas_collected; - } for (auto& ue : ue_aggr_rlc_metrics) { size_t num_pdu_bytes_with_segmentation; switch (ue.second.front().tx.tx_low.mode) { @@ -550,16 +574,17 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_mean_throughput(const asn1::e2sm std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: DRB.UEThpUl supports only NO_LABEL label."); return meas_collected; } + double seconds = 1; std::map ue_throughput; - if (ue_aggr_rlc_metrics.size() == 0) { - return meas_collected; - } for (auto& ue : ue_aggr_rlc_metrics) { auto num_pdu_bytes = std::accumulate(ue.second.begin(), ue.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { @@ -604,7 +629,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_success_rate(const asn1::e2sm::l std::vector& items) { bool meas_collected = false; - + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: DRB.PacketSuccessRateUlgNBUu supports only NO_LABEL label."); @@ -679,6 +706,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_packet_drop_rate_dl( std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -757,6 +787,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_sdu_transmitted_volume_dl( std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -813,6 +846,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_sdu_transmitted_volume_ul( std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -868,11 +904,16 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); + } + if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: DRB.RlcSduDelayDl supports only NO_LABEL label."); return meas_collected; } + if (ues.size() == 0) { meas_record_item_c meas_record_item; float av_ue_sdu_latency_us = 0; @@ -938,11 +979,16 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm std::vector& items) { bool meas_collected = false; + if (ue_aggr_rlc_metrics.empty()) { + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); + } + if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: DRB.RlcDelayUl supports only NO_LABEL label."); return meas_collected; } + if (ues.size() == 0) { meas_record_item_c meas_record_item; float av_ue_sdu_latency_us = 0; diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h index 01e722b4e7..94f088d8f8 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h @@ -83,6 +83,9 @@ class e2sm_kpm_du_meas_provider_impl : public e2sm_kpm_meas_provider, public e2_ // Helper functions. float bytes_to_kbits(float value); + bool handle_no_meas_data_available(const std::vector& ues, + std::vector& items, + asn1::e2sm::meas_record_item_c::types::options value_type); // Measurement getter functions. metric_meas_getter_func_t get_cqi; From 9e0ef9e471893909019e238255fdf0057c90febb Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 23 Aug 2024 13:50:24 +0200 Subject: [PATCH 325/407] sched: don't use ded_cfg in fallback sched Signed-off-by: Carlo Galiotto --- .../ue_scheduling/ue_fallback_scheduler.cpp | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 74c7a98df6..6ce2019c08 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -694,8 +694,21 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, } // Allocate PUCCH resources. - auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch( - u, res_alloc, pucch_alloc, *pdcch, dci_1_0_k1_values, pdsch_alloc.slot, most_recent_ack_slot, is_retx); + // NOTEs: + // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) + // could have a complete configuration; if so, the UCI scheduler can start allocating SRs and CSIs in advance, as the + // scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs. + // - If the UE object in the scheduler doesn't have a complete configuration, don't use the PUCCH ded. resources. + const bool use_common_and_ded_res = is_retx and u.ue_cfg_dedicated()->is_ue_cfg_complete(); + auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common_and_ded_res); + if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. @@ -887,8 +900,24 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 } // Allocate PUCCH resources. - auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch( - u, res_alloc, pucch_alloc, *pdcch, dci_1_0_k1_values, pdsch_alloc.slot, most_recent_ack_slot, is_retx); + // NOTEs: + // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) + // could have a complete configuration; if so, (i) the UCI scheduler can start allocating SRs and CSIs in advance, as + // the scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs; (ii) if the actual UE has + // received the RRCSetup (with configuration) but the GNB doesn't receive an ACK = 1, the UE can use the PUCCH + // dedicated resource to ack the RRCSetup retx (as per TS 38.213, Section 9.2.1, "If a UE has dedicated PUCCH resource + // configuration, the UE is provided by higher layers with one or more PUCCH resources [...]"). + // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), + // don't use the PUCCH ded. resources. + const bool use_common_and_ded_res = is_retx and u.ue_cfg_dedicated()->is_ue_cfg_complete(); + auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common_and_ded_res); if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. @@ -1092,7 +1121,13 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 } // Allocate PUCCH resources. - const bool alloc_common_and_ded_pucch = dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0 or is_retx; + // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) + // could have a complete configuration; if so, the UCI scheduler can start allocating SRs and CSIs in advance, as the + // scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs. + // - If the UE object in the scheduler doesn't have a complete configuration (which is a requirement for any PUCCH + // function that handles PUCCH dedicated resource), don't use the PUCCH dedicated resources. + const bool use_common_and_ded_res = + u.ue_cfg_dedicated()->is_ue_cfg_complete() and (dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0 or is_retx); auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, res_alloc, pucch_alloc, @@ -1100,7 +1135,7 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 dci_1_0_k1_values, pdsch_alloc.slot, most_recent_ack_slot, - alloc_common_and_ded_pucch); + use_common_and_ded_res); if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { logger.debug("rnti={}: Failed to allocate PDSCH for SRB1 for slot={}. Cause: No space in PUCCH", From 72ecf572da9b82a6f744ff5bcd8243cd4feba8c4 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 23 Aug 2024 14:52:39 +0200 Subject: [PATCH 326/407] sched: rename static fnc in ue_fallback sched Signed-off-by: Carlo Galiotto --- .../ue_scheduling/ue_fallback_scheduler.cpp | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 6ce2019c08..382c314873 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -542,14 +542,14 @@ static dci_dl_rnti_config_type get_dci_type(const ue& u, const dl_harq_process& // Helper to allocate common (and optionally dedicated) PUCCH. static std::pair, std::optional> -allocate_common_pucch(ue& u, - cell_resource_allocator& res_alloc, - pucch_allocator& pucch_alloc, - const pdcch_dl_information& pdcch_info, - span k1_values, - slot_point pdsch_slot, - slot_point min_ack_slot, - bool common_and_ded_alloc) +allocate_ue_fallback_pucch(ue& u, + cell_resource_allocator& res_alloc, + pucch_allocator& pucch_alloc, + const pdcch_dl_information& pdcch_info, + span k1_values, + slot_point pdsch_slot, + slot_point min_ack_slot, + bool common_and_ded_alloc) { const unsigned pdsch_delay = pdsch_slot - res_alloc.slot_tx(); @@ -700,14 +700,14 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, // scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs. // - If the UE object in the scheduler doesn't have a complete configuration, don't use the PUCCH ded. resources. const bool use_common_and_ded_res = is_retx and u.ue_cfg_dedicated()->is_ue_cfg_complete(); - auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, - res_alloc, - pucch_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common_and_ded_res); + auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common_and_ded_res); if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { @@ -910,14 +910,14 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), // don't use the PUCCH ded. resources. const bool use_common_and_ded_res = is_retx and u.ue_cfg_dedicated()->is_ue_cfg_complete(); - auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, - res_alloc, - pucch_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common_and_ded_res); + auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common_and_ded_res); if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. @@ -1128,14 +1128,14 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 // function that handles PUCCH dedicated resource), don't use the PUCCH dedicated resources. const bool use_common_and_ded_res = u.ue_cfg_dedicated()->is_ue_cfg_complete() and (dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0 or is_retx); - auto [pucch_res_indicator, chosen_k1] = allocate_common_pucch(u, - res_alloc, - pucch_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common_and_ded_res); + auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common_and_ded_res); if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { logger.debug("rnti={}: Failed to allocate PDSCH for SRB1 for slot={}. Cause: No space in PUCCH", From 5d06f4efb7cbee675039b2a0bfa67f51a69b4e14 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 20 Aug 2024 16:05:59 +0200 Subject: [PATCH 327/407] cu_cp,ngap: store serving plmn from guami in ue context --- lib/ngap/ngap_impl.cpp | 7 +++++-- .../procedures/ngap_handover_preparation_procedure.cpp | 8 ++++---- lib/ngap/procedures/ngap_handover_preparation_procedure.h | 4 ++-- lib/ngap/ue_context/ngap_ue_context.h | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 72f6690f69..6278d63a60 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -442,6 +442,9 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont return; } + // Store serving PLMN + ue_ctxt.serving_guami = init_ctxt_setup_req.guami; + // Store UE Aggregate Maximum Bitrate if (init_ctxt_setup_req.ue_aggr_max_bit_rate.has_value()) { ue_ctxt.aggregate_maximum_bit_rate_dl = init_ctxt_setup_req.ue_aggr_max_bit_rate.value().ue_aggr_max_bit_rate_dl; @@ -504,7 +507,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ // Convert to common type cu_cp_pdu_session_resource_setup_request msg; msg.ue_index = ue_ctxt.ue_ids.ue_index; - msg.serving_plmn = context.plmn; + msg.serving_plmn = ue_ctxt.serving_guami.plmn; if (!fill_cu_cp_pdu_session_resource_setup_request(msg, request->pdu_session_res_setup_list_su_req)) { ue_ctxt.logger.log_warning("Conversion of PduSessionResourceSetupRequest failed"); send_error_indication(*tx_pdu_notifier, logger, ue_ctxt.ue_ids.ran_ue_id, ue_ctxt.ue_ids.amf_ue_id, {}); @@ -943,7 +946,7 @@ ngap_impl::handle_handover_preparation_request(const ngap_handover_preparation_r ue_ctxt.logger.log_info("Starting HO preparation"); return launch_async(msg, - context, + ue_ctxt.serving_guami.plmn, ue_ctxt.ue_ids, *tx_pdu_notifier, ue->get_rrc_ue_control_notifier(), diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp index f8ba07236d..5d9f6699ae 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp @@ -21,7 +21,7 @@ constexpr std::chrono::milliseconds ng_cancel_ack_timeout{5000}; ngap_handover_preparation_procedure::ngap_handover_preparation_procedure( const ngap_handover_preparation_request& request_, - const ngap_context_t& context_, + const plmn_identity& serving_plmn_, const ngap_ue_ids& ue_ids_, ngap_message_notifier& amf_notifier_, ngap_rrc_ue_control_notifier& rrc_ue_notifier_, @@ -30,7 +30,7 @@ ngap_handover_preparation_procedure::ngap_handover_preparation_procedure( timer_factory timers, ngap_ue_logger& logger_) : request(request_), - context(context_), + serving_plmn(serving_plmn_), ue_ids(ue_ids_), amf_notifier(amf_notifier_), rrc_ue_notifier(rrc_ue_notifier_), @@ -160,7 +160,7 @@ void ngap_handover_preparation_procedure::fill_asn1_target_ran_node_id(target_id auto& target_node = target_id.set_target_ran_node_id(); target_node.global_ran_node_id.set(global_ran_node_id_c::types::global_gnb_id); auto& global_gnb = target_node.global_ran_node_id.global_gnb_id(); - global_gnb.plmn_id = context.plmn.to_bytes(); + global_gnb.plmn_id = serving_plmn.to_bytes(); global_gnb.gnb_id.set_gnb_id(); global_gnb.gnb_id.gnb_id().from_number(request.gnb_id.id, request.gnb_id.bit_length); } @@ -202,7 +202,7 @@ byte_buffer ngap_handover_preparation_procedure::fill_asn1_source_to_target_tran } nr_cgi_s& target_nr_cgi = transparent_container.target_cell_id.set_nr_cgi(); - target_nr_cgi.plmn_id = context.plmn.to_bytes(); + target_nr_cgi.plmn_id = serving_plmn.to_bytes(); target_nr_cgi.nr_cell_id.from_number(request.nci.value()); last_visited_cell_item_s last_visited_cell_item; diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.h b/lib/ngap/procedures/ngap_handover_preparation_procedure.h index 039c30493e..15d57651c4 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.h +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.h @@ -24,7 +24,7 @@ class ngap_handover_preparation_procedure { public: ngap_handover_preparation_procedure(const ngap_handover_preparation_request& req_, - const ngap_context_t& context_, + const plmn_identity& serving_plmn_, const ngap_ue_ids& ue_ids_, ngap_message_notifier& amf_notifier_, ngap_rrc_ue_control_notifier& rrc_ue_notifier_, @@ -39,7 +39,7 @@ class ngap_handover_preparation_procedure private: const ngap_handover_preparation_request request; - const ngap_context_t context; + const plmn_identity& serving_plmn; const ngap_ue_ids ue_ids; ngap_message_notifier& amf_notifier; ngap_rrc_ue_control_notifier& rrc_ue_notifier; diff --git a/lib/ngap/ue_context/ngap_ue_context.h b/lib/ngap/ue_context/ngap_ue_context.h index 27bed286d3..e520787c69 100644 --- a/lib/ngap/ue_context/ngap_ue_context.h +++ b/lib/ngap/ue_context/ngap_ue_context.h @@ -27,7 +27,8 @@ struct ngap_ue_ids { struct ngap_ue_context { ngap_ue_ids ue_ids; - ngap_cu_cp_ue_notifier* ue = nullptr; + ngap_cu_cp_ue_notifier* ue = nullptr; + guami_t serving_guami; uint64_t aggregate_maximum_bit_rate_dl = 0; unique_timer pdu_session_setup_timer = {}; bool release_requested = false; From 85f0fe764204717bb6a23c2315cfa41a2a9d0ebf Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 20 Aug 2024 17:09:39 +0200 Subject: [PATCH 328/407] cu_cp: add support for multiple PLMNs --- apps/cu/cu.cpp | 5 +- apps/gnb/gnb.cpp | 11 +- apps/gnb/gnb_appconfig_validators.cpp | 17 ++- apps/units/cu_cp/cu_cp_config_translators.cpp | 17 ++- apps/units/cu_cp/cu_cp_unit_config.h | 19 ++- .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 130 +++++++++--------- .../cu_cp/cu_cp_unit_config_cli11_schema.h | 8 +- .../cu_cp/cu_cp_unit_config_validator.cpp | 6 - .../cu_cp/cu_cp_unit_config_yaml_writer.cpp | 45 ++++-- configs/tracking_areas.yml | 13 ++ include/srsran/cu_cp/cu_cp_configuration.h | 17 ++- .../cu_cp/cu_cp_configuration_helpers.h | 14 +- include/srsran/ngap/ngap_configuration.h | 10 +- .../srsran/ngap/ngap_configuration_helpers.h | 3 +- lib/cu_cp/cu_cp_impl.cpp | 3 +- .../du_processor/du_configuration_manager.cpp | 14 +- .../du_processor/du_configuration_manager.h | 9 +- .../du_processor/du_processor_repository.cpp | 6 +- .../routines/amf_connection_setup_routine.cpp | 39 +++--- lib/ngap/ngap_context.h | 12 +- lib/ngap/ngap_impl.cpp | 3 +- .../ngap/ngap_integration_test.cpp | 43 +++--- .../du_configuration_manager_test.cpp | 8 +- .../du_processor_test_helpers.cpp | 3 +- tests/unittests/ngap/ngap_test_helpers.cpp | 3 +- 25 files changed, 264 insertions(+), 194 deletions(-) create mode 100644 configs/tracking_areas.yml diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 0361d65209..0ce127c065 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -201,9 +201,8 @@ int main(int argc, char** argv) // Set the callback for the app calling all the autoderivation functions. app.callback([&app, &cu_cp_config]() { // Create the PLMN and TAC list from the cells. - std::vector plmns; - std::vector tacs; - autoderive_cu_cp_parameters_after_parsing(app, cu_cp_config, std::move(plmns), std::move(tacs)); + std::vector supported_tas; + autoderive_cu_cp_parameters_after_parsing(app, cu_cp_config, std::move(supported_tas)); }); // Parse arguments. diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 2658c7a4f4..2b0331d1a5 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -233,12 +233,11 @@ int main(int argc, char** argv) autoderive_slicing_args(du_unit_cfg, cu_cp_config); autoderive_dynamic_du_parameters_after_parsing(app, du_unit_cfg); - // Create the PLMN and TAC list from the cells. - std::vector plmns; - std::vector tacs; + // Create the supported tracking areas list from the cells. + std::vector supported_tas; + supported_tas.reserve(du_unit_cfg.du_high_cfg.config.cells_cfg.size()); for (const auto& cell : du_unit_cfg.du_high_cfg.config.cells_cfg) { - plmns.push_back(cell.cell.plmn); - tacs.push_back(cell.cell.tac); + supported_tas.push_back({cell.cell.tac, cell.cell.plmn, {}}); } // If test mode is enabled, we auto-enable "no_core" option @@ -246,7 +245,7 @@ int main(int argc, char** argv) cu_cp_config.amf_cfg.no_core = true; } - autoderive_cu_cp_parameters_after_parsing(app, cu_cp_config, std::move(plmns), std::move(tacs)); + autoderive_cu_cp_parameters_after_parsing(app, cu_cp_config, std::move(supported_tas)); }); // Parse arguments. diff --git a/apps/gnb/gnb_appconfig_validators.cpp b/apps/gnb/gnb_appconfig_validators.cpp index 794a8254ed..c527ce42d1 100644 --- a/apps/gnb/gnb_appconfig_validators.cpp +++ b/apps/gnb/gnb_appconfig_validators.cpp @@ -46,18 +46,21 @@ bool srsran::validate_appconfig(const gnb_appconfig& config) bool srsran::validate_plmn_and_tacs(const du_high_unit_config& du_hi_cfg, const cu_cp_unit_config& cu_cp_cfg) { + bool ret_val = false; for (const auto& cell : du_hi_cfg.cells_cfg) { - if (std::find(cu_cp_cfg.plmns.cbegin(), cu_cp_cfg.plmns.cend(), cell.cell.plmn) == cu_cp_cfg.plmns.cend()) { - fmt::print("Could not find cell PLMN '{}' in the CU-CP PLMN list", cell.cell.plmn); - - return false; + for (const auto& supported_ta : cu_cp_cfg.supported_tas) { + if (supported_ta.tac == cell.cell.tac && supported_ta.plmn == cell.cell.plmn) { + ret_val = true; + } } - if (std::find(cu_cp_cfg.tacs.cbegin(), cu_cp_cfg.tacs.cend(), cell.cell.tac) == cu_cp_cfg.tacs.cend()) { - fmt::print("Could not find cell TAC '{}' in the CU-CP TAC list", cell.cell.tac); + if (!ret_val) { + fmt::print("Could not find cell PLMN '{}' and cell TAC '{}' in the CU-CP supported tracking areas list\n", + cell.cell.plmn, + cell.cell.tac); return false; } } - return true; + return ret_val; } diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index 5a0bcf6100..25b0d1b9fa 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -11,6 +11,7 @@ #include "cu_cp_config_translators.h" #include "cu_cp_unit_config.h" #include "srsran/cu_cp/cu_cp_configuration_helpers.h" +#include "srsran/ran/plmn_identity.h" #include "srsran/rlc/rlc_config.h" #include @@ -324,13 +325,15 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co out_cfg.admission.max_nof_cu_ups = cu_cfg.max_nof_cu_ups; out_cfg.admission.max_nof_ues = cu_cfg.max_nof_ues; - srsran_assert(!cu_cfg.plmns.empty(), "PLMN list is empty"); - srsran_assert(!cu_cfg.tacs.empty(), "PLMN list is empty"); - out_cfg.node.gnb_id = cu_cfg.gnb_id; - out_cfg.node.ran_node_name = cu_cfg.ran_node_name; - out_cfg.node.plmn = plmn_identity::parse(cu_cfg.plmns.front()).value(); - out_cfg.node.tac = cu_cfg.tacs.front(); - out_cfg.node.supported_slices = cu_cfg.slice_cfg; + out_cfg.node.gnb_id = cu_cfg.gnb_id; + out_cfg.node.ran_node_name = cu_cfg.ran_node_name; + + srsran_assert(!cu_cfg.supported_tas.empty(), "Supported tracking area list is empty"); + for (const auto& supported_ta : cu_cfg.supported_tas) { + expected plmn = plmn_identity::parse(supported_ta.plmn); + srsran_assert(plmn.has_value(), "Invalid PLMN: {}", supported_ta.plmn); + out_cfg.node.supported_tas.push_back({supported_ta.tac, plmn.value(), supported_ta.tai_slice_support_list}); + } out_cfg.rrc.force_reestablishment_fallback = cu_cfg.rrc_config.force_reestablishment_fallback; out_cfg.rrc.rrc_procedure_timeout_ms = std::chrono::milliseconds{cu_cfg.rrc_config.rrc_procedure_timeout_ms}; diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index 582fbf3f97..50e0d955f0 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -21,6 +21,19 @@ namespace srsran { +struct cu_cp_unit_supported_ta_item { + unsigned tac; + std::string plmn; + /// Supported Slices by the RAN node. + std::vector tai_slice_support_list; +}; + +/// All tracking area related configuration parameters. +struct cu_cp_unit_ta_config { + /// List of all tracking areas supported by the CU-CP. + std::vector supported_tas; +}; + /// Report configuration, for now only supporting the A3 event. struct cu_cp_unit_report_config { unsigned report_cfg_id; @@ -231,10 +244,6 @@ struct cu_cp_unit_config { std::string ran_node_name = "cu_cp_01"; /// gNB identifier. gnb_id_t gnb_id = {411, 22}; - /// List of accepted PLMNs. - std::vector plmns; - /// List of accepted TACs. - std::vector tacs; /// Maximum number of DUs. uint16_t max_nof_dus = 6; /// Maximum number of CU-UPs. @@ -253,6 +262,8 @@ struct cu_cp_unit_config { cu_cp_unit_metrics_config metrics; /// AMF configuration. cu_cp_unit_amf_config amf_cfg; + /// List of all tracking areas supported by the CU-CP. + std::vector supported_tas; /// Mobility configuration. cu_cp_unit_mobility_config mobility_config; /// RRC configuration. diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp index 2ee464c08f..002fe18b76 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -46,6 +46,46 @@ static void configure_cli11_pcap_args(CLI::App& app, cu_cp_unit_pcap_config& pca add_option(app, "--e1ap_enable", pcap_params.e1ap.enabled, "Enable E1AP packet capture")->always_capture_default(); } +static void configure_cli11_tai_slice_support_args(CLI::App& app, s_nssai_t& config) +{ + add_option(app, "--sst", config.sst, "Slice Service Type")->capture_default_str()->check(CLI::Range(0, 255)); + add_option(app, "--sd", config.sd, "Service Differentiator")->capture_default_str()->check(CLI::Range(0, 0xffffff)); +} + +static void configure_cli11_supported_ta_args(CLI::App& app, cu_cp_unit_supported_ta_item& config) +{ + add_option(app, "--tac", config.tac, "TAC to be configured")->check([](const std::string& value) { + std::stringstream ss(value); + unsigned tac; + ss >> tac; + + // Values 0 and 0xfffffe are reserved. + if (tac == 0U || tac == 0xfffffeU) { + return "TAC values 0 or 0xfffffe are reserved"; + } + + return (tac <= 0xffffffU) ? "" : "TAC value out of range"; + }); + add_option(app, "--plmn", config.plmn, "PLMN to be configured"); + + // TAI slice support list. + app.add_option_function>( + "--tai_slice_support_list", + [&config](const std::vector& values) { + config.tai_slice_support_list.resize(values.size()); + + for (unsigned i = 0, e = values.size(); i != e; ++i) { + CLI::App subapp("TAI slice support list"); + subapp.config_formatter(create_yaml_config_parser()); + subapp.allow_config_extras(CLI::config_extras_mode::error); + configure_cli11_tai_slice_support_args(subapp, config.tai_slice_support_list[i]); + std::istringstream ss(values[i]); + subapp.parse_from_stream(ss); + } + }, + "Sets the list of TAI slices supported by the CU-CP"); +} + static void configure_cli11_report_args(CLI::App& app, cu_cp_unit_report_config& report_params) { add_option(app, "--report_cfg_id", report_params.report_cfg_id, "Report configuration id to be configured") @@ -263,21 +303,6 @@ static void configure_cli11_cu_cp_args(CLI::App& app, cu_cp_unit_config& cu_cp_p ->capture_default_str() ->check(CLI::Range(1, 7200)); - add_option(app, "--plmns", cu_cp_params.plmns, "List of allowed PLMNs"); - add_option(app, "--tacs", cu_cp_params.tacs, "List of allowed TACs")->check([](const std::string& value) { - std::stringstream ss(value); - unsigned tac; - ss >> tac; - - // Values 0 and 0xfffffe are reserved. - if (tac == 0U || tac == 0xfffffeU) { - return "TAC values 0 or 0xfffffe are reserved"; - } - - return (tac <= 0xffffffU) ? "" : "TAC value out of range"; - }); - ; - add_option(app, "--pdu_session_setup_timeout", cu_cp_params.pdu_session_setup_timeout, @@ -285,6 +310,24 @@ static void configure_cli11_cu_cp_args(CLI::App& app, cu_cp_unit_config& cu_cp_p "seconds. The timeout must be larger than T310. If the value is reached, the UE will be released") ->capture_default_str(); + // Tracking areas section. + auto ta_lambda = [&cu_cp_params](const std::vector& values) { + // Prepare the supported TAs list. + cu_cp_params.supported_tas.resize(values.size()); + + // Format every TA setting. + for (unsigned i = 0, e = values.size(); i != e; ++i) { + CLI::App subapp("Supported tracking areas", "TA config, item #" + std::to_string(i)); + subapp.config_formatter(create_yaml_config_parser()); + subapp.allow_config_extras(CLI::config_extras_mode::capture); + configure_cli11_supported_ta_args(subapp, cu_cp_params.supported_tas[i]); + std::istringstream ss(values[i]); + subapp.parse_from_stream(ss); + } + }; + add_option_cell( + app, "--supported_tracking_areas", ta_lambda, "Configures the list of tracking areas supported by the CU-CP"); + CLI::App* mobility_subcmd = app.add_subcommand("mobility", "Mobility configuration"); configure_cli11_mobility_args(*mobility_subcmd, cu_cp_params.mobility_config); @@ -408,14 +451,6 @@ static void configure_cli11_metrics_args(CLI::App& app, cu_cp_unit_metrics_confi ->capture_default_str(); } -static void configure_cli11_slicing_args(CLI::App& app, s_nssai_t& slice_params) -{ - add_option(app, "--sst", slice_params.sst, "Slice Service Type")->capture_default_str()->check(CLI::Range(0, 255)); - add_option(app, "--sd", slice_params.sd, "Service Differentiator") - ->capture_default_str() - ->check(CLI::Range(0, 0xffffff)); -} - static void configure_cli11_amf_args(CLI::App& app, cu_cp_unit_amf_config& amf_params) { add_option(app, "--addr", amf_params.ip_addr, "AMF IP address"); @@ -484,55 +519,24 @@ void srsran::configure_cli11_with_cu_cp_unit_config_schema(CLI::App& app, cu_cp_ } }; add_option_cell(app, "--qos", qos_lambda, "Configures RLC and PDCP radio bearers on a per 5QI basis."); - - // Slicing section. - auto slicing_lambda = [&unit_cfg](const std::vector& values) { - // Prepare the slices. - unit_cfg.slice_cfg.resize(values.size()); - - // Format every slicing setting. - for (unsigned i = 0, e = values.size(); i != e; ++i) { - CLI::App subapp("Slicing parameters", "Slicing config, item #" + std::to_string(i)); - subapp.config_formatter(create_yaml_config_parser()); - subapp.allow_config_extras(CLI::config_extras_mode::capture); - configure_cli11_slicing_args(subapp, unit_cfg.slice_cfg[i]); - std::istringstream ss(values[i]); - subapp.parse_from_stream(ss); - } - }; - add_option_cell(app, "--slicing", slicing_lambda, "Network slicing configuration"); } -static std::vector auto_generate_plmns() +static std::vector auto_generate_supported_tas() { - std::vector vec = {"00101"}; + std::vector vec = {{7, "00101", {}}}; return vec; } -static std::vector auto_generate_tacs() -{ - std::vector out_cfg = {7}; - - return out_cfg; -} - -void srsran::autoderive_cu_cp_parameters_after_parsing(CLI::App& app, - cu_cp_unit_config& unit_cfg, - std::vector plmns, - std::vector tacs) +void srsran::autoderive_cu_cp_parameters_after_parsing(CLI::App& app, + cu_cp_unit_config& unit_cfg, + std::vector supported_tas) { auto cu_cp_app = app.get_subcommand_ptr("cu_cp"); - // No PLMNs defined in the cu_cp section. Use the given ones. - if (cu_cp_app->count_all() == 0 || cu_cp_app->count("--plmns") == 0) { - srsran_assert(unit_cfg.plmns.empty(), "PLMN list is not empty"); - - unit_cfg.plmns = plmns.empty() ? auto_generate_plmns() : std::move(plmns); - } - - if (cu_cp_app->count_all() == 0 || cu_cp_app->count("--tacs") == 0) { - srsran_assert(unit_cfg.tacs.empty(), "TAC list is not empty"); + // No supported tracking areas defined in the cu_cp section. Use the given ones. + if (cu_cp_app->count_all() == 0 || cu_cp_app->count("--supported_tracking_areas") == 0) { + srsran_assert(unit_cfg.supported_tas.empty(), "Supported tracking area list is not empty"); - unit_cfg.tacs = tacs.empty() ? auto_generate_tacs() : std::move(tacs); + unit_cfg.supported_tas = supported_tas.empty() ? auto_generate_supported_tas() : std::move(supported_tas); } for (auto& cell : unit_cfg.mobility_config.cells) { diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.h b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.h index 0d5b04d436..e9f884b68a 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.h +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.h @@ -17,14 +17,14 @@ namespace srsran { struct cu_cp_unit_config; +struct cu_cp_unit_supported_ta_item; /// Configures the given CLI11 application with the CU-CP application unit configuration schema. void configure_cli11_with_cu_cp_unit_config_schema(CLI::App& app, cu_cp_unit_config& unit_cfg); /// Auto derive DU high parameters after the parsing. -void autoderive_cu_cp_parameters_after_parsing(CLI::App& app, - cu_cp_unit_config& unit_cfg, - std::vector plmns, - std::vector tacs); +void autoderive_cu_cp_parameters_after_parsing(CLI::App& app, + cu_cp_unit_config& unit_cfg, + std::vector supported_tas); } // namespace srsran diff --git a/apps/units/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/cu_cp/cu_cp_unit_config_validator.cpp index 25528055ca..53409d0113 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_validator.cpp @@ -461,12 +461,6 @@ static bool validate_cu_cp_appconfig(const gnb_id_t gnb_id, const cu_cp_unit_con return false; } - if (config.plmns.size() != config.tacs.size()) { - fmt::print("Number of PLMNs '{}' do not match the number of TACs '{}'\n", config.plmns.size(), config.tacs.size()); - - return false; - } - return true; } diff --git a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp index e6dd6f4eb3..8246010f87 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp @@ -30,6 +30,33 @@ static void fill_cu_cp_amf_section(YAML::Node node, const cu_cp_unit_amf_config& node["no_core"] = config.no_core; } +static YAML::Node build_cu_cp_tai_slice_section(const s_nssai_t& config) +{ + YAML::Node node; + + node["sst"] = config.sst; + if (config.sd) { + node["sd"] = config.sd.value(); + } + + return node; +} + +static YAML::Node build_cu_cp_supported_tas_section(const std::vector& config) +{ + YAML::Node node; + + for (const auto& supported_ta : config) { + node["tac"] = supported_ta.tac; + node["plmn"] = supported_ta.plmn; + for (const auto& slice : supported_ta.tai_slice_support_list) { + node["tai_slice_support_list"] = build_cu_cp_tai_slice_section(slice); + } + } + + return node; +} + static YAML::Node build_cu_cp_mobility_ncells_section(const cu_cp_unit_neighbor_cell_config_item& config) { YAML::Node node; @@ -170,20 +197,12 @@ static YAML::Node build_cu_cp_section(const cu_cp_unit_config& config) node["max_nof_ues"] = config.max_nof_ues; node["inactivity_timer"] = config.inactivity_timer; node["pdu_session_setup_timeout"] = config.pdu_session_setup_timeout; - for (const auto& plmn : config.plmns) { - node["plmns"].push_back(plmn); - } - node["plmns"].SetStyle(YAML::EmitterStyle::Flow); - - for (auto tac : config.tacs) { - node["tacs"].push_back(tac); - } - node["tacs"].SetStyle(YAML::EmitterStyle::Flow); - node["mobility"] = build_cu_cp_mobility_section(config.mobility_config); - node["rrc"] = build_cu_cp_rrc_section(config.rrc_config); - node["security"] = build_cu_cp_security_section(config.security_config); - node["f1ap"] = build_cu_cp_f1ap_section(config.f1ap_config); + node["supported_tracking_areas"] = build_cu_cp_supported_tas_section(config.supported_tas); + node["mobility"] = build_cu_cp_mobility_section(config.mobility_config); + node["rrc"] = build_cu_cp_rrc_section(config.rrc_config); + node["security"] = build_cu_cp_security_section(config.security_config); + node["f1ap"] = build_cu_cp_f1ap_section(config.f1ap_config); return node; } diff --git a/configs/tracking_areas.yml b/configs/tracking_areas.yml new file mode 100644 index 0000000000..7577039aff --- /dev/null +++ b/configs/tracking_areas.yml @@ -0,0 +1,13 @@ +# Example configuration file for supported tracking areas. + +cu_cp: + supported_tracking_areas: + # List of all tracking areas supported by the CU-CP. + # Note that the first PLMN of this list is used for the Global RAN Node ID + - tac: 7 + plmn: "00101" + tai_slice_support_list: + - sst: 1 + sd: 1 + - sst: 2 + sd: 42 diff --git a/include/srsran/cu_cp/cu_cp_configuration.h b/include/srsran/cu_cp/cu_cp_configuration.h index 68377f77ee..390d010fe7 100644 --- a/include/srsran/cu_cp/cu_cp_configuration.h +++ b/include/srsran/cu_cp/cu_cp_configuration.h @@ -22,15 +22,20 @@ namespace srs_cu_cp { class n2_connection_client; +struct supported_tracking_area { + unsigned tac; + plmn_identity plmn; + /// Supported Slices by the RAN node. + std::vector supported_slices; +}; + /// Parameters of the CU-CP that will reported to the 5G core. struct ran_node_configuration { /// The gNodeB identifier. - gnb_id_t gnb_id{411, 22}; - std::string ran_node_name = "srsgnb01"; - plmn_identity plmn = plmn_identity::test_value(); - unsigned tac = 7; - /// Supported Slices by the RAN node. - std::vector supported_slices; + gnb_id_t gnb_id{411, 22}; + std::string ran_node_name = "srsgnb01"; + // Supported TAs in the NG RAN node. + std::vector supported_tas; }; struct mobility_configuration { diff --git a/include/srsran/cu_cp/cu_cp_configuration_helpers.h b/include/srsran/cu_cp/cu_cp_configuration_helpers.h index 65338783f2..a0c3142691 100644 --- a/include/srsran/cu_cp/cu_cp_configuration_helpers.h +++ b/include/srsran/cu_cp/cu_cp_configuration_helpers.h @@ -149,7 +149,8 @@ inline srs_cu_cp::cu_cp_configuration make_default_cu_cp_config() // Slices s_nssai_t slice_cfg; slice_cfg.sst = 1; - cfg.node.supported_slices.push_back(slice_cfg); + cfg.node.supported_tas.push_back( + srsran::srs_cu_cp::supported_tracking_area{7, plmn_identity::test_value(), {slice_cfg}}); // DRBs cfg.bearers.drb_config = config_helpers::make_default_cu_cp_qos_config_list(); // Security. @@ -191,5 +192,16 @@ inline bool is_valid_configuration(const srs_cu_cp::cu_cp_configuration& config) return true; } +inline std::vector +get_supported_plmns(const std::vector& supported_tas) +{ + std::vector plmns; + plmns.reserve(supported_tas.size()); + for (const auto& ta : supported_tas) { + plmns.push_back(ta.plmn); + } + return plmns; +} + } // namespace config_helpers } // namespace srsran diff --git a/include/srsran/ngap/ngap_configuration.h b/include/srsran/ngap/ngap_configuration.h index 8f207dd288..da40b53861 100644 --- a/include/srsran/ngap/ngap_configuration.h +++ b/include/srsran/ngap/ngap_configuration.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/cu_cp/cu_cp_configuration.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/ran/gnb_id.h" #include @@ -22,11 +23,10 @@ namespace srs_cu_cp { /// \brief NGAP configuration struct ngap_configuration { - gnb_id_t gnb_id{0, 22}; - std::string ran_node_name; - plmn_identity plmn = plmn_identity::test_value(); - unsigned tac; - std::chrono::seconds pdu_session_setup_timeout; // timeout for pdu session setup in seconds + gnb_id_t gnb_id{0, 22}; + std::string ran_node_name; + std::vector supported_tas; + std::chrono::seconds pdu_session_setup_timeout; // timeout for pdu session setup in seconds }; } // namespace srs_cu_cp diff --git a/include/srsran/ngap/ngap_configuration_helpers.h b/include/srsran/ngap/ngap_configuration_helpers.h index ecf219fb62..4363334b7a 100644 --- a/include/srsran/ngap/ngap_configuration_helpers.h +++ b/include/srsran/ngap/ngap_configuration_helpers.h @@ -24,8 +24,7 @@ inline srs_cu_cp::ngap_configuration make_default_ngap_config() srs_cu_cp::ngap_configuration cfg{}; cfg.gnb_id = {411, 22}; cfg.ran_node_name = "srsgnb01"; - cfg.plmn = plmn_identity::test_value(); - cfg.tac = 7; + cfg.supported_tas = {{7, plmn_identity::test_value(), {}}}; return cfg; } diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index e3ab23041a..a45b4ce186 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -49,8 +49,7 @@ ngap_configuration create_ngap_cfg(const cu_cp_configuration& cfg) ngap_configuration ngap_cfg; ngap_cfg.gnb_id = cfg.node.gnb_id; ngap_cfg.ran_node_name = cfg.node.ran_node_name; - ngap_cfg.plmn = cfg.node.plmn; - ngap_cfg.tac = cfg.node.tac; + ngap_cfg.supported_tas = cfg.node.supported_tas; ngap_cfg.pdu_session_setup_timeout = cfg.ue.pdu_session_setup_timeout; return ngap_cfg; } diff --git a/lib/cu_cp/du_processor/du_configuration_manager.cpp b/lib/cu_cp/du_processor/du_configuration_manager.cpp index 1b47b64b15..fe5daa8b4e 100644 --- a/lib/cu_cp/du_processor/du_configuration_manager.cpp +++ b/lib/cu_cp/du_processor/du_configuration_manager.cpp @@ -9,6 +9,7 @@ */ #include "du_configuration_manager.h" +#include "srsran/ran/plmn_identity.h" using namespace srsran; using namespace srs_cu_cp; @@ -73,8 +74,8 @@ class du_configuration_manager::du_configuration_handler_impl : public du_config du_configuration_manager& parent; }; -du_configuration_manager::du_configuration_manager(const gnb_id_t& gnb_id_, const plmn_identity& plmn_id_) : - gnb_id(gnb_id_), plmn_id(plmn_id_), logger(srslog::fetch_basic_logger("CU-CP")) +du_configuration_manager::du_configuration_manager(const gnb_id_t& gnb_id_, const std::vector& plmns_) : + gnb_id(gnb_id_), plmns(plmns_), logger(srslog::fetch_basic_logger("CU-CP")) { } @@ -209,14 +210,15 @@ du_configuration_manager::validate_new_du_config(const du_setup_request& req) co return ret; } - if (served_cell.served_cell_info.nr_cgi.plmn_id != plmn_id) { + if (std::find(plmns.begin(), plmns.end(), served_cell.served_cell_info.nr_cgi.plmn_id) == plmns.end()) { return make_unexpected(du_setup_result::rejected{f1ap_cause_radio_network_t::plmn_not_served_by_the_gnb_cu, "Served Cell CGI PLMN is not supported by the CU-CP"}); } - if (std::none_of(served_cell.served_cell_info.served_plmns.begin(), - served_cell.served_cell_info.served_plmns.end(), - [this](const plmn_identity& plmn) { return plmn == plmn_id; })) { + if (std::none_of( + served_cell.served_cell_info.served_plmns.begin(), + served_cell.served_cell_info.served_plmns.end(), + [this](const plmn_identity& plmn) { return std::find(plmns.begin(), plmns.end(), plmn) != plmns.end(); })) { return make_unexpected(du_setup_result::rejected{f1ap_cause_radio_network_t::plmn_not_served_by_the_gnb_cu, "None of the served cell PLMNs is available in the CU-CP"}); } diff --git a/lib/cu_cp/du_processor/du_configuration_manager.h b/lib/cu_cp/du_processor/du_configuration_manager.h index 6ec1513e2c..c390308341 100644 --- a/lib/cu_cp/du_processor/du_configuration_manager.h +++ b/lib/cu_cp/du_processor/du_configuration_manager.h @@ -12,6 +12,7 @@ #include "du_configuration_handler.h" #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/ran/plmn_identity.h" #include "srsran/srslog/srslog.h" namespace srsran { @@ -21,7 +22,7 @@ namespace srs_cu_cp { class du_configuration_manager { public: - du_configuration_manager(const gnb_id_t& gnb_id, const plmn_identity& plmn_id); + du_configuration_manager(const gnb_id_t& gnb_id_, const std::vector& plmns_); /// Create a new DU configuration handler. std::unique_ptr create_du_handler(); @@ -42,9 +43,9 @@ class du_configuration_manager validation_result validate_du_config_update(const du_config_update_request& req) const; validation_result validate_cell_config_request(const cu_cp_du_served_cells_item& served_cell) const; - const gnb_id_t gnb_id; - const plmn_identity plmn_id; - srslog::basic_logger& logger; + const gnb_id_t gnb_id; + const std::vector plmns; + srslog::basic_logger& logger; std::unordered_map dus; }; diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index 1d76580df0..acb4a6c2e4 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -12,6 +12,8 @@ #include "du_processor_config.h" #include "du_processor_factory.h" #include "srsran/cu_cp/cu_cp_configuration.h" +#include "srsran/cu_cp/cu_cp_configuration_helpers.h" +#include "srsran/ran/plmn_identity.h" #include "srsran/rrc/rrc_config.h" #include "srsran/support/executors/sync_task_executor.h" #include @@ -20,7 +22,9 @@ using namespace srsran; using namespace srs_cu_cp; du_processor_repository::du_processor_repository(du_repository_config cfg_) : - cfg(cfg_), logger(cfg.logger), du_cfg_mng(cfg.cu_cp.node.gnb_id, cfg.cu_cp.node.plmn) + cfg(cfg_), + logger(cfg.logger), + du_cfg_mng(cfg.cu_cp.node.gnb_id, config_helpers::get_supported_plmns(cfg.cu_cp.node.supported_tas)) { } diff --git a/lib/cu_cp/routines/amf_connection_setup_routine.cpp b/lib/cu_cp/routines/amf_connection_setup_routine.cpp index 935b2f87d9..6ae7804ed0 100644 --- a/lib/cu_cp/routines/amf_connection_setup_routine.cpp +++ b/lib/cu_cp/routines/amf_connection_setup_routine.cpp @@ -39,30 +39,33 @@ ngap_ng_setup_request amf_connection_setup_routine::fill_ng_setup_request() ngap_ng_setup_request request; // fill global ran node id - request.global_ran_node_id.gnb_id = cu_cp_cfg.node.gnb_id; - request.global_ran_node_id.plmn_id = cu_cp_cfg.node.plmn; + request.global_ran_node_id.gnb_id = cu_cp_cfg.node.gnb_id; + // TODO: Which PLMN do we need to use here? + request.global_ran_node_id.plmn_id = cu_cp_cfg.node.supported_tas.front().plmn; // fill ran node name request.ran_node_name = cu_cp_cfg.node.ran_node_name; // fill supported ta list - // TODO: add support for more items - ngap_supported_ta_item supported_ta_item; - - ngap_broadcast_plmn_item broadcast_plmn_item; - broadcast_plmn_item.plmn_id = cu_cp_cfg.node.plmn; - - for (const auto& slice_config : cu_cp_cfg.node.supported_slices) { - slice_support_item_t slice_support_item; - slice_support_item.s_nssai.sst = slice_config.sst; - if (slice_config.sd.has_value()) { - slice_support_item.s_nssai.sd = slice_config.sd.value(); + for (const auto& supported_ta : cu_cp_cfg.node.supported_tas) { + // TODO: add support for more items + ngap_supported_ta_item supported_ta_item; + + ngap_broadcast_plmn_item broadcast_plmn_item; + broadcast_plmn_item.plmn_id = supported_ta.plmn; + + for (const auto& slice_config : supported_ta.supported_slices) { + slice_support_item_t slice_support_item; + slice_support_item.s_nssai.sst = slice_config.sst; + if (slice_config.sd.has_value()) { + slice_support_item.s_nssai.sd = slice_config.sd.value(); + } + broadcast_plmn_item.tai_slice_support_list.push_back(slice_support_item); } - broadcast_plmn_item.tai_slice_support_list.push_back(slice_support_item); - } - supported_ta_item.broadcast_plmn_list.push_back(broadcast_plmn_item); - supported_ta_item.tac = cu_cp_cfg.node.tac; + supported_ta_item.broadcast_plmn_list.push_back(broadcast_plmn_item); + supported_ta_item.tac = supported_ta.tac; - request.supported_ta_list.push_back(supported_ta_item); + request.supported_ta_list.push_back(supported_ta_item); + } // fill paging drx request.default_paging_drx = 256; diff --git a/lib/ngap/ngap_context.h b/lib/ngap/ngap_context.h index 21319b6b1b..bb7602b3e9 100644 --- a/lib/ngap/ngap_context.h +++ b/lib/ngap/ngap_context.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/cu_cp/cu_cp_configuration.h" #include "srsran/ngap/ngap_types.h" #include "srsran/ran/gnb_id.h" #include "srsran/ran/plmn_identity.h" @@ -22,12 +23,11 @@ namespace srs_cu_cp { /// \brief NGAP context struct ngap_context_t { - gnb_id_t gnb_id = {0, 22}; - std::string ran_node_name; - plmn_identity plmn = plmn_identity::test_value(); - unsigned tac; - std::vector served_guami_list; - std::chrono::seconds pdu_session_setup_timeout; // timeout for PDU context setup in seconds + gnb_id_t gnb_id = {0, 22}; + std::string ran_node_name; + std::vector supported_tas; + std::vector served_guami_list; + std::chrono::seconds pdu_session_setup_timeout; // timeout for PDU context setup in seconds }; } // namespace srs_cu_cp diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 6278d63a60..0ce4822a2c 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -49,8 +49,7 @@ ngap_impl::ngap_impl(const ngap_configuration& ngap_cfg_, { context.gnb_id = ngap_cfg_.gnb_id; context.ran_node_name = ngap_cfg_.ran_node_name; - context.plmn = ngap_cfg_.plmn; - context.tac = ngap_cfg_.tac; + context.supported_tas = ngap_cfg_.supported_tas; context.pdu_session_setup_timeout = ngap_cfg_.pdu_session_setup_timeout; } diff --git a/tests/integrationtests/ngap/ngap_integration_test.cpp b/tests/integrationtests/ngap/ngap_integration_test.cpp index 4ef0b764fa..fd0b749cbc 100644 --- a/tests/integrationtests/ngap/ngap_integration_test.cpp +++ b/tests/integrationtests/ngap/ngap_integration_test.cpp @@ -116,8 +116,7 @@ class ngap_integration_test : public ::testing::Test { cfg.gnb_id = cu_cp_cfg.node.gnb_id; cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; - cfg.plmn = cu_cp_cfg.node.plmn; - cfg.tac = cu_cp_cfg.node.tac; + cfg.supported_tas = cu_cp_cfg.node.supported_tas; cfg.pdu_session_setup_timeout = cu_cp_cfg.ue.pdu_session_setup_timeout; } @@ -153,38 +152,40 @@ class ngap_integration_test : public ::testing::Test srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); }; -ngap_ng_setup_request generate_ng_setup_request(const ngap_configuration& ngap_cfg, - const std::vector& slices) +ngap_ng_setup_request generate_ng_setup_request(const ngap_configuration& ngap_cfg) { ngap_ng_setup_request request_msg = {}; ngap_ng_setup_request request; // fill global ran node id - request.global_ran_node_id.gnb_id = ngap_cfg.gnb_id; - request.global_ran_node_id.plmn_id = ngap_cfg.plmn; + request.global_ran_node_id.gnb_id = ngap_cfg.gnb_id; + // TODO: Which PLMN do we need to use here? + request.global_ran_node_id.plmn_id = ngap_cfg.supported_tas.front().plmn; // fill ran node name request.ran_node_name = ngap_cfg.ran_node_name; // fill supported ta list - // TODO: add support for more items - ngap_supported_ta_item supported_ta_item; + for (const auto& supported_ta : ngap_cfg.supported_tas) { + ngap_supported_ta_item supported_ta_item; - ngap_broadcast_plmn_item broadcast_plmn_item; - broadcast_plmn_item.plmn_id = ngap_cfg.plmn; + supported_ta_item.tac = supported_ta.tac; - for (const auto& slice_config : slices) { - slice_support_item_t slice_support_item; - slice_support_item.s_nssai.sst = slice_config.sst; - if (slice_config.sd.has_value()) { - slice_support_item.s_nssai.sd = slice_config.sd.value(); + ngap_broadcast_plmn_item broadcast_plmn_item; + broadcast_plmn_item.plmn_id = supported_ta.plmn; + + for (const auto& slice_config : supported_ta.supported_slices) { + slice_support_item_t slice_support_item; + slice_support_item.s_nssai.sst = slice_config.sst; + if (slice_config.sd.has_value()) { + slice_support_item.s_nssai.sd = slice_config.sd.value(); + } + broadcast_plmn_item.tai_slice_support_list.push_back(slice_support_item); } - broadcast_plmn_item.tai_slice_support_list.push_back(slice_support_item); - } - supported_ta_item.broadcast_plmn_list.push_back(broadcast_plmn_item); - supported_ta_item.tac = ngap_cfg.tac; + supported_ta_item.broadcast_plmn_list.push_back(broadcast_plmn_item); - request.supported_ta_list.push_back(supported_ta_item); + request.supported_ta_list.push_back(supported_ta_item); + } // fill paging drx request.default_paging_drx = 256; @@ -196,7 +197,7 @@ ngap_ng_setup_request generate_ng_setup_request(const ngap_configuration& ng TEST_F(ngap_integration_test, when_ng_setup_response_received_then_amf_connected) { // Action 1: Launch NG setup procedure - ngap_ng_setup_request request_msg = generate_ng_setup_request(cfg, cu_cp_cfg.node.supported_slices); + ngap_ng_setup_request request_msg = generate_ng_setup_request(cfg); test_logger.info("Launching NG setup procedure..."); async_task t = ngap->handle_ng_setup_request(request_msg); diff --git a/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp b/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp index 0edb1f5b48..28896b420f 100644 --- a/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp +++ b/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp @@ -41,11 +41,11 @@ static du_setup_request create_basic_du_setup_request(unsigned du_counter = 0) class du_configuration_manager_test : public ::testing::Test { public: - du_configuration_manager_test() : du_cfg_mng(gnb_id, plmn) {} + du_configuration_manager_test() : du_cfg_mng(gnb_id, plmns) {} - gnb_id_t gnb_id{411, 22}; - plmn_identity plmn = plmn_identity::test_value(); - du_configuration_manager du_cfg_mng; + gnb_id_t gnb_id{411, 22}; + std::vector plmns = {plmn_identity::test_value()}; + du_configuration_manager du_cfg_mng; }; TEST_F(du_configuration_manager_test, when_instance_created_then_it_has_no_dus) diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp index 369b3dea93..5032455f8c 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp @@ -108,7 +108,8 @@ du_processor_test::du_processor_test() : return cucfg; }()), common_task_sched(std::make_unique()), - du_cfg_mgr{cu_cp_cfg.node.gnb_id, cu_cp_cfg.node.plmn} + + du_cfg_mgr{cu_cp_cfg.node.gnb_id, config_helpers::get_supported_plmns(cu_cp_cfg.node.supported_tas)} { test_logger.set_level(srslog::basic_levels::debug); cu_cp_logger.set_level(srslog::basic_levels::debug); diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index 0a0bdab173..aa248e7d40 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -36,8 +36,7 @@ ngap_test::ngap_test() : ngap_configuration ngap_cfg{}; ngap_cfg.gnb_id = cu_cp_cfg.node.gnb_id; ngap_cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; - ngap_cfg.plmn = cu_cp_cfg.node.plmn; - ngap_cfg.tac = cu_cp_cfg.node.tac; + ngap_cfg.supported_tas = cu_cp_cfg.node.supported_tas; ngap_cfg.pdu_session_setup_timeout = cu_cp_cfg.ue.pdu_session_setup_timeout; ngap = create_ngap(ngap_cfg, cu_cp_notifier, cu_cp_paging_notifier, n2_gw, timers, ctrl_worker); From d1ca7308124ececaea3e77fcc188e234f14a98a9 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 23 Aug 2024 15:46:40 +0200 Subject: [PATCH 329/407] cu_cp: add validator for supported tracking areas --- apps/gnb/gnb.cpp | 8 ++++- apps/units/cu_cp/cu_cp_config_translators.cpp | 5 +++- .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 2 +- .../cu_cp/cu_cp_unit_config_validator.cpp | 30 +++++++++++++++++++ .../cu_cp/cu_cp_configuration_helpers.h | 7 ++--- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 2b0331d1a5..9cba8e86a4 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -234,10 +234,16 @@ int main(int argc, char** argv) autoderive_dynamic_du_parameters_after_parsing(app, du_unit_cfg); // Create the supported tracking areas list from the cells. + // These will only be used if no supported TAs are provided in the CU-CP configuration. std::vector supported_tas; supported_tas.reserve(du_unit_cfg.du_high_cfg.config.cells_cfg.size()); for (const auto& cell : du_unit_cfg.du_high_cfg.config.cells_cfg) { - supported_tas.push_back({cell.cell.tac, cell.cell.plmn, {}}); + // Make sure supported tracking areas are unique. + if (std::find_if(supported_tas.begin(), supported_tas.end(), [&cell](const auto& ta) { + return ta.tac == cell.cell.tac && ta.plmn == cell.cell.plmn; + }) == supported_tas.end()) { + supported_tas.push_back({cell.cell.tac, cell.cell.plmn, {{1}}}); + } } // If test mode is enabled, we auto-enable "no_core" option diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index 25b0d1b9fa..4a1f8835cb 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -328,7 +328,10 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co out_cfg.node.gnb_id = cu_cfg.gnb_id; out_cfg.node.ran_node_name = cu_cfg.ran_node_name; - srsran_assert(!cu_cfg.supported_tas.empty(), "Supported tracking area list is empty"); + if (!cu_cfg.supported_tas.empty()) { + // Clear default supported TAs if any are provided in the config. + out_cfg.node.supported_tas.clear(); + } for (const auto& supported_ta : cu_cfg.supported_tas) { expected plmn = plmn_identity::parse(supported_ta.plmn); srsran_assert(plmn.has_value(), "Invalid PLMN: {}", supported_ta.plmn); diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp index 002fe18b76..13c2d8ecfe 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -523,7 +523,7 @@ void srsran::configure_cli11_with_cu_cp_unit_config_schema(CLI::App& app, cu_cp_ static std::vector auto_generate_supported_tas() { - std::vector vec = {{7, "00101", {}}}; + std::vector vec = {{7, "00101", {{1}}}}; return vec; } diff --git a/apps/units/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/cu_cp/cu_cp_unit_config_validator.cpp index 53409d0113..38a2e9a77b 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_validator.cpp @@ -441,6 +441,31 @@ static bool validate_amf_appconfig(const cu_cp_unit_amf_config& config) return true; } +/// Validates the given supported tracking areas configuration. Returns true on success, otherwise false. +static bool validate_supported_tas_appconfig(const std::vector& config) +{ + if (config.size() > 1) { + for (unsigned outer_ta_idx = 0; outer_ta_idx < config.size(); outer_ta_idx++) { + for (unsigned inner_ta_idx = outer_ta_idx + 1; inner_ta_idx < config.size(); inner_ta_idx++) { + if (config[outer_ta_idx].plmn == config[inner_ta_idx].plmn && + config[outer_ta_idx].tac == config[inner_ta_idx].tac) { + fmt::print("Supported tracking areas must be unique\n"); + return false; + } + } + } + } + + for (const auto& ta : config) { + if (ta.tai_slice_support_list.empty()) { + fmt::print("TAI slice support list for PLMN={} and TAC={} is empty\n", ta.plmn, ta.tac); + return false; + } + } + + return true; +} + /// Validates the given CU-CP configuration. Returns true on success, otherwise false. static bool validate_cu_cp_appconfig(const gnb_id_t gnb_id, const cu_cp_unit_config& config) { @@ -448,6 +473,11 @@ static bool validate_cu_cp_appconfig(const gnb_id_t gnb_id, const cu_cp_unit_con return false; } + // validate supported tracking area config + if (!validate_supported_tas_appconfig(config.supported_tas)) { + return false; + } + // validate mobility config if (!validate_mobility_appconfig(gnb_id, config.mobility_config)) { return false; diff --git a/include/srsran/cu_cp/cu_cp_configuration_helpers.h b/include/srsran/cu_cp/cu_cp_configuration_helpers.h index a0c3142691..15c442a935 100644 --- a/include/srsran/cu_cp/cu_cp_configuration_helpers.h +++ b/include/srsran/cu_cp/cu_cp_configuration_helpers.h @@ -146,11 +146,8 @@ inline std::map make_default_cu_cp_qos_c inline srs_cu_cp::cu_cp_configuration make_default_cu_cp_config() { srs_cu_cp::cu_cp_configuration cfg{}; - // Slices - s_nssai_t slice_cfg; - slice_cfg.sst = 1; - cfg.node.supported_tas.push_back( - srsran::srs_cu_cp::supported_tracking_area{7, plmn_identity::test_value(), {slice_cfg}}); + // Supported TAs (this default entry will be removed if supported TAs are provided in the config) + cfg.node.supported_tas.push_back(srsran::srs_cu_cp::supported_tracking_area{7, plmn_identity::test_value(), {{1}}}); // DRBs cfg.bearers.drb_config = config_helpers::make_default_cu_cp_qos_config_list(); // Security. From bec60f961a8a47e60301c281e71c1f2fca1574f5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 22 Aug 2024 11:02:35 +0200 Subject: [PATCH 330/407] phy: optimize PDSCH processor --- .../upper/channel_coding/crc_calculator_lut_impl.h | 4 +++- .../pdsch_processor_concurrent_impl.cpp | 12 ++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/phy/upper/channel_coding/crc_calculator_lut_impl.h b/lib/phy/upper/channel_coding/crc_calculator_lut_impl.h index 9a42eb63a1..4eabf08f9d 100644 --- a/lib/phy/upper/channel_coding/crc_calculator_lut_impl.h +++ b/lib/phy/upper/channel_coding/crc_calculator_lut_impl.h @@ -63,7 +63,9 @@ class crc_calculator_lut_impl : public crc_calculator void put_byte(uint8_t byte) { unsigned idx; - if (order > 8) { + if (order == 24) { + idx = ((crc >> 16) & 0xffU) ^ byte; + } else if (order > 8) { // For more than 8 bits unsigned ord = order - 8U; idx = ((crc >> (ord)) & 0xffU) ^ byte; diff --git a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp index 4b6a5494cd..1f2ceb5db7 100644 --- a/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch_processor_concurrent_impl.cpp @@ -237,14 +237,18 @@ void pdsch_processor_concurrent_impl::fork_cb_batches() cb_counter = 0; auto async_task = [this]() { - trace_point process_pdsch_tp = l1_tracer.now(); - // Select codeblock processor. pdsch_codeblock_processor& cb_processor = cb_processor_pool->get(); // For each segment within the batch. unsigned absolute_i_cb; while ((absolute_i_cb = cb_counter.fetch_add(1)) < nof_cb) { + trace_point process_pdsch_tp = l1_tracer.now(); + + // As the last codeblock has a higher overhead due to the transport block CRC calculation. Reverse codeblock order + // to process first the last CB. + absolute_i_cb = nof_cb - 1 - absolute_i_cb; + // Limit the codeblock number of information bits. units::bits nof_info_bits = std::min(cb_info_bits, tbs - cb_info_bits * absolute_i_cb); @@ -270,6 +274,8 @@ void pdsch_processor_concurrent_impl::fork_cb_batches() // Map into the resource grid. mapper->map(buffer, allocation, reserved, precoding, re_offset[absolute_i_cb]); + + l1_tracer << trace_event((absolute_i_cb == (nof_cb - 1)) ? "Last CB" : "CB", process_pdsch_tp); } // Decrement code block batch counter. @@ -280,8 +286,6 @@ void pdsch_processor_concurrent_impl::fork_cb_batches() notifier->on_finish_processing(); } } - - l1_tracer << trace_event("CB batch", process_pdsch_tp); }; // Spawn tasks. From 81b9d40c278e99d47cb3ae33935d1dc3953aeb29 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 26 Aug 2024 11:23:42 +0200 Subject: [PATCH 331/407] phy: review resource grid pool --- apps/examples/phy/upper_phy_ssb_example.cpp | 13 +++++++++---- include/srsran/phy/support/resource_grid_pool.h | 10 ++++++++-- lib/phy/support/resource_grid_pool_impl.cpp | 1 - lib/phy/support/resource_grid_pool_impl.h | 13 ++++++++++--- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/examples/phy/upper_phy_ssb_example.cpp b/apps/examples/phy/upper_phy_ssb_example.cpp index ad8f5e4b46..cd49b0496f 100644 --- a/apps/examples/phy/upper_phy_ssb_example.cpp +++ b/apps/examples/phy/upper_phy_ssb_example.cpp @@ -118,11 +118,16 @@ class upper_phy_example_sw : public upper_phy_ssb_example // Request RX symbol if UL processing is enabled. if (enable_ul_processing) { resource_grid_context rx_symb_context; - rx_symb_context.sector = 0; - rx_symb_context.slot = context.slot; + rx_symb_context.sector = 0; + rx_symb_context.slot = context.slot; + + // Try to allocate a resource grid. shared_resource_grid rg = ul_rg_pool->allocate_resource_grid(rx_symb_context); - srsran_assert(rg, "Failed to fetch a resource grid."); - rx_symb_req_notifier->on_uplink_slot_request(rx_symb_context, rg); + + // If the resource grid allocation fails, it aborts the slot request. + if (rg) { + rx_symb_req_notifier->on_uplink_slot_request(rx_symb_context, rg); + } } // Request PRACH capture if PRACH processing is enabled. diff --git a/include/srsran/phy/support/resource_grid_pool.h b/include/srsran/phy/support/resource_grid_pool.h index 1e35194833..cc557a31c9 100644 --- a/include/srsran/phy/support/resource_grid_pool.h +++ b/include/srsran/phy/support/resource_grid_pool.h @@ -24,8 +24,14 @@ class resource_grid_pool /// Default destructor. virtual ~resource_grid_pool() = default; - /// \brief Allocates a unique resource grid. - /// \param [in] context Allocation context. + /// \brief Allocates a resource grid for the given context. + /// + /// Attempts to allocate a resource grid based on the provided allocation context. If the system is under high load, + /// the allocation might fail. When allocation fails, the reason for the failure is logged to the \e PHY logger + /// channel. + /// + /// \param [in] context The context for resource grid allocation. + /// \return A valid shared resource grid if the allocation is successful; otherwise, an invalid shared resource grid. virtual shared_resource_grid allocate_resource_grid(const resource_grid_context& context) = 0; }; diff --git a/lib/phy/support/resource_grid_pool_impl.cpp b/lib/phy/support/resource_grid_pool_impl.cpp index cd1fad4462..f2223173ff 100644 --- a/lib/phy/support/resource_grid_pool_impl.cpp +++ b/lib/phy/support/resource_grid_pool_impl.cpp @@ -9,7 +9,6 @@ */ #include "resource_grid_pool_impl.h" -#include "srsran/adt/optional.h" #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/phy/support/resource_grid.h" #include "srsran/phy/support/resource_grid_context.h" diff --git a/lib/phy/support/resource_grid_pool_impl.h b/lib/phy/support/resource_grid_pool_impl.h index f2867d2182..ff8304839b 100644 --- a/lib/phy/support/resource_grid_pool_impl.h +++ b/lib/phy/support/resource_grid_pool_impl.h @@ -35,10 +35,15 @@ class resource_grid_pool_impl : public resource_grid_pool, private shared_resour /// \brief Constructs a resource grid pool. /// \param async_executor_ Asynchronous housekeeping executor. /// \param grids_ Resource grids. - resource_grid_pool_impl(task_executor* async_executor_, std::vector> grids_); + resource_grid_pool_impl(task_executor* async_executor_, std::vector grids_); /// \brief The destructor checks that all resource grids have been returned to the pool. - ~resource_grid_pool_impl(); + /// + /// The resource grids that are still active in at least one scope get dereferenced if the pool is destructed prior + /// their context release. This triggers a segmentation fault signal. + /// + /// A fatal error is triggered if not all the resource grids have been returned to the pool. + ~resource_grid_pool_impl() override; // See resource_grid_pool interface for documentation. shared_resource_grid allocate_resource_grid(const resource_grid_context& context) override; @@ -59,7 +64,9 @@ class resource_grid_pool_impl : public resource_grid_pool, private shared_resour std::vector grids; /// Counts the resource grid requests. unsigned counter = 0; - /// Resource grid scope count. Zero means they are available. + /// \brief Resource grid scope count. + /// + /// A resource grid is available when the counter is equal to \c ref_counter_available. std::vector> grids_scope_count; /// Pool of resource grid zero set string for tracing. std::vector grids_str_zero; From 88963516522a628a37f78d9176e8c25e9006f9de Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 21 Aug 2024 10:20:25 +0200 Subject: [PATCH 332/407] phy: review rx buffer related --- include/srsran/phy/upper/unique_rx_buffer.h | 3 + .../pusch/pusch_decoder_empty_impl.cpp | 2 +- .../upper_phy_rx_symbol_handler_impl.cpp | 2 +- .../channel_processors/pxsch_bler_test.cpp | 2 +- .../pusch/pusch_decoder_vectortest.cpp | 2 +- .../phy/upper/rx_buffer_pool_test.cpp | 102 ++++++++++++------ 6 files changed, 78 insertions(+), 35 deletions(-) diff --git a/include/srsran/phy/upper/unique_rx_buffer.h b/include/srsran/phy/upper/unique_rx_buffer.h index 44bebdf1a7..c094b943f5 100644 --- a/include/srsran/phy/upper/unique_rx_buffer.h +++ b/include/srsran/phy/upper/unique_rx_buffer.h @@ -105,6 +105,9 @@ class unique_rx_buffer /// Returns true if the unique buffer contains a valid buffer. bool is_valid() const { return ptr != nullptr; } + /// Overload conversion to bool. + explicit operator bool() const noexcept { return is_valid(); } + /// Unlock and releases the buffer resources. void release() { diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.cpp index 8a5da7560d..81a6ef3baa 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_empty_impl.cpp @@ -48,7 +48,7 @@ void pusch_decoder_empty_impl::decoder_buffer_impl::new_data(span // Save inputs. rm_buffer = std::move(rm_buffer_); - srsran_assert(rm_buffer.is_valid(), "Invalid buffer."); + srsran_assert(rm_buffer, "Invalid buffer."); notifier = ¬ifier_; is_new_data = cfg.new_data; softbits_count = 0; diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp index 4a78c324c0..c66417ec79 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.cpp @@ -97,7 +97,7 @@ void upper_phy_rx_symbol_handler_impl::process_pusch(const uplink_processor::pus unique_rx_buffer buffer = rm_buffer_pool.reserve(slot, id, nof_codeblocks, new_data); // Skip processing if the buffer is not valid. The pool shall log the context and the reason of the failure. - if (!buffer.is_valid()) { + if (!buffer) { // Report data-related discarded result if shared channel data is present. if (pdu.pdu.codeword.has_value()) { ul_pusch_results_data discarded_results = diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp index 6f2d0cb1fc..22239dd702 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp @@ -376,7 +376,7 @@ class pxsch_bler_test // Get a receive buffer. unique_rx_buffer buffer = buffer_pool->get_pool().reserve(pusch_config.slot, trx_buffer_identifier(rnti, 0), nof_codeblocks, true); - report_error_if_not(buffer.is_valid(), "Invalid buffer."); + report_error_if_not(buffer, "Invalid buffer."); // Process PUSCH. pusch_processor_notifier_adaptor rx_notifier; diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp index b1134cc967..c3a85413c5 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp @@ -333,7 +333,7 @@ int main(int argc, char** argv) // Reserve buffer. unique_rx_buffer buffer = pool->get_pool().reserve({}, trx_buffer_identifier(0, 0), nof_codeblocks, true); - TESTASSERT(buffer.is_valid()); + TESTASSERT(buffer); // Reset code blocks CRCs. buffer.get().reset_codeblocks_crc(); diff --git a/tests/unittests/phy/upper/rx_buffer_pool_test.cpp b/tests/unittests/phy/upper/rx_buffer_pool_test.cpp index 6c62418f94..fa8aefacc7 100644 --- a/tests/unittests/phy/upper/rx_buffer_pool_test.cpp +++ b/tests/unittests/phy/upper/rx_buffer_pool_test.cpp @@ -11,7 +11,6 @@ #include "srsran/phy/upper/log_likelihood_ratio.h" #include "srsran/phy/upper/rx_buffer_pool.h" #include "srsran/phy/upper/unique_rx_buffer.h" -#include "srsran/support/executors/task_worker.h" #include "srsran/support/executors/task_worker_pool.h" #include @@ -24,6 +23,47 @@ bool operator==(span left, span right) return std::equal(left.begin(), left.end(), right.begin(), right.end()); } +/// \brief Tries to reserve buffers from a pool for a number of trials with a waiting time after every failed +/// reservation. +/// +/// This function is intended for being used when it is expect that a buffer shall be available but due memory +/// synchronization it could potentially fail. +/// +/// \param pool Receive buffer pool. +/// \param[in] slot Slot context in which the reservation occurs. +/// \param[in] id Buffer identifier. +/// \param[in] nof_codeblocks Indicates the number of codeblocks to reserve. +/// \param[in] new_data Set to true if the transmission is for new data. +/// \return A valid receive buffer if the reservation is successful before exhausting the number trials. Otherwise, an +/// invalid buffer. +inline unique_rx_buffer reserve_buffer_trial(rx_buffer_pool& pool, + const slot_point& slot, + trx_buffer_identifier id, + unsigned nof_codeblocks, + bool new_data) +{ + // Maximum number of trials. + static constexpr unsigned max_nof_trials = 10; + // Waiting time between failed reservations. + static constexpr std::chrono::milliseconds wait_time_between_trials(100); + + for (unsigned i_trial = 0; i_trial != max_nof_trials; ++i_trial) { + // Try to reserve buffer. + unique_rx_buffer rx_buffer = pool.reserve(slot, id, nof_codeblocks, new_data); + + // Return a valid buffer if the reservation is successful. + if (rx_buffer) { + return rx_buffer; + } + + // Wait time before trying again. + std::this_thread::sleep_for(wait_time_between_trials); + } + + // It did not reserve successfully a buffer. Return an invalid buffer. + return unique_rx_buffer(); +} + } // namespace srsran // Tests that the pool returns nullptr when the limit of buffers is reached. @@ -51,12 +91,12 @@ TEST(rx_buffer_pool, buffer_limit) // Reserve buffer, it shall not fail. buffers.emplace_back(pool->get_pool().reserve(slot, buffer_id, 1, true)); - ASSERT_TRUE(buffers.back().is_valid()); + ASSERT_TRUE(buffers.back()); } // Create one more buffer. No buffers are available. It must fail to reserve. trx_buffer_identifier buffer_id(static_cast(pool_config.nof_buffers), 0); - ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id, 1, true).is_valid()); + ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id, 1, true)); } // Tests that the pool returns nullptr when the limit of codeblocks is reached. @@ -80,11 +120,11 @@ TEST(rx_buffer_pool, codeblock_limit) // Reserve buffer with all the codeblocks, it shall not fail. trx_buffer_identifier buffer_id0(0x1234, 0x3); unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Create one more buffer. No codeblocks are available. It must fail to reserve. trx_buffer_identifier buffer_id1(0x1234, buffer_id0.get_harq() + 1); - ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true)); } // Tests that the pool frees reserved buffer. @@ -108,7 +148,7 @@ TEST(rx_buffer_pool, buffer_free) // Reserve buffer with all the codeblocks, it shall not fail. trx_buffer_identifier buffer_id0(0x1234, 0x3); unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Extract CRCs. span crc = buffer->get_codeblocks_crc(); @@ -120,15 +160,15 @@ TEST(rx_buffer_pool, buffer_free) std::fill(crc.begin(), crc.end(), true); // Unlock buffer. It is still reserved. - buffer = unique_rx_buffer(); + buffer.unlock(); // Reserve buffer with the same identifier. It shall not fail. buffer = pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, false); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Reserve buffer with a different identifier. It shall fail. trx_buffer_identifier buffer_id1(0x1234, buffer_id0.get_harq() + 1); - ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true)); // Extract CRCs. crc = buffer->get_codeblocks_crc(); @@ -144,7 +184,7 @@ TEST(rx_buffer_pool, buffer_free) // Reserve buffer with all the codeblocks, it shall not fail. buffer = pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Check the CRC are all false. ASSERT_TRUE(std::find(crc.begin(), crc.end(), true) == crc.end()); @@ -172,25 +212,25 @@ TEST(rx_buffer_pool, buffer_expire) // Reserve buffer with all the codeblocks, it shall not fail. trx_buffer_identifier buffer_id0(0x1234, 0x3); - ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true)); // Run slot and reserve the same buffer. slot += delay; pool->get_pool().run_slot(slot); - ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true)); // Run for each slot until it expires. do { // Try to reserve another buffer. As there are no buffers available it shall fail. trx_buffer_identifier buffer_id1(0x1234, buffer_id0.get_harq() + 1); - ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true)); ++slot; pool->get_pool().run_slot(slot); } while (slot.system_slot() < pool_config.expire_timeout_slots + delay); // After the first buffer expired, buffer reservation shall not fail. trx_buffer_identifier buffer_id2(0x1234, buffer_id0.get_harq() + 2); - ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id2, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_TRUE(reserve_buffer_trial(pool->get_pool(), slot, buffer_id2, pool_config.nof_codeblocks, true)); } // Tests that the pool renews buffer expiration if they are locked. @@ -216,7 +256,7 @@ TEST(rx_buffer_pool, buffer_renew_expire) // Reserve buffer with all the codeblocks, it shall not fail. trx_buffer_identifier buffer_id0(0x1234, 0x3); unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Advance slots. As the buffer is locked, the expiration shall be renewed. slot += expire_timeout_slots; @@ -224,24 +264,24 @@ TEST(rx_buffer_pool, buffer_renew_expire) // Try to get the same buffer. It must fail as the buffer is locked. unique_rx_buffer locked_buffer = pool->get_pool().reserve(slot, buffer_id0, pool_config.nof_codeblocks, true); - ASSERT_FALSE(locked_buffer.is_valid()); + ASSERT_FALSE(locked_buffer); // Unlock buffer. - buffer = unique_rx_buffer(); + buffer.unlock(); // Run for each slot until it expires. do { // Try to reserve another buffer. As there are no buffers available it shall fail. trx_buffer_identifier buffer_id1(0x1234, buffer_id0.get_harq() + 1); unique_rx_buffer invalid_buffer = pool->get_pool().reserve(slot, buffer_id1, pool_config.nof_codeblocks, true); - ASSERT_FALSE(invalid_buffer.is_valid()); + ASSERT_FALSE(invalid_buffer); ++slot; pool->get_pool().run_slot(slot); } while (slot.system_slot() < pool_config.expire_timeout_slots + expire_timeout_slots); // After the first buffer expired, buffer reservation shall not fail. trx_buffer_identifier buffer_id2(0x1234, buffer_id0.get_harq() + 2); - ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id2, pool_config.nof_codeblocks, true).is_valid()); + ASSERT_TRUE(pool->get_pool().reserve(slot, buffer_id2, pool_config.nof_codeblocks, true)); } // Tests that the pool renews buffer expiration if they are locked. @@ -267,7 +307,7 @@ TEST(rx_buffer_pool, buffer_resize) // Reserve buffer with max_nof_codeblocks - 1 codeblocks, it shall not fail. trx_buffer_identifier buffer_id0(0x1234, 0x3); unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id0, max_nof_codeblocks, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Check the number of codeblock matches. ASSERT_EQ(buffer.get().get_nof_codeblocks(), max_nof_codeblocks); @@ -277,7 +317,7 @@ TEST(rx_buffer_pool, buffer_resize) std::fill(crc.begin(), crc.end(), true); // Unlock the buffer. - buffer = unique_rx_buffer(); + buffer.unlock(); // Reserve the same buffer with more codeblocks. buffer = pool->get_pool().reserve(slot, buffer_id0, max_nof_codeblocks - 1, true); @@ -313,16 +353,16 @@ TEST(rx_buffer_pool, buffer_resize_false_retransmission) // Reserve buffer with nof_codeblocks - 1 codeblocks, it shall not fail. trx_buffer_identifier buffer_id0(0x1234, 0x3); unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id0, nof_codeblocks, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // Check the number of codeblock matches. ASSERT_EQ(buffer.get().get_nof_codeblocks(), nof_codeblocks); // Unlock the buffer. - buffer = unique_rx_buffer(); + buffer.unlock(); // Reserve the same buffer with less codeblocks, the buffer shall be invalid. - ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id0, nof_codeblocks - 1, false).is_valid()); + ASSERT_FALSE(pool->get_pool().reserve(slot, buffer_id0, nof_codeblocks - 1, false)); } // Tests that the pool returns an invalid buffer upon a retransmission without a previous reservation. @@ -348,7 +388,7 @@ TEST(rx_buffer_pool, fresh_false_retransmission) // Reserve buffer as retransmission without a previous reservation, the buffer shall be invalid. trx_buffer_identifier buffer_id0(0x1234, 0x3); unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id0, nof_codeblocks, false); - ASSERT_FALSE(buffer.is_valid()); + ASSERT_FALSE(buffer); } // Tests buffer soft bits contents persists between retransmissions. @@ -385,7 +425,7 @@ TEST(rx_buffer_pool, buffer_contents) { // Reserve buffer, it shall not fail. unique_rx_buffer rm_buffer = pool->get_pool().reserve(slot, buffer_id, nof_cb_x_buffer, true); - ASSERT_TRUE(rm_buffer.is_valid()); + ASSERT_TRUE(rm_buffer); // For each codeblock... for (unsigned cb_id = 0; cb_id != nof_cb_x_buffer; ++cb_id) { @@ -413,7 +453,7 @@ TEST(rx_buffer_pool, buffer_contents) // Reserve buffer, it shall not fail. unique_rx_buffer buffer = pool->get_pool().reserve(slot, buffer_id, nof_cb_x_buffer, true); - ASSERT_TRUE(buffer.is_valid()); + ASSERT_TRUE(buffer); // For each codeblock... for (unsigned cb_id = 0; cb_id != nof_cb_x_buffer; ++cb_id) { @@ -467,7 +507,7 @@ TEST(rx_buffer_pool, reserve_after_stop) pool->get_pool().reserve(slot, trx_buffer_identifier(0, 0), pool_config.nof_codeblocks, true); // The buffer must be invalid. - ASSERT_FALSE(buffer.is_valid()); + ASSERT_FALSE(buffer); } // Tests buffer pool waits to stop. @@ -505,7 +545,7 @@ TEST(rx_buffer_pool, wait_to_stop) async_unlock.join(); // The buffer must be invalid. - ASSERT_FALSE(buffer.is_valid()); + ASSERT_FALSE(buffer); } TEST(rx_buffer_pool, concurrent) @@ -541,10 +581,10 @@ TEST(rx_buffer_pool, concurrent) pool->get_pool().reserve(slot, trx_buffer_identifier(0x1234, i_buffer), nof_cb_x_buffer, true); // The reservation should be successful for the first time. - ASSERT_TRUE((i_repetition > 0) || buffer.is_valid()); + ASSERT_TRUE((i_repetition > 0) || buffer); // Release or unlock buffer asynchronously in the worker pool. - if (buffer.is_valid()) { + if (buffer) { if (i_repetition & 1) { ASSERT_TRUE(release_worker_pool.push_task([buffer2 = std::move(buffer)]() mutable { buffer2.unlock(); })); } else { From ed6546470e1492db7e541a17f963f2bc4425bb71 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 27 Aug 2024 11:20:36 +0200 Subject: [PATCH 333/407] nru: simplify (deep)copy of optional members --- include/srsran/nru/nru_message.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/srsran/nru/nru_message.h b/include/srsran/nru/nru_message.h index 4097cd87ec..3f3b472b90 100644 --- a/include/srsran/nru/nru_message.h +++ b/include/srsran/nru/nru_message.h @@ -223,12 +223,8 @@ struct nru_ul_message { } copy.t_pdu = std::move(chain.value()); } - if (data_delivery_status.has_value()) { - copy.data_delivery_status = data_delivery_status.value(); - } - if (assistance_information.has_value()) { - copy.assistance_information = assistance_information.value(); - } + copy.data_delivery_status = data_delivery_status; + copy.assistance_information = assistance_information; return copy; } From d46286d6c44807a7a37d999a12b54435280459b2 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Aug 2024 13:49:37 +0200 Subject: [PATCH 334/407] ci: create tag self retry --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 222dd0f470..916c33d9d1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -472,6 +472,7 @@ create-tags: create_tag "${name}_$(date -u +"%Y.%m.%d")" done needs: [] + retry: 2 ################################################################################ # Enable / Disable pipelines From cd5fe21345bf092d943e77f29bace0df644f1721 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Aug 2024 10:27:05 +0200 Subject: [PATCH 335/407] ci,e2e: clean up resources when cancelling --- .gitlab/ci/e2e.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 245283b28b..609c2f15c1 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -176,6 +176,8 @@ e2e request and config validation: echo "${E2E_CMD}" eval $E2E_CMD after_script: + # Remove any existing retina resource for this group + - retina-delete-orchestration-network --user-name ^ci_${GROUP} --regex # Push test metrics - | find . -iname "test_metrics.csv" -exec \ @@ -694,3 +696,5 @@ retina post: extends: .demolition dependencies: - load retina variables + when: manual + allow_failure: true From 8660b15927a27da85226b586295914f4d6cc923c Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Aug 2024 13:58:54 +0200 Subject: [PATCH 336/407] ci: use new dpdk lts versions --- .github/workflows/docker.yml | 8 ++++---- .gitlab/ci/build.yml | 22 +++++++++++----------- .gitlab/ci/builders.yml | 28 ++++++++++++++-------------- .gitlab/ci/docker.yml | 2 +- .gitlab/ci/e2e/.env | 2 +- .gitlab/run_viavi_pipeline.py | 2 +- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6440c0ca50..7c4fc34921 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -40,7 +40,7 @@ jobs: MARCH: x86-64-v3 PLATFORM: amd64 LIB: dpdk - LIB_VERSION: "23.11" + LIB_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ - TAGNAME: split72_release_with_debug_avx2 @@ -49,7 +49,7 @@ jobs: MARCH: x86-64-v3 PLATFORM: amd64 LIB: dpdk - LIB_VERSION: "23.11" + LIB_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ # AMD AVX512 @@ -58,7 +58,7 @@ jobs: MARCH: x86-64-v4 PLATFORM: amd64 LIB: dpdk - LIB_VERSION: "23.11" + LIB_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ - TAGNAME: split72_release_with_debug_avx512 @@ -67,7 +67,7 @@ jobs: MARCH: x86-64-v4 PLATFORM: amd64 LIB: dpdk - LIB_VERSION: "23.11" + LIB_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ # --> split8 diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index d640d3417f..715532a83d 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -419,7 +419,7 @@ variables: ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" ASSERT_LEVEL: PARANOID - DPDK_VERSION: "23.11_avx2" + DPDK_VERSION: "23.11.1_avx2" MARCH: x86-64-v3 tags: ["${AMD64_AVX2_TAG}"] @@ -1119,13 +1119,13 @@ ubuntu dpdk: matrix: - OS: ubuntu-24.04 COMPILER: [gcc, clang] - DPDK_VERSION: ["23.11_avx2"] + DPDK_VERSION: ["23.11.1_avx2"] - OS: ubuntu-23.10 COMPILER: [gcc, clang] - DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] + DPDK_VERSION: ["22.11.6_avx2", "23.11.1_avx2"] - OS: ubuntu-22.04 COMPILER: [gcc, clang] - DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] + DPDK_VERSION: ["22.11.6_avx2", "23.11.1_avx2"] ################### # Alternative OSs # @@ -1588,7 +1588,7 @@ ubuntu-22.04 amd64 avx2 dpdk: matrix: - OS: ubuntu-22.04 <<: *basic_combinations_dpdk - DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] + DPDK_VERSION: ["22.11.6_avx2", "23.11.1_avx2"] MARCH: x86-64-v3 ubuntu-22.04 amd64 avx512 dpdk: @@ -1603,7 +1603,7 @@ ubuntu-22.04 amd64 avx512 dpdk: matrix: - OS: ubuntu-22.04 <<: *basic_combinations_dpdk - DPDK_VERSION: ["22.11.3_avx512", "23.11_avx512"] + DPDK_VERSION: ["22.11.6_avx512", "23.11.1_avx512"] MARCH: x86-64-v4 ubuntu-23.10 amd64 avx2 dpdk: @@ -1618,7 +1618,7 @@ ubuntu-23.10 amd64 avx2 dpdk: matrix: - OS: ubuntu-23.10 <<: *basic_combinations_dpdk - DPDK_VERSION: ["22.11.3_avx2", "23.11_avx2"] + DPDK_VERSION: ["22.11.6_avx2", "23.11.1_avx2"] MARCH: x86-64-v3 ubuntu-23.10 amd64 avx512 dpdk: @@ -1633,7 +1633,7 @@ ubuntu-23.10 amd64 avx512 dpdk: matrix: - OS: ubuntu-23.10 <<: *basic_combinations_dpdk - DPDK_VERSION: ["22.11.3_avx512", "23.11_avx512"] + DPDK_VERSION: ["22.11.6_avx512", "23.11.1_avx512"] MARCH: x86-64-v4 ubuntu-24.04 amd64 avx2 dpdk: @@ -1648,7 +1648,7 @@ ubuntu-24.04 amd64 avx2 dpdk: matrix: - OS: ubuntu-24.04 <<: *basic_combinations_dpdk - DPDK_VERSION: "23.11_avx2" + DPDK_VERSION: "23.11.1_avx2" MARCH: x86-64-v3 ubuntu-24.04 amd64 avx512 dpdk: @@ -1663,7 +1663,7 @@ ubuntu-24.04 amd64 avx512 dpdk: matrix: - OS: ubuntu-24.04 <<: *basic_combinations_dpdk - DPDK_VERSION: "23.11_avx512" + DPDK_VERSION: "23.11.1_avx512" MARCH: x86-64-v4 ############# @@ -1796,7 +1796,7 @@ basic avx512 dpdk: ENABLE_UHD: "False" ENABLE_ZEROMQ: "False" ENABLE_DPDK: "True" - DPDK_VERSION: "23.11_avx512" + DPDK_VERSION: "23.11.1_avx512" MARCH: x86-64-v4 FORCE_DEBUG_INFO: "True" ASSERT_LEVEL: MINIMAL diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index eefe1dfeb1..9de7157277 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -222,16 +222,16 @@ ubuntu-uhd-builder arm64: matrix: - &dpdk_2204_no_isa_matrix os_version: "22.04" - dpdk_version: ["22.11.3", "23.11"] + dpdk_version: ["22.11.6", "23.11.1"] - &dpdk_2204_matrix os_version: "22.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] + dpdk_version: ["21.08", "22.11.6", "23.11.1"] - &dpdk_2310_matrix os_version: "23.10" - dpdk_version: ["22.11.3", "23.11"] + dpdk_version: ["22.11.6", "23.11.1"] - &dpdk_2404_matrix os_version: "24.04" - dpdk_version: ["23.11"] + dpdk_version: ["23.11.1"] ubuntu-dpdk-builder no isa: extends: .ubuntu-dpdk-builder @@ -407,17 +407,17 @@ image-build-publish [ubuntu, 22.04, amd64]: parallel: matrix: - os_version: "22.04" - dpdk_version: ["22.11.3", "23.11"] + dpdk_version: ["22.11.6", "23.11.1"] - job: ubuntu-dpdk-builder avx2 parallel: matrix: - os_version: "22.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] + dpdk_version: ["21.08", "22.11.6", "23.11.1"] - job: ubuntu-dpdk-builder avx512 parallel: matrix: - os_version: "22.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] + dpdk_version: ["21.08", "22.11.6", "23.11.1"] alternative-tag [ubuntu, 22.04, amd64]: extends: @@ -449,7 +449,7 @@ image-build-publish [ubuntu, 22.04, arm64]: parallel: matrix: - os_version: "22.04" - dpdk_version: ["21.08", "22.11.3", "23.11"] + dpdk_version: ["21.08", "22.11.6", "23.11.1"] alternative-tag [ubuntu, 22.04, arm64]: extends: @@ -499,12 +499,12 @@ image-build-publish [ubuntu, 23.10, amd64]: parallel: matrix: - os_version: "23.10" - dpdk_version: ["22.11.3", "23.11"] + dpdk_version: ["22.11.6", "23.11.1"] - job: ubuntu-dpdk-builder avx512 parallel: matrix: - os_version: "23.10" - dpdk_version: ["22.11.3", "23.11"] + dpdk_version: ["22.11.6", "23.11.1"] alternative-tag [ubuntu, 23.10, amd64]: extends: @@ -536,7 +536,7 @@ image-build-publish [ubuntu, 23.10, arm64]: parallel: matrix: - os_version: "23.10" - dpdk_version: ["22.11.3", "23.11"] + dpdk_version: ["22.11.6", "23.11.1"] alternative-tag [ubuntu, 23.10, arm64]: extends: @@ -581,12 +581,12 @@ image-build-publish [ubuntu, 24.04, amd64]: parallel: matrix: - os_version: "24.04" - dpdk_version: ["23.11"] + dpdk_version: ["23.11.1"] - job: ubuntu-dpdk-builder avx512 parallel: matrix: - os_version: "24.04" - dpdk_version: ["23.11"] + dpdk_version: ["23.11.1"] alternative-tag [ubuntu, 24.04, amd64]: extends: @@ -613,7 +613,7 @@ image-build-publish [ubuntu, 24.04, arm64]: parallel: matrix: - os_version: "24.04" - dpdk_version: ["23.11"] + dpdk_version: ["23.11.1"] alternative-tag [ubuntu, 24.04, arm64]: extends: diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index 4c6cb89716..f5b5707c75 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -43,7 +43,7 @@ variables: .dpdk_params: variables: &dpdk_params LIB: dpdk - LIB_VERSION: "23.11" + LIB_VERSION: "23.11.1" ################################################################################ # Static diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index e2dbb38d9f..5874c7dfd0 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -7,7 +7,7 @@ SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.7.0 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.3 -DPDK_VERSION=23.11 +DPDK_VERSION=23.11.1 ZMQ_HOSTLABEL_0=kubernetes.io/hostname=k8s-worker-vm2 ZMQ_HOSTLABEL_1=kubernetes.io/hostname=skinny-beast AMARISOFT_TXRX_BINARY_PATH=../../build_trx_srsran/libtrx_srsran.so diff --git a/.gitlab/run_viavi_pipeline.py b/.gitlab/run_viavi_pipeline.py index 2612f9c97b..74f363516e 100644 --- a/.gitlab/run_viavi_pipeline.py +++ b/.gitlab/run_viavi_pipeline.py @@ -54,7 +54,7 @@ def main(): MAKE_ARGS = "-j6" BUILD_ARGS = '-DCMAKE_BUILD_TYPE=Release -DFORCE_DEBUG_INFO=True -DENABLE_UHD=False -DENABLE_DPDK=True -DENABLE_ZEROMQ=False -DMARCH="x86-64-v4"' - DPDK_VERSION = "23.11_avx512" + DPDK_VERSION = "23.11.1_avx512" TESTBED = "viavi" MARKERS = "viavi_manual" From d16d3e931167b41017eeb08f7a1d92d86e7a4feb Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Aug 2024 14:03:32 +0200 Subject: [PATCH 337/407] ci: new uhd version support --- .github/workflows/docker.yml | 4 +-- .gitlab/ci/build.yml | 6 ++--- .gitlab/ci/builders.yml | 47 +++++++++++++++--------------------- .gitlab/ci/docker.yml | 2 +- docker/Dockerfile | 2 +- 5 files changed, 27 insertions(+), 34 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7c4fc34921..c93644cb2d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -77,7 +77,7 @@ jobs: MARCH: x86-64-v3 PLATFORM: amd64 LIB: uhd - LIB_VERSION: "4.6.0.0" + LIB_VERSION: "4.7.0.0" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ - TAGNAME: split8_release_with_debug_avx2 @@ -86,7 +86,7 @@ jobs: MARCH: x86-64-v3 PLATFORM: amd64 LIB: uhd - LIB_VERSION: "4.6.0.0" + LIB_VERSION: "4.7.0.0" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ env: diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 715532a83d..fd864a886e 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -1397,13 +1397,13 @@ build uhd alt: matrix: - OS: ubuntu-24.04 COMPILER: [gcc, clang] - UHD_VERSION: ["4.6.0.0"] + UHD_VERSION: ["4.7.0.0", "4.6.0.0"] - OS: ubuntu-23.10 COMPILER: [gcc, clang] - UHD_VERSION: ["4.6.0.0", "4.4.0.0"] + UHD_VERSION: ["4.7.0.0", "4.6.0.0", "4.4.0.0"] - OS: ubuntu-22.04 COMPILER: [gcc, clang] - UHD_VERSION: ["4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] + UHD_VERSION: ["4.7.0.0", "4.6.0.0", "4.4.0.0", "4.3.0.0", "4.1.0.5"] # Build + unit tests combinations diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index 9de7157277..5cd459fa42 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -110,25 +110,12 @@ tox python in builder: expire_in: 8 hours parallel: matrix: - - &uhd_2204_matrix - os_version: "22.04" - uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0"] # "4.1.0.5" default - - &uhd_2310_matrix - os_version: "23.10" - uhd_version: ["4.6.0.0"] # "4.4.0.0" default - # - os_version: "24.04" - # uhd_version: [] # "4.6.0.0" default - -ubuntu-uhd-builder no isa: - extends: .ubuntu-uhd-builder - tags: - - amd64 - variables: - arch_name: amd64 - target_arch: x86-64 # x86-64-vX not supported in compilers' versions - parallel: - matrix: - - *uhd_2204_matrix + - os_version: "22.04" + uhd_version: ["4.7.0.0", "4.6.0.0", "4.4.0.0", "4.3.0.0"] # "4.1.0.5" default + - os_version: "23.10" + uhd_version: ["4.7.0.0", "4.6.0.0"] # "4.4.0.0" default + - os_version: "24.04" + uhd_version: ["4.7.0.0"] # "4.6.0.0" default ubuntu-uhd-builder avx2: extends: .ubuntu-uhd-builder @@ -137,10 +124,6 @@ ubuntu-uhd-builder avx2: variables: arch_name: amd64 target_arch: x86-64-v3 - parallel: - matrix: - - *uhd_2204_matrix - - *uhd_2310_matrix ubuntu-uhd-builder arm64: extends: .ubuntu-uhd-builder @@ -402,7 +385,7 @@ image-build-publish [ubuntu, 22.04, amd64]: parallel: matrix: - os_version: "22.04" - uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0"] + uhd_version: ["4.7.0.0", "4.6.0.0", "4.4.0.0", "4.3.0.0"] - job: ubuntu-dpdk-builder no isa parallel: matrix: @@ -444,7 +427,7 @@ image-build-publish [ubuntu, 22.04, arm64]: parallel: matrix: - os_version: "22.04" - uhd_version: ["4.6.0.0", "4.4.0.0", "4.3.0.0"] + uhd_version: ["4.7.0.0", "4.6.0.0", "4.4.0.0", "4.3.0.0"] - job: ubuntu-dpdk-builder arm64 parallel: matrix: @@ -494,7 +477,7 @@ image-build-publish [ubuntu, 23.10, amd64]: parallel: matrix: - os_version: "23.10" - uhd_version: ["4.6.0.0"] # "4.4.0.0" default + uhd_version: ["4.7.0.0", "4.6.0.0"] # "4.4.0.0" default - job: ubuntu-dpdk-builder avx2 parallel: matrix: @@ -531,7 +514,7 @@ image-build-publish [ubuntu, 23.10, arm64]: parallel: matrix: - os_version: "23.10" - uhd_version: ["4.6.0.0"] # "4.4.0.0" default + uhd_version: ["4.7.0.0", "4.6.0.0"] # "4.4.0.0" default - job: ubuntu-dpdk-builder arm64 parallel: matrix: @@ -577,6 +560,11 @@ image-build-publish [ubuntu, 24.04, amd64]: PLATFORM: amd64 needs: - builder version + - job: ubuntu-uhd-builder avx2 + parallel: + matrix: + - os_version: "24.04" + uhd_version: ["4.7.0.0"] # "4.6.0.0" default - job: ubuntu-dpdk-builder avx2 parallel: matrix: @@ -609,6 +597,11 @@ image-build-publish [ubuntu, 24.04, arm64]: PLATFORM: arm64 needs: - builder version + - job: ubuntu-uhd-builder arm64 + parallel: + matrix: + - os_version: "24.04" + uhd_version: ["4.7.0.0"] # "4.6.0.0" default - job: ubuntu-dpdk-builder arm64 parallel: matrix: diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index f5b5707c75..95934ecf42 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -38,7 +38,7 @@ variables: .uhd_params: variables: &uhd_params LIB: uhd - LIB_VERSION: "4.6.0.0" + LIB_VERSION: "4.7.0.0" .dpdk_params: variables: &dpdk_params diff --git a/docker/Dockerfile b/docker/Dockerfile index 966d09e63a..8e3d2e529b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -17,7 +17,7 @@ ARG OS_VERSION=24.04 ARG LIB=uhd -ARG LIB_VERSION=4.6.0.0 +ARG LIB_VERSION=4.7.0.0 ARG MARCH=native ARG NUM_CORES="" From 298feef0f95da19db6b24a7368e35a5de59d420f Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Aug 2024 10:26:53 +0200 Subject: [PATCH 338/407] ci: deprecate clang 11 support --- .gitlab/ci/build.yml | 44 -------------------------------------- .gitlab/ci/builders.yml | 47 +---------------------------------------- 2 files changed, 1 insertion(+), 90 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index fd864a886e..9740f23265 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -1214,50 +1214,6 @@ debian 12 amd64 avx512: <<: *basic_combinations MARCH: x86-64-v4 -debian 11 amd64 native: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Alternative OSs/ - when: delayed - start_in: 120 minutes - interruptible: false - tags: ["${AMD64_TAG}"] - parallel: - matrix: - - OS: debian-11 - ENABLE_WERROR: "False" - <<: *basic_combinations - -debian 11 amd64 avx2: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Alternative OSs/ - when: delayed - start_in: 150 minutes - interruptible: false - tags: ["${AMD64_AVX2_TAG}"] - parallel: - matrix: - - OS: debian-11 - ENABLE_WERROR: "False" - <<: *basic_combinations - MARCH: x86-64-v2 - -debian 11 amd64 avx512: - extends: .build_and_unit - rules: - - if: $CI_DESCRIPTION =~ /Alternative OSs/ - when: delayed - start_in: 60 minutes - interruptible: false - tags: ["${AMD64_AVX512_TAG}"] - parallel: - matrix: - - OS: debian-11 - ENABLE_WERROR: "False" - <<: *basic_combinations - MARCH: x86-64-v4 - ########## # Weekly # ########## diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index 5cd459fa42..374245258a 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -646,56 +646,11 @@ image-build-publish [debian]: PLATFORM: amd64 parallel: matrix: - - OS_VERSION: ["11", "12"] + - OS_VERSION: "12" PLATFORM: [amd64, arm64] needs: - builder version -alternative-tag [debian, 11, amd64]: - extends: - - .alternative-tag - variables: - OS_NAME: debian - OS_VERSION: "11" - VERSION: ${DOCKER_BUILDER_VERSION}-amd64 - needs: - - builder version - - job: image-build-publish [debian] - parallel: - matrix: - - OS_VERSION: "11" - PLATFORM: amd64 - -alternative-tag [debian, 11, arm64]: - extends: - - .alternative-tag - variables: - OS_NAME: debian - OS_VERSION: "11" - VERSION: ${DOCKER_BUILDER_VERSION}-arm64 - needs: - - builder version - - job: image-build-publish [debian] - parallel: - matrix: - - OS_VERSION: "11" - PLATFORM: arm64 - -manifest [debian, 11]: - extends: .manifest - variables: - OS_NAME: debian - OS_VERSION: "11" - needs: - - builder version - - job: alternative-tag [debian, 11, amd64] - optional: false - - job: alternative-tag [debian, 11, arm64] - optional: false - parallel: - matrix: - - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] - alternative-tag [debian, 12, amd64]: extends: - .alternative-tag From 1576540c071b30ebf47debbc987dd30153d49cfe Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Aug 2024 14:38:10 +0200 Subject: [PATCH 339/407] ci: ubuntu 24.10 support --- .gitlab/ci/build.yml | 133 +++++++++++++++++++++++--- .gitlab/ci/builders.yml | 84 ++++++++++++++++ .gitlab/ci/builders/debian/Dockerfile | 2 +- 3 files changed, 205 insertions(+), 14 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 9740f23265..865739fd1c 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -33,6 +33,7 @@ variables: OS: description: Operating system options: + - "ubuntu-24.10" - "ubuntu-24.04" - "ubuntu-23.10" - "ubuntu-22.04" @@ -928,6 +929,7 @@ package: - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" + - OS_VERSION: "24.10" needs: [] install-package: @@ -946,6 +948,7 @@ install-package: - OS_VERSION: "22.04" - OS_VERSION: "23.10" - OS_VERSION: "24.04" + - OS_VERSION: "24.10" needs: - package @@ -971,8 +974,8 @@ export on amd64: tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: - - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] - - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v3 export on amd64 avx512: @@ -980,11 +983,25 @@ export on amd64 avx512: tags: ["${AMD64_AVX512_TAG}"] parallel: matrix: - - OS: [ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10, ubuntu-22.04] MARCH: x86-64-v4 # Build + unit tests combinations +ubuntu-24.10 amd64 avx2: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + when: delayed + start_in: 210 minutes + interruptible: false + tags: ["${AMD64_AVX2_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations + MARCH: x86-64-v3 + ubuntu-24.04 amd64 avx2: extends: .build_and_unit rules: @@ -1117,6 +1134,9 @@ ubuntu dpdk: tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: + - OS: ubuntu-24.10 + COMPILER: [gcc, clang] + DPDK_VERSION: ["23.11.1_avx2"] - OS: ubuntu-24.04 COMPILER: [gcc, clang] DPDK_VERSION: ["23.11.1_avx2"] @@ -1231,7 +1251,7 @@ debian 12 amd64 avx512: parallel: matrix: # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan COMPILER: [gcc, clang] ENABLE_TSAN: "True" @@ -1241,12 +1261,12 @@ debian 12 amd64 avx512: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang ENABLE_ASAN: "True" TEST_MODE: default - - OS: [ubuntu-24.04] + - OS: [ubuntu-24.10, ubuntu-24.04] SANITIZER: valgrind COMPILER: gcc TEST_MODE: valgrind @@ -1257,7 +1277,7 @@ sanitizers amd64 native: parallel: matrix: # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan COMPILER: [gcc, clang] ENABLE_TSAN: "True" @@ -1267,7 +1287,7 @@ sanitizers amd64 native: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang ENABLE_ASAN: "True" @@ -1282,7 +1302,7 @@ sanitizers amd64 avx2: parallel: matrix: # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan COMPILER: [gcc, clang] ENABLE_TSAN: "True" @@ -1292,12 +1312,12 @@ sanitizers amd64 avx2: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang ENABLE_ASAN: "True" TEST_MODE: default - - OS: [ubuntu-24.04] + - OS: [ubuntu-24.10, ubuntu-24.04] SANITIZER: valgrind COMPILER: gcc TEST_MODE: valgrind @@ -1310,7 +1330,7 @@ sanitizers amd64 avx512: parallel: matrix: # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: tsan COMPILER: [gcc, clang] ENABLE_TSAN: "True" @@ -1320,7 +1340,7 @@ sanitizers amd64 avx512: COMPILER: [gcc, clang] ENABLE_ASAN: "True" TEST_MODE: default - - OS: [ubuntu-24.04, ubuntu-23.10] + - OS: [ubuntu-24.10, ubuntu-24.04, ubuntu-23.10] SANITIZER: asan COMPILER: clang ENABLE_ASAN: "True" @@ -1351,6 +1371,9 @@ build uhd alt: tags: ["${AMD64_AVX2_TAG}"] parallel: matrix: + - OS: ubuntu-24.10 + COMPILER: [gcc, clang] + UHD_VERSION: ["4.7.0.0"] - OS: ubuntu-24.04 COMPILER: [gcc, clang] UHD_VERSION: ["4.7.0.0", "4.6.0.0"] @@ -1363,6 +1386,60 @@ build uhd alt: # Build + unit tests combinations +ubuntu-24.10 amd64 native: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + when: delayed + start_in: 90 minutes + interruptible: false + tags: ["${AMD64_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations + +ubuntu-24.10 amd64 avx512: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + when: delayed + start_in: 90 minutes + interruptible: false + tags: ["${AMD64_AVX512_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations + MARCH: x86-64-v4 + +ubuntu-24.10 arm native: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + when: delayed + start_in: 90 minutes + interruptible: false + tags: ["${ARM64_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations + +ubuntu-24.10 arm neon: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + when: delayed + start_in: 90 minutes + interruptible: false + tags: ["${ARM64_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations + MARCH: armv8.2-a+crypto+fp16+dotprod + ubuntu-24.04 amd64 native: extends: .build_and_unit rules: @@ -1622,6 +1699,36 @@ ubuntu-24.04 amd64 avx512 dpdk: DPDK_VERSION: "23.11.1_avx512" MARCH: x86-64-v4 +ubuntu-24.10 amd64 avx2 dpdk: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + when: delayed + start_in: 420 minutes + interruptible: false + tags: ["${AMD64_AVX2_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations_dpdk + DPDK_VERSION: "23.11.1_avx2" + MARCH: x86-64-v3 + +ubuntu-24.10 amd64 avx512 dpdk: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + when: delayed + start_in: 450 minutes + interruptible: false + tags: ["${AMD64_AVX512_TAG}"] + parallel: + matrix: + - OS: ubuntu-24.10 + <<: *basic_combinations_dpdk + DPDK_VERSION: "23.11.1_avx512" + MARCH: x86-64-v4 + ############# # Run check # ############# diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index 374245258a..25695fcd1d 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -116,6 +116,8 @@ tox python in builder: uhd_version: ["4.7.0.0", "4.6.0.0"] # "4.4.0.0" default - os_version: "24.04" uhd_version: ["4.7.0.0"] # "4.6.0.0" default + # - os_version: "24.10" + # uhd_version: [] # "4.7.0.0" default ubuntu-uhd-builder avx2: extends: .ubuntu-uhd-builder @@ -215,6 +217,9 @@ ubuntu-uhd-builder arm64: - &dpdk_2404_matrix os_version: "24.04" dpdk_version: ["23.11.1"] + - &dpdk_2410_matrix + os_version: "24.10" + dpdk_version: ["23.11.1"] ubuntu-dpdk-builder no isa: extends: .ubuntu-dpdk-builder @@ -240,6 +245,7 @@ ubuntu-dpdk-builder avx2: - *dpdk_2204_matrix - *dpdk_2310_matrix - *dpdk_2404_matrix + - *dpdk_2410_matrix ubuntu-dpdk-builder avx512: extends: .ubuntu-dpdk-builder @@ -254,6 +260,7 @@ ubuntu-dpdk-builder avx512: - *dpdk_2204_matrix - *dpdk_2310_matrix - *dpdk_2404_matrix + - *dpdk_2410_matrix ubuntu-dpdk-builder arm64: extends: .ubuntu-dpdk-builder @@ -634,6 +641,83 @@ manifest [ubuntu, 24.04]: matrix: - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] +################################################################################ +# Ubuntu 24.10 +################################################################################ +image-build-publish [ubuntu, 24.10, amd64]: + extends: + - .image-build-publish + variables: + OS_FAMILY: debian + OS_NAME: ubuntu + OS_VERSION: "24.10" + PLATFORM: amd64 + needs: + - builder version + - job: ubuntu-dpdk-builder avx2 + parallel: + matrix: + - os_version: "24.10" + dpdk_version: ["23.11.1"] + - job: ubuntu-dpdk-builder avx512 + parallel: + matrix: + - os_version: "24.10" + dpdk_version: ["23.11.1"] + +alternative-tag [ubuntu, 24.10, amd64]: + extends: + - .alternative-tag + variables: + OS_NAME: ubuntu + OS_VERSION: "24.10" + VERSION: ${DOCKER_BUILDER_VERSION}-amd64 + needs: + - builder version + - image-build-publish [ubuntu, 24.10, amd64] + +image-build-publish [ubuntu, 24.10, arm64]: + extends: + - .image-build-publish + variables: + OS_FAMILY: debian + OS_NAME: ubuntu + OS_VERSION: "24.10" + PLATFORM: arm64 + needs: + - builder version + - job: ubuntu-dpdk-builder arm64 + parallel: + matrix: + - os_version: "24.10" + dpdk_version: ["23.11.1"] + +alternative-tag [ubuntu, 24.10, arm64]: + extends: + - .alternative-tag + variables: + OS_NAME: ubuntu + OS_VERSION: "24.10" + VERSION: ${DOCKER_BUILDER_VERSION}-arm64 + needs: + - builder version + - image-build-publish [ubuntu, 24.10, arm64] + +manifest [ubuntu, 24.10]: + extends: .manifest + variables: + OS_NAME: ubuntu + OS_VERSION: "24.10" + needs: + - builder version + - job: alternative-tag [ubuntu, 24.10, amd64] + optional: false + - job: alternative-tag [ubuntu, 24.10, arm64] + optional: false + parallel: + matrix: + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + ################################################################################ # Debian ################################################################################ diff --git a/.gitlab/ci/builders/debian/Dockerfile b/.gitlab/ci/builders/debian/Dockerfile index 2ea52e09d3..2dee373bc4 100644 --- a/.gitlab/ci/builders/debian/Dockerfile +++ b/.gitlab/ci/builders/debian/Dockerfile @@ -6,7 +6,7 @@ # the distribution. # -ARG VERSION=24.04 +ARG VERSION=24.10 ARG OS_NAME=ubuntu FROM $OS_NAME:$VERSION From 1d03bb951a6b2125e3b849231a436ae98810fd81 Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 27 Aug 2024 16:09:15 +0200 Subject: [PATCH 340/407] ci,e2e: cleanup on cancel --- .gitlab/ci/e2e.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 609c2f15c1..17d2f8f8ec 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -78,7 +78,7 @@ load retina variables: variables: KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" - before_script: + before_script: &setup_kube_config - | export FORCE_COLOR=1 eval K_PATH="\$$KUBECONFIG_VAR_NAME" @@ -86,6 +86,7 @@ load retina variables: eval K_PATH_EXTRA="\$$KUBECONFIG_VAR_NAME_EXTRA" export KUBECONFIG_EXTRA=$K_PATH_EXTRA + e2e request and config validation: stage: static extends: @@ -177,6 +178,7 @@ e2e request and config validation: eval $E2E_CMD after_script: # Remove any existing retina resource for this group + - *setup_kube_config - retina-delete-orchestration-network --user-name ^ci_${GROUP} --regex # Push test metrics - | From d1f7d71eef29e7973b6ccc881197b2829090a471 Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 27 Aug 2024 15:56:43 +0200 Subject: [PATCH 341/407] ci: fix job name and improve logging --- .gitlab/ci/e2e.yml | 2 +- .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/steps/stub.py | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 17d2f8f8ec..8a4000b338 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -292,7 +292,7 @@ amari 1UE: - *txrx-lib - *retina-needs -amari 1UE 2x2 mimo: +amari 32UE 2x2 mimo: extends: .zmq variables: MARKERS: "zmq_2x2_mimo" diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 5874c7dfd0..b821573216 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.5 +RETINA_VERSION=0.52.7 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/tests/steps/stub.py b/tests/e2e/tests/steps/stub.py index ed458f899e..5d46aecc99 100644 --- a/tests/e2e/tests/steps/stub.py +++ b/tests/e2e/tests/steps/stub.py @@ -281,11 +281,9 @@ def _print_ping_result(msg: str, task: grpc.Future): result: PingResponse = task.result() if not result.status: log_fn = logging.error - except (grpc.RpcError, grpc.FutureCancelledError, grpc.FutureTimeoutError) as err: - log_fn = logging.error - result = ErrorReportedByAgent(err) - finally: log_fn("Ping %s:\n%s", msg, MessageToString(result, indent=2)) + except (grpc.RpcError, grpc.FutureCancelledError, grpc.FutureTimeoutError) as err: + logging.error(ErrorReportedByAgent(err)) def iperf_parallel( From 9e0dab6513ea928185648f8c324d82a4a3f8244a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 15:50:44 +0200 Subject: [PATCH 342/407] sched: derive the ring size required more programatically --- lib/scheduler/cell/resource_grid_util.h | 40 +++++++++++++------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/scheduler/cell/resource_grid_util.h b/lib/scheduler/cell/resource_grid_util.h index f52670da66..d483fabc4f 100644 --- a/lib/scheduler/cell/resource_grid_util.h +++ b/lib/scheduler/cell/resource_grid_util.h @@ -11,31 +11,33 @@ #pragma once #include "srsran/scheduler/sched_consts.h" +#include "srsran/support/math_utils.h" namespace srsran { -/// \brief Retrieves the resource grid allocator ring size greater than given minimum value. -/// \remark 1. The implementation of circular ring based resource allocator only works correctly if we set a -/// ring size which satisfies the condition NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0. -/// The condition is placed to avoid misalignment between (last_slot_ind + slot_delay) slot point and -/// slot point contained in ((last_slot_ind + slot_delay) % RING_ALLOCATOR_SIZE) slot, which occurs when slot point is -/// close to NOF_SLOTS_PER_SYSTEM_FRAME value. +/// \brief Determines a the resource grid allocator ring size that is greater than the given minimum value. +/// \remark 1. The ring size must satisfy the condition NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0, for +/// the used numerology. Otherwise, misalignments may occur close to the slot point wrap around. /// Misalignment example: Assume NOF_SLOTS_PER_SYSTEM_FRAME = 10240 and RING_ALLOCATOR_SIZE = 37 -/// At Slot point (10238) % 37 = Element at index 26 of slots array/vector is accessed, similarly -/// Slot point (10239) % 37 = 27 -/// Now, Slot point wraps around NOF_SLOTS_PER_SYSTEM_FRAME and is set to 0, this causes Slot point (0) % 37 = 0. -/// Resulting in element at index 0 of slots array/vector being accessed rather than index 28. -/// \remark 2. The reason for choosing values 20, 40 and 80 for RING_ALLOCATOR_SIZE is because it holds the condition -/// NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0. for all numerologies. +/// At the slot 1023.9, the ring index 10239 % 37 = 26 is accessed. At slot point 0.0 (once slot point wraps around), +/// the ring index 0 % 37 = 0 would be accessed. constexpr inline unsigned get_allocator_ring_size_gt_min(unsigned minimum_value) { - if (minimum_value < 20) { - return 20; - } - if (minimum_value < 40) { - return 40; - } - return 640; + auto power2_ceil = [](unsigned x) { + if (x <= 1) + return 1U; + unsigned power = 2; + x--; + while (x >>= 1) + power <<= 1; + return power; + }; + + // Note: we compute ring size assuming numerology 0. The reason being that if the condition + // NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0 is true for numerology 0, it will be as well for other + // numerologies. + unsigned div10 = divide_ceil(minimum_value, 10U); + return power2_ceil(div10) * 10; } /// \brief Retrieves how far in advance the scheduler can allocate resources in the UL resource grid. From 5cea848f0ed24869cf1b7b929d23318b909dcdc7 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 15:59:26 +0200 Subject: [PATCH 343/407] sched: extend get_allocator_ring_size_gt_min for different numerologies --- lib/scheduler/cell/resource_grid_util.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/cell/resource_grid_util.h b/lib/scheduler/cell/resource_grid_util.h index d483fabc4f..5a9ff37aa6 100644 --- a/lib/scheduler/cell/resource_grid_util.h +++ b/lib/scheduler/cell/resource_grid_util.h @@ -21,7 +21,11 @@ namespace srsran { /// Misalignment example: Assume NOF_SLOTS_PER_SYSTEM_FRAME = 10240 and RING_ALLOCATOR_SIZE = 37 /// At the slot 1023.9, the ring index 10239 % 37 = 26 is accessed. At slot point 0.0 (once slot point wraps around), /// the ring index 0 % 37 = 0 would be accessed. -constexpr inline unsigned get_allocator_ring_size_gt_min(unsigned minimum_value) +/// \remark 2. Numerology 0 (SCS=15kHz) can be used as a conservative value, at the expense of more space used, since +/// that if the condition NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0 is satisfied for numerology 0, it is +/// also satisfied for other numerologies. +constexpr inline unsigned get_allocator_ring_size_gt_min(unsigned minimum_value, + subcarrier_spacing scs = subcarrier_spacing::kHz15) { auto power2_ceil = [](unsigned x) { if (x <= 1) @@ -33,11 +37,9 @@ constexpr inline unsigned get_allocator_ring_size_gt_min(unsigned minimum_value) return power; }; - // Note: we compute ring size assuming numerology 0. The reason being that if the condition - // NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0 is true for numerology 0, it will be as well for other - // numerologies. - unsigned div10 = divide_ceil(minimum_value, 10U); - return power2_ceil(div10) * 10; + unsigned slots_per_frame = 10U * get_nof_slots_per_subframe(scs); + unsigned frames_ceil = divide_ceil(minimum_value, slots_per_frame); + return power2_ceil(frames_ceil) * slots_per_frame; } /// \brief Retrieves how far in advance the scheduler can allocate resources in the UL resource grid. From 27b56e1a5639874160b6d24850a04f85d8ccefa5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 19:59:23 +0200 Subject: [PATCH 344/407] sched: improve resource_grid_util.h documentation --- lib/scheduler/cell/resource_grid_util.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/cell/resource_grid_util.h b/lib/scheduler/cell/resource_grid_util.h index 5a9ff37aa6..99fd08f371 100644 --- a/lib/scheduler/cell/resource_grid_util.h +++ b/lib/scheduler/cell/resource_grid_util.h @@ -15,15 +15,16 @@ namespace srsran { -/// \brief Determines a the resource grid allocator ring size that is greater than the given minimum value. +/// \brief Derives a ring size for the resource grid allocator that is equal or larger than the given minimum value. /// \remark 1. The ring size must satisfy the condition NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0, for /// the used numerology. Otherwise, misalignments may occur close to the slot point wrap around. /// Misalignment example: Assume NOF_SLOTS_PER_SYSTEM_FRAME = 10240 and RING_ALLOCATOR_SIZE = 37 /// At the slot 1023.9, the ring index 10239 % 37 = 26 is accessed. At slot point 0.0 (once slot point wraps around), /// the ring index 0 % 37 = 0 would be accessed. -/// \remark 2. Numerology 0 (SCS=15kHz) can be used as a conservative value, at the expense of more space used, since -/// that if the condition NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0 is satisfied for numerology 0, it is -/// also satisfied for other numerologies. +/// \remark 2. If the condition NOF_SLOTS_PER_SYSTEM_FRAME % RING_ALLOCATOR_SIZE = 0 is satisfied for +/// the numerology mu=0 (SCS=15kHz), it will be also satisfied for the same RING_ALLOCATOR_SIZE and larger numerologies. +/// This means that in contexts where mu is not known (e.g. compile time), mu=0 can be used for generality sake, +/// at the expense of more memory overhead. constexpr inline unsigned get_allocator_ring_size_gt_min(unsigned minimum_value, subcarrier_spacing scs = subcarrier_spacing::kHz15) { From 99f37855f7a27f73fa5e7f5428326d04d87d7d64 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Aug 2024 08:39:29 +0200 Subject: [PATCH 345/407] cu_cp: remove unused code --- tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h | 1 - tests/unittests/cu_cp/mobility/mobility_test_helpers.h | 1 - tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h | 1 - 3 files changed, 3 deletions(-) diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h index df3c81dab0..d9485ebe12 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h @@ -42,7 +42,6 @@ class du_processor_test : public ::testing::Test cu_cp_configuration cu_cp_cfg; ue_manager ue_mng{cu_cp_cfg}; - dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; dummy_du_processor_cu_cp_notifier cu_cp_notifier{&ue_mng}; dummy_du_connection_notifier du_conn_notifier; dummy_f1ap_pdu_notifier f1ap_pdu_notifier; diff --git a/tests/unittests/cu_cp/mobility/mobility_test_helpers.h b/tests/unittests/cu_cp/mobility/mobility_test_helpers.h index 1aa19fba03..ddad3c5e9f 100644 --- a/tests/unittests/cu_cp/mobility/mobility_test_helpers.h +++ b/tests/unittests/cu_cp/mobility/mobility_test_helpers.h @@ -34,7 +34,6 @@ class mobility_test : public ::testing::Test cu_cp_configuration cu_cp_cfg; ue_manager ue_mng{cu_cp_cfg}; - dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; dummy_cu_cp_ue_context_manipulation_handler cu_cp_handler; }; diff --git a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h index c283afe84f..09e0c1ede2 100644 --- a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h +++ b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h @@ -43,7 +43,6 @@ class ue_manager_test : public ::testing::Test // DU processor to RRC UE adapters std::unordered_map rrc_ue_adapters; dummy_ngap_rrc_ue_notifier rrc_ue_pdu_notifier; - dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; }; } // namespace srs_cu_cp From 1cc11ae159208a3fcb4923b9e390859f6e99877b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Aug 2024 09:32:56 +0200 Subject: [PATCH 346/407] cu_cp,ngap: simplify ngap to cu-cp notifiers --- include/srsran/ngap/ngap.h | 8 --- include/srsran/ngap/ngap_factory.h | 11 ++-- lib/cu_cp/adapters/ngap_adapters.h | 2 +- lib/cu_cp/cu_cp_impl.cpp | 1 - lib/ngap/ngap_factory.cpp | 15 ++--- lib/ngap/ngap_impl.cpp | 19 +++--- lib/ngap/ngap_impl.h | 18 +++--- ...handover_resource_allocation_procedure.cpp | 24 ++++--- ...p_handover_resource_allocation_procedure.h | 34 +++++----- .../ngap/ngap_integration_test.cpp | 3 +- tests/unittests/ngap/ngap_paging_test.cpp | 62 +++++++++---------- tests/unittests/ngap/ngap_test_helpers.cpp | 2 +- tests/unittests/ngap/ngap_test_helpers.h | 9 ++- tests/unittests/ngap/test_helpers.h | 50 ++++++--------- 14 files changed, 112 insertions(+), 146 deletions(-) diff --git a/include/srsran/ngap/ngap.h b/include/srsran/ngap/ngap.h index 823b5cb477..5cfbda6062 100644 --- a/include/srsran/ngap/ngap.h +++ b/include/srsran/ngap/ngap.h @@ -199,14 +199,6 @@ class ngap_cu_cp_notifier /// \brief Notify that the TNL connection to the AMF was lost. virtual void on_n2_disconnection() = 0; -}; - -/// Interface to communication with the DU repository -/// Useful when the NGAP does not know the DU for an UE, e.g. paging and handover. -class ngap_cu_cp_du_repository_notifier -{ -public: - virtual ~ngap_cu_cp_du_repository_notifier() = default; /// \brief Notifies the CU-CP about a Paging message. virtual void on_paging_message(cu_cp_paging_message& msg) = 0; diff --git a/include/srsran/ngap/ngap_factory.h b/include/srsran/ngap/ngap_factory.h index f16d5bf4df..56b1a62cab 100644 --- a/include/srsran/ngap/ngap_factory.h +++ b/include/srsran/ngap/ngap_factory.h @@ -22,12 +22,11 @@ namespace srs_cu_cp { class n2_connection_client; /// Creates an instance of an NGAP interface, notifying outgoing packets on the specified listener object. -std::unique_ptr create_ngap(const ngap_configuration& ngap_cfg_, - ngap_cu_cp_notifier& cu_cp_ue_creation_notifier_, - ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - n2_connection_client& n2_gateway_handler_, - timer_manager& timers_, - task_executor& ctrl_exec_); +std::unique_ptr create_ngap(const ngap_configuration& ngap_cfg_, + ngap_cu_cp_notifier& cu_cp_notifier_, + n2_connection_client& n2_gateway_handler_, + timer_manager& timers_, + task_executor& ctrl_exec_); } // namespace srs_cu_cp diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index 13cb572b7c..7766d1dcc3 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -22,7 +22,7 @@ namespace srsran { namespace srs_cu_cp { /// Adapter between NGAP and CU-CP -class ngap_cu_cp_adapter : public ngap_cu_cp_du_repository_notifier, public ngap_cu_cp_notifier +class ngap_cu_cp_adapter : public ngap_cu_cp_notifier { public: explicit ngap_cu_cp_adapter() = default; diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index a45b4ce186..49fe05d912 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -84,7 +84,6 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : // Create NGAP. ngap_entity = create_ngap(create_ngap_cfg(cfg), - ngap_cu_cp_ev_notifier, ngap_cu_cp_ev_notifier, *cfg.services.n2_gw, *cfg.services.timers, diff --git a/lib/ngap/ngap_factory.cpp b/lib/ngap/ngap_factory.cpp index 8717a3494c..11295eab97 100644 --- a/lib/ngap/ngap_factory.cpp +++ b/lib/ngap/ngap_factory.cpp @@ -16,15 +16,12 @@ using namespace srsran; using namespace srs_cu_cp; -std::unique_ptr -srsran::srs_cu_cp::create_ngap(const ngap_configuration& ngap_cfg_, - ngap_cu_cp_notifier& cu_cp_ue_creation_notifier_, - ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - n2_connection_client& n2_gateway_handler_, - timer_manager& timers_, - task_executor& ctrl_exec_) +std::unique_ptr srsran::srs_cu_cp::create_ngap(const ngap_configuration& ngap_cfg_, + ngap_cu_cp_notifier& cu_cp_notifier_, + n2_connection_client& n2_gateway_handler_, + timer_manager& timers_, + task_executor& ctrl_exec_) { - auto ngap = std::make_unique( - ngap_cfg_, cu_cp_ue_creation_notifier_, cu_cp_du_repository_notifier_, n2_gateway_handler_, timers_, ctrl_exec_); + auto ngap = std::make_unique(ngap_cfg_, cu_cp_notifier_, n2_gateway_handler_, timers_, ctrl_exec_); return ngap; } diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 0ce4822a2c..8622e2cf32 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -32,16 +32,14 @@ using namespace srsran; using namespace asn1::ngap; using namespace srs_cu_cp; -ngap_impl::ngap_impl(const ngap_configuration& ngap_cfg_, - ngap_cu_cp_notifier& cu_cp_notifier_, - ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - n2_connection_client& n2_gateway, - timer_manager& timers_, - task_executor& ctrl_exec_) : +ngap_impl::ngap_impl(const ngap_configuration& ngap_cfg_, + ngap_cu_cp_notifier& cu_cp_notifier_, + n2_connection_client& n2_gateway, + timer_manager& timers_, + task_executor& ctrl_exec_) : logger(srslog::fetch_basic_logger("NGAP")), ue_ctxt_list(logger), cu_cp_notifier(cu_cp_notifier_), - cu_cp_du_repository_notifier(cu_cp_du_repository_notifier_), timers(timers_), ctrl_exec(ctrl_exec_), ev_mng(timer_factory{timers, ctrl_exec}), @@ -710,7 +708,7 @@ void ngap_impl::handle_paging(const asn1::ngap::paging_s& msg) cu_cp_paging_message cu_cp_paging_msg; fill_cu_cp_paging_message(cu_cp_paging_msg, msg); - cu_cp_du_repository_notifier.on_paging_message(cu_cp_paging_msg); + cu_cp_notifier.on_paging_message(cu_cp_paging_msg); } // free function to generate a handover failure message @@ -743,8 +741,8 @@ void ngap_impl::handle_handover_request(const asn1::ngap::ho_request_s& msg) ho_request.source_to_target_transparent_container.target_cell_id.nci); // Create UE in target cell - ho_request.ue_index = cu_cp_du_repository_notifier.request_new_ue_index_allocation( - ho_request.source_to_target_transparent_container.target_cell_id); + ho_request.ue_index = + cu_cp_notifier.request_new_ue_index_allocation(ho_request.source_to_target_transparent_container.target_cell_id); if (ho_request.ue_index == ue_index_t::invalid) { logger.warning("Sending HandoverFailure. Couldn't allocate UE index"); tx_pdu_notifier->on_new_message(generate_handover_failure(msg->amf_ue_ngap_id)); @@ -764,7 +762,6 @@ void ngap_impl::handle_handover_request(const asn1::ngap::ho_request_s& msg) uint_to_amf_ue_id(msg->amf_ue_ngap_id), ue_ctxt_list, cu_cp_notifier, - cu_cp_du_repository_notifier, *tx_pdu_notifier, timers, ctrl_exec, diff --git a/lib/ngap/ngap_impl.h b/lib/ngap/ngap_impl.h index b6dfee182a..56d8f20443 100644 --- a/lib/ngap/ngap_impl.h +++ b/lib/ngap/ngap_impl.h @@ -30,12 +30,11 @@ namespace srs_cu_cp { class ngap_impl final : public ngap_interface { public: - ngap_impl(const ngap_configuration& ngap_cfg_, - ngap_cu_cp_notifier& cu_cp_notifier_, - ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - n2_connection_client& n2_gateway, - timer_manager& timers_, - task_executor& ctrl_exec_); + ngap_impl(const ngap_configuration& ngap_cfg_, + ngap_cu_cp_notifier& cu_cp_notifier_, + n2_connection_client& n2_gateway, + timer_manager& timers_, + task_executor& ctrl_exec_); ~ngap_impl(); bool @@ -168,10 +167,9 @@ class ngap_impl final : public ngap_interface std::unordered_map stored_error_indications; - ngap_cu_cp_notifier& cu_cp_notifier; - ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier; - timer_manager& timers; - task_executor& ctrl_exec; + ngap_cu_cp_notifier& cu_cp_notifier; + timer_manager& timers; + task_executor& ctrl_exec; ngap_transaction_manager ev_mng; diff --git a/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp b/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp index 88c12575b3..06104e94c5 100644 --- a/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp @@ -18,20 +18,18 @@ using namespace srsran::srs_cu_cp; using namespace asn1::ngap; ngap_handover_resource_allocation_procedure::ngap_handover_resource_allocation_procedure( - const ngap_handover_request& request_, - const amf_ue_id_t amf_ue_id_, - ngap_ue_context_list& ue_ctxt_list_, - ngap_cu_cp_notifier& cu_cp_ue_creation_notifier_, - ngap_cu_cp_du_repository_notifier& du_repository_notif_, - ngap_message_notifier& amf_notif_, - timer_manager& timers_, - task_executor& task_exec_, - srslog::basic_logger& logger_) : + const ngap_handover_request& request_, + const amf_ue_id_t amf_ue_id_, + ngap_ue_context_list& ue_ctxt_list_, + ngap_cu_cp_notifier& cu_cp_notifier_, + ngap_message_notifier& amf_notif_, + timer_manager& timers_, + task_executor& task_exec_, + srslog::basic_logger& logger_) : request(request_), amf_ue_id(amf_ue_id_), ue_ctxt_list(ue_ctxt_list_), - cu_cp_ue_creation_notifier(cu_cp_ue_creation_notifier_), - du_repository_notifier(du_repository_notif_), + cu_cp_notifier(cu_cp_notifier_), amf_notifier(amf_notif_), timers(timers_), task_exec(task_exec_), @@ -46,7 +44,7 @@ void ngap_handover_resource_allocation_procedure::operator()(coro_context>& ctx); @@ -42,15 +41,14 @@ class ngap_handover_resource_allocation_procedure void send_handover_request_ack(ue_index_t ue_index, ran_ue_id_t ran_ue_id); void send_handover_failure(); - const ngap_handover_request& request; - const amf_ue_id_t amf_ue_id; - ngap_ue_context_list& ue_ctxt_list; - ngap_cu_cp_notifier& cu_cp_ue_creation_notifier; - ngap_cu_cp_du_repository_notifier& du_repository_notifier; - ngap_message_notifier& amf_notifier; - timer_manager& timers; - task_executor& task_exec; - srslog::basic_logger& logger; + const ngap_handover_request& request; + const amf_ue_id_t amf_ue_id; + ngap_ue_context_list& ue_ctxt_list; + ngap_cu_cp_notifier& cu_cp_notifier; + ngap_message_notifier& amf_notifier; + timer_manager& timers; + task_executor& task_exec; + srslog::basic_logger& logger; // (sub-)routine requests diff --git a/tests/integrationtests/ngap/ngap_integration_test.cpp b/tests/integrationtests/ngap/ngap_integration_test.cpp index fd0b749cbc..390266d675 100644 --- a/tests/integrationtests/ngap/ngap_integration_test.cpp +++ b/tests/integrationtests/ngap/ngap_integration_test.cpp @@ -135,7 +135,7 @@ class ngap_integration_test : public ::testing::Test nw_config.non_blocking_mode = true; adapter = std::make_unique(nw_config); - ngap = create_ngap(cfg, cu_cp_notifier, cu_cp_paging_notifier, *adapter, timers, ctrl_worker); + ngap = create_ngap(cfg, cu_cp_notifier, *adapter, timers, ctrl_worker); } timer_manager timers; @@ -145,7 +145,6 @@ class ngap_integration_test : public ::testing::Test ue_manager ue_mng{cu_cp_cfg}; dummy_ngap_cu_cp_notifier cu_cp_notifier{ue_mng}; - dummy_ngap_cu_cp_paging_notifier cu_cp_paging_notifier; std::unique_ptr adapter; std::unique_ptr ngap; diff --git a/tests/unittests/ngap/ngap_paging_test.cpp b/tests/unittests/ngap/ngap_paging_test.cpp index 521625b8fa..d18f041274 100644 --- a/tests/unittests/ngap/ngap_paging_test.cpp +++ b/tests/unittests/ngap/ngap_paging_test.cpp @@ -20,28 +20,28 @@ class ngap_paging_test : public ngap_test bool was_minimal_conversion_successful() const { // check ue paging id - if (cu_cp_paging_notifier.last_msg.ue_paging_id.get_amf_set_id() != 1) { + if (cu_cp_notifier.last_paging_msg.ue_paging_id.get_amf_set_id() != 1) { test_logger.error( - "AMF Set ID mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.get_amf_set_id(), 1); + "AMF Set ID mismatch {} != {}", cu_cp_notifier.last_paging_msg.ue_paging_id.get_amf_set_id(), 1); return false; } - if (cu_cp_paging_notifier.last_msg.ue_paging_id.get_amf_pointer() != 0) { + if (cu_cp_notifier.last_paging_msg.ue_paging_id.get_amf_pointer() != 0) { test_logger.error( - "AMF Pointer mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.get_amf_pointer(), 0); + "AMF Pointer mismatch {} != {}", cu_cp_notifier.last_paging_msg.ue_paging_id.get_amf_pointer(), 0); return false; } - if (cu_cp_paging_notifier.last_msg.ue_paging_id.get_five_g_tmsi() != 4211117727) { + if (cu_cp_notifier.last_paging_msg.ue_paging_id.get_five_g_tmsi() != 4211117727) { test_logger.error( - "FiveG TMSI mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.get_five_g_tmsi(), 4211117727); + "FiveG TMSI mismatch {} != {}", cu_cp_notifier.last_paging_msg.ue_paging_id.get_five_g_tmsi(), 4211117727); return false; } // check tai list for paging - if (cu_cp_paging_notifier.last_msg.tai_list_for_paging.size() != 1) { + if (cu_cp_notifier.last_paging_msg.tai_list_for_paging.size() != 1) { return false; } - auto& paging_item = cu_cp_paging_notifier.last_msg.tai_list_for_paging.front(); + auto& paging_item = cu_cp_notifier.last_paging_msg.tai_list_for_paging.front(); if (paging_item.tai.plmn_id != plmn_identity::test_value()) { test_logger.error("PLMN mismatch {} != 00f110", paging_item.tai.plmn_id); return false; @@ -61,58 +61,58 @@ class ngap_paging_test : public ngap_test } // check paging drx - if (!cu_cp_paging_notifier.last_msg.paging_drx.has_value()) { + if (!cu_cp_notifier.last_paging_msg.paging_drx.has_value()) { return false; } - if (cu_cp_paging_notifier.last_msg.paging_drx.value() != 64) { - test_logger.error("Paging DRX mismatch {} != {}", cu_cp_paging_notifier.last_msg.paging_drx, 64); + if (cu_cp_notifier.last_paging_msg.paging_drx.value() != 64) { + test_logger.error("Paging DRX mismatch {} != {}", cu_cp_notifier.last_paging_msg.paging_drx, 64); return false; } // check paging prio - if (!cu_cp_paging_notifier.last_msg.paging_prio.has_value()) { + if (!cu_cp_notifier.last_paging_msg.paging_prio.has_value()) { return false; } - if (cu_cp_paging_notifier.last_msg.paging_prio.value() != 5) { - test_logger.error("Paging prio mismatch {} != {}", cu_cp_paging_notifier.last_msg.paging_prio.value(), 5); + if (cu_cp_notifier.last_paging_msg.paging_prio.value() != 5) { + test_logger.error("Paging prio mismatch {} != {}", cu_cp_notifier.last_paging_msg.paging_prio.value(), 5); return false; } // check ue radio cap for paging - if (!cu_cp_paging_notifier.last_msg.ue_radio_cap_for_paging.has_value()) { + if (!cu_cp_notifier.last_paging_msg.ue_radio_cap_for_paging.has_value()) { return false; } - if (cu_cp_paging_notifier.last_msg.ue_radio_cap_for_paging.value().ue_radio_cap_for_paging_of_nr != + if (cu_cp_notifier.last_paging_msg.ue_radio_cap_for_paging.value().ue_radio_cap_for_paging_of_nr != make_byte_buffer("deadbeef").value()) { test_logger.error("UE radio cap for paging mismatch {} != {}", - cu_cp_paging_notifier.last_msg.ue_radio_cap_for_paging.value().ue_radio_cap_for_paging_of_nr, + cu_cp_notifier.last_paging_msg.ue_radio_cap_for_paging.value().ue_radio_cap_for_paging_of_nr, make_byte_buffer("deadbeef").value()); return false; } // check paging origin - if (!cu_cp_paging_notifier.last_msg.paging_origin.has_value()) { + if (!cu_cp_notifier.last_paging_msg.paging_origin.has_value()) { return false; } - if (!cu_cp_paging_notifier.last_msg.paging_origin.value()) { + if (!cu_cp_notifier.last_paging_msg.paging_origin.value()) { test_logger.error("Paging origin mismatch"); return false; } // check assist data for paging - if (!cu_cp_paging_notifier.last_msg.assist_data_for_paging.has_value()) { + if (!cu_cp_notifier.last_paging_msg.assist_data_for_paging.has_value()) { return false; } - if (!cu_cp_paging_notifier.last_msg.assist_data_for_paging.value().assist_data_for_recommended_cells.has_value()) { + if (!cu_cp_notifier.last_paging_msg.assist_data_for_paging.value().assist_data_for_recommended_cells.has_value()) { return false; } - if (cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + if (cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .assist_data_for_recommended_cells.value() .recommended_cells_for_paging.recommended_cell_list.size() != 1) { return false; } - auto& cell_item = cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + auto& cell_item = cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .assist_data_for_recommended_cells.value() .recommended_cells_for_paging.recommended_cell_list.front(); if (cell_item.ngran_cgi.plmn_id != plmn_identity::test_value()) { @@ -129,39 +129,39 @@ class ngap_paging_test : public ngap_test return false; } - if (!cu_cp_paging_notifier.last_msg.assist_data_for_paging.value().paging_attempt_info.has_value()) { + if (!cu_cp_notifier.last_paging_msg.assist_data_for_paging.value().paging_attempt_info.has_value()) { return false; } - if (cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + if (cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .paging_attempt_count != 3) { test_logger.error("Paging attempt count mismatch {} != {}", - cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .paging_attempt_count, 3); return false; } - if (cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + if (cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .intended_nof_paging_attempts != 4) { test_logger.error("Intended nof paging attempts mismatch {} != {}", - cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .intended_nof_paging_attempts, 4); return false; } - if (!cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + if (!cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .next_paging_area_scope.has_value()) { return false; } - if (cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + if (cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .next_paging_area_scope.value() != "changed") { test_logger.error("Next paging area mismatch {} != changed", - cu_cp_paging_notifier.last_msg.assist_data_for_paging.value() + cu_cp_notifier.last_paging_msg.assist_data_for_paging.value() .paging_attempt_info.value() .next_paging_area_scope.value()); return false; diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index aa248e7d40..0e7141d74b 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -38,7 +38,7 @@ ngap_test::ngap_test() : ngap_cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; ngap_cfg.supported_tas = cu_cp_cfg.node.supported_tas; ngap_cfg.pdu_session_setup_timeout = cu_cp_cfg.ue.pdu_session_setup_timeout; - ngap = create_ngap(ngap_cfg, cu_cp_notifier, cu_cp_paging_notifier, n2_gw, timers, ctrl_worker); + ngap = create_ngap(ngap_cfg, cu_cp_notifier, n2_gw, timers, ctrl_worker); cu_cp_notifier.connect_ngap(ngap->get_ngap_ue_context_removal_handler()); diff --git a/tests/unittests/ngap/ngap_test_helpers.h b/tests/unittests/ngap/ngap_test_helpers.h index 833ec7edc8..b4dc924214 100644 --- a/tests/unittests/ngap/ngap_test_helpers.h +++ b/tests/unittests/ngap/ngap_test_helpers.h @@ -80,11 +80,10 @@ class ngap_test : public ::testing::Test manual_task_worker ctrl_worker{128}; cu_cp_configuration cu_cp_cfg; - ue_manager ue_mng{cu_cp_cfg}; - dummy_n2_gateway n2_gw; - dummy_ngap_cu_cp_notifier cu_cp_notifier{ue_mng}; - dummy_ngap_cu_cp_paging_notifier cu_cp_paging_notifier; - std::unique_ptr ngap; + ue_manager ue_mng{cu_cp_cfg}; + dummy_n2_gateway n2_gw; + dummy_ngap_cu_cp_notifier cu_cp_notifier{ue_mng}; + std::unique_ptr ngap; }; } // namespace srs_cu_cp diff --git a/tests/unittests/ngap/test_helpers.h b/tests/unittests/ngap/test_helpers.h index 3dfc7e7e3d..9d9b41e67e 100644 --- a/tests/unittests/ngap/test_helpers.h +++ b/tests/unittests/ngap/test_helpers.h @@ -139,36 +139,6 @@ class dummy_ngap_rrc_ue_notifier : public ngap_rrc_ue_pdu_notifier, public ngap_ srslog::basic_logger& logger; }; -class dummy_ngap_cu_cp_paging_notifier : public ngap_cu_cp_du_repository_notifier -{ -public: - dummy_ngap_cu_cp_paging_notifier() : logger(srslog::fetch_basic_logger("TEST")){}; - - void on_paging_message(cu_cp_paging_message& msg) override - { - logger.info("Received a new Paging message"); - last_msg = std::move(msg); - } - - ue_index_t request_new_ue_index_allocation(nr_cell_global_id_t /*cgi*/) override { return ue_index_t::invalid; } - - async_task - on_ngap_handover_request(const ngap_handover_request& request) override - { - return launch_async([res = ngap_handover_resource_allocation_response{}]( - coro_context>& ctx) mutable { - CORO_BEGIN(ctx); - - CORO_RETURN(res); - }); - } - - cu_cp_paging_message last_msg; - -private: - srslog::basic_logger& logger; -}; - class dummy_ngap_cu_cp_notifier : public ngap_cu_cp_notifier { public: @@ -365,12 +335,32 @@ class dummy_ngap_cu_cp_notifier : public ngap_cu_cp_notifier return ue_index; } + void on_paging_message(cu_cp_paging_message& msg) override + { + logger.info("Received a new Paging message"); + last_paging_msg = std::move(msg); + } + + ue_index_t request_new_ue_index_allocation(nr_cell_global_id_t /*cgi*/) override { return ue_index_t::invalid; } + + async_task + on_ngap_handover_request(const ngap_handover_request& request) override + { + return launch_async([res = ngap_handover_resource_allocation_response{}]( + coro_context>& ctx) mutable { + CORO_BEGIN(ctx); + + CORO_RETURN(res); + }); + } + ue_index_t last_ue = ue_index_t::invalid; ngap_init_context_setup_request last_init_ctxt_setup_request; cu_cp_pdu_session_resource_setup_request last_request; cu_cp_pdu_session_resource_modify_request last_modify_request; cu_cp_pdu_session_resource_release_command last_release_command; std::optional last_created_ue_index; + cu_cp_paging_message last_paging_msg; private: ue_manager& ue_mng; From 1d1b1c292959a6f8191cbe74cef0bcd3cc6c7e78 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Aug 2024 09:44:40 +0200 Subject: [PATCH 347/407] cu_cp,ngap: simplify ngap to rrc ue notifiers --- include/srsran/ngap/ngap.h | 20 +++++-------------- lib/cu_cp/adapters/ngap_adapters.h | 15 ++++---------- lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp | 10 ++-------- lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 7 ++----- .../ue_manager/cu_cp_ue_impl_interface.h | 10 +++------- lib/ngap/ngap_impl.cpp | 10 +++------- ...ngap_dl_nas_message_transfer_procedure.cpp | 13 ++++-------- .../ngap_dl_nas_message_transfer_procedure.h | 6 ++---- .../ngap_handover_preparation_procedure.cpp | 2 +- .../ngap_handover_preparation_procedure.h | 4 ++-- tests/unittests/ngap/test_helpers.h | 2 +- 11 files changed, 29 insertions(+), 70 deletions(-) diff --git a/include/srsran/ngap/ngap.h b/include/srsran/ngap/ngap.h index 5cfbda6062..b32fdc3074 100644 --- a/include/srsran/ngap/ngap.h +++ b/include/srsran/ngap/ngap.h @@ -87,22 +87,15 @@ class ngap_ue_context_removal_handler virtual void remove_ue_context(ue_index_t ue_index) = 0; }; -/// Notifier to the RRC UE for NAS PDUs. -class ngap_rrc_ue_pdu_notifier +/// Notifier to the RRC UE. +class ngap_rrc_ue_notifier { public: - virtual ~ngap_rrc_ue_pdu_notifier() = default; + virtual ~ngap_rrc_ue_notifier() = default; /// \brief Notify about the a new nas pdu. /// \param [in] nas_pdu The nas pdu. virtual void on_new_pdu(byte_buffer nas_pdu) = 0; -}; - -/// Notifier to the RRC UE for control messages. -class ngap_rrc_ue_control_notifier -{ -public: - virtual ~ngap_rrc_ue_control_notifier() = default; /// \brief Get packed packed UE radio access capability info for UE radio capability info indication. virtual byte_buffer on_ue_radio_access_cap_info_required() = 0; @@ -123,11 +116,8 @@ class ngap_cu_cp_ue_notifier /// \brief Schedule an async task for the UE. virtual bool schedule_async_task(async_task task) = 0; - /// \brief Get the RRC UE PDU notifier of the UE. - virtual ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() = 0; - - /// \brief Get the RRC UE control notifier of the UE. - virtual ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() = 0; + /// \brief Get the RRC UE notifier of the UE. + virtual ngap_rrc_ue_notifier& get_ngap_rrc_ue_notifier() = 0; /// \brief Notify the CU-CP about a security context /// \param[in] sec_ctxt The received security context diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index 7766d1dcc3..753c8f1875 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -144,18 +144,11 @@ class ngap_cu_cp_ue_adapter : public ngap_cu_cp_ue_notifier return ue->get_task_sched().schedule_async_task(std::move(task)); } - /// \brief Get the RRC UE PDU notifier of the UE. - ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() override + /// \brief Get the RRC UE notifier of the UE. + ngap_rrc_ue_notifier& get_ngap_rrc_ue_notifier() override { srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); - return ue->get_rrc_ue_pdu_notifier(); - } - - /// \brief Get the RRC UE control notifier of the UE. - ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() override - { - srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); - return ue->get_rrc_ue_control_notifier(); + return ue->get_ngap_rrc_ue_notifier(); } bool init_security_context(security::security_context sec_ctxt) override @@ -175,7 +168,7 @@ class ngap_cu_cp_ue_adapter : public ngap_cu_cp_ue_notifier }; /// Adapter between NGAP and RRC UE -class ngap_rrc_ue_adapter : public ngap_rrc_ue_pdu_notifier, public ngap_rrc_ue_control_notifier +class ngap_rrc_ue_adapter : public ngap_rrc_ue_notifier { public: ngap_rrc_ue_adapter() = default; diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp index 62aff68a69..857b0dd8e7 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp @@ -97,14 +97,8 @@ void cu_cp_ue::set_rrc_ue(rrc_ue_interface& rrc_ue_) rrc_ue = &rrc_ue_; } -/// \brief Get the RRC UE PDU notifier of the UE. -ngap_rrc_ue_pdu_notifier& cu_cp_ue::get_rrc_ue_pdu_notifier() -{ - return ngap_rrc_ue_ev_notifier; -} - -/// \brief Get the RRC UE control notifier of the UE. -ngap_rrc_ue_control_notifier& cu_cp_ue::get_rrc_ue_control_notifier() +/// \brief Get the NGAP RRC UE notifier of the UE. +ngap_rrc_ue_notifier& cu_cp_ue::get_ngap_rrc_ue_notifier() { return ngap_rrc_ue_ev_notifier; } diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index be9a1a7324..e36e5f9c73 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -107,11 +107,8 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \brief Set the RRC UE of the UE. void set_rrc_ue(rrc_ue_interface& rrc_ue_); - /// \brief Get the RRC UE PDU notifier of the UE. - ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() override; - - /// \brief Get the RRC UE control notifier of the UE. - ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() override; + /// \brief Get the RRC UE notifier of the UE. + ngap_rrc_ue_notifier& get_ngap_rrc_ue_notifier() override; /// \brief Get the NGAP CU-CP UE notifier of the UE. ngap_cu_cp_ue_notifier& get_ngap_cu_cp_ue_notifier() { return ngap_cu_cp_ue_ev_notifier; } diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h index e5931f110b..caa452b67f 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h @@ -21,8 +21,7 @@ namespace srs_cu_cp { class up_resource_manager; class ue_task_scheduler; class ue_security_manager; -class ngap_rrc_ue_pdu_notifier; -class ngap_rrc_ue_control_notifier; +class ngap_rrc_ue_notifier; /// Common UE interface. class cu_cp_ue_impl_interface @@ -42,11 +41,8 @@ class cu_cp_ue_impl_interface /// \brief Get the security manager of the UE. virtual ue_security_manager& get_security_manager() = 0; - /// \brief Get the RRC UE PDU notifier of the UE. - virtual ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() = 0; - - /// \brief Get the RRC UE control notifier of the UE. - virtual ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() = 0; + /// \brief Get the RRC UE notifier of the UE. + virtual ngap_rrc_ue_notifier& get_ngap_rrc_ue_notifier() = 0; }; } // namespace srs_cu_cp diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 8622e2cf32..69f591c8cd 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -384,12 +384,8 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo fill_ngap_dl_nas_transport_message(dl_nas_msg, ue->get_ue_index(), msg); // start routine - ue->schedule_async_task( - launch_async(dl_nas_msg, - ue->get_rrc_ue_pdu_notifier(), - ue->get_rrc_ue_control_notifier(), - get_ngap_ue_radio_cap_management_handler(), - ue_ctxt.logger)); + ue->schedule_async_task(launch_async( + dl_nas_msg, ue->get_ngap_rrc_ue_notifier(), get_ngap_ue_radio_cap_management_handler(), ue_ctxt.logger)); } void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_context_setup_request_s& request) @@ -945,7 +941,7 @@ ngap_impl::handle_handover_preparation_request(const ngap_handover_preparation_r ue_ctxt.serving_guami.plmn, ue_ctxt.ue_ids, *tx_pdu_notifier, - ue->get_rrc_ue_control_notifier(), + ue->get_ngap_rrc_ue_notifier(), cu_cp_notifier, ev_mng, timer_factory{timers, ctrl_exec}, diff --git a/lib/ngap/procedures/ngap_dl_nas_message_transfer_procedure.cpp b/lib/ngap/procedures/ngap_dl_nas_message_transfer_procedure.cpp index 62b3ce7656..64933b70e2 100644 --- a/lib/ngap/procedures/ngap_dl_nas_message_transfer_procedure.cpp +++ b/lib/ngap/procedures/ngap_dl_nas_message_transfer_procedure.cpp @@ -17,15 +17,10 @@ using namespace asn1::ngap; ngap_dl_nas_message_transfer_procedure::ngap_dl_nas_message_transfer_procedure( const ngap_dl_nas_transport_message& msg_, - ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier_, - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier_, + ngap_rrc_ue_notifier& rrc_ue_notifier_, ngap_ue_radio_capability_management_handler& ngap_handler_, ngap_ue_logger& logger_) : - msg(msg_), - rrc_ue_pdu_notifier(rrc_ue_pdu_notifier_), - rrc_ue_ctrl_notifier(rrc_ue_ctrl_notifier_), - ngap_handler(ngap_handler_), - logger(logger_) + msg(msg_), rrc_ue_notifier(rrc_ue_notifier_), ngap_handler(ngap_handler_), logger(logger_) { } @@ -50,14 +45,14 @@ void ngap_dl_nas_message_transfer_procedure::operator()(coro_context Date: Tue, 27 Aug 2024 09:57:49 +0200 Subject: [PATCH 348/407] cu_cp,rrc: simplify rrc ul pdu handler --- include/srsran/rrc/rrc.h | 65 -------------------- include/srsran/rrc/rrc_ue.h | 42 +++++++++++-- lib/cu_cp/adapters/f1ap_adapters.h | 17 ++--- lib/cu_cp/adapters/ngap_adapters.h | 2 +- lib/cu_cp/du_processor/du_processor_impl.cpp | 3 +- lib/rrc/ue/rrc_ue_impl.h | 6 +- tests/unittests/rrc/rrc_ue_test_helpers.h | 32 +++++----- 7 files changed, 62 insertions(+), 105 deletions(-) delete mode 100644 include/srsran/rrc/rrc.h diff --git a/include/srsran/rrc/rrc.h b/include/srsran/rrc/rrc.h deleted file mode 100644 index a4cd4e4920..0000000000 --- a/include/srsran/rrc/rrc.h +++ /dev/null @@ -1,65 +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/byte_buffer.h" -#include "srsran/ran/lcid.h" - -namespace srsran { - -namespace srs_cu_cp { - -enum ue_context_release_cause : uint16_t { - radio_network = 0, - transport = 1, - protocol = 2, - misc = 3, - choice_ext = 4, - nulltype = 5 -}; - -/// This interface represents the data entry point for the RRC receiving PDUs on the UL-CCCH logical channel. -/// The lower-layers will use this class to pass PDUs into the RRC. -class rrc_ul_ccch_pdu_handler -{ -public: - virtual ~rrc_ul_ccch_pdu_handler() = default; - - /// Handle the incoming PDU on the UL-CCCH logical channel. - virtual void handle_ul_ccch_pdu(byte_buffer pdu) = 0; -}; - -/// This interface represents the data entry point for the RRC receiving PDUs on the UL-DCCH logical channel. -/// The lower-layers will use this class to pass PDUs into the RRC. -class rrc_ul_dcch_pdu_handler -{ -public: - virtual ~rrc_ul_dcch_pdu_handler() = default; - - /// Handle the incoming SRB PDCP PDU on the UL-DCCH logical channel. - virtual void handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdu) = 0; -}; - -/// This interface represents the data entry point for the RRC receiving NAS PDUs. -/// The higher-layers will use this class to pass PDUs into the RRC. -class rrc_dl_nas_message_handler -{ -public: - virtual ~rrc_dl_nas_message_handler() = default; - - /// \brief Handle the received Downlink NAS Transport message. - /// \param[in] nas_pdu The received NAS PDU. - virtual void handle_dl_nas_transport_message(byte_buffer nas_pdu) = 0; -}; - -} // namespace srs_cu_cp - -} // namespace srsran diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 0d6edddca3..df51057e97 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -18,7 +18,6 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/cu_cp/cu_cp_ue_messages.h" #include "srsran/ran/rnti.h" -#include "srsran/rrc/rrc.h" #include "srsran/rrc/rrc_ue_config.h" #include "srsran/security/security.h" #include "srsran/support/async/async_task.h" @@ -45,6 +44,41 @@ class rrc_ue_controller virtual void stop() = 0; }; +enum ue_context_release_cause : uint16_t { + radio_network = 0, + transport = 1, + protocol = 2, + misc = 3, + choice_ext = 4, + nulltype = 5 +}; + +/// This interface represents the data entry point for the RRC UE receiving UL PDUs on the CCCH and DCCH logical +/// channel. The lower-layers will use this class to pass PDUs into the RRC. +class rrc_ul_pdu_handler +{ +public: + virtual ~rrc_ul_pdu_handler() = default; + + /// Handle the incoming PDU on the UL-CCCH logical channel. + virtual void handle_ul_ccch_pdu(byte_buffer pdu) = 0; + + /// Handle the incoming SRB PDCP PDU on the UL-DCCH logical channel. + virtual void handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdu) = 0; +}; + +/// This interface represents the data entry point for the RRC receiving NAS PDUs. +/// The higher-layers will use this class to pass PDUs into the RRC. +class rrc_dl_nas_message_handler +{ +public: + virtual ~rrc_dl_nas_message_handler() = default; + + /// \brief Handle the received Downlink NAS Transport message. + /// \param[in] nas_pdu The received NAS PDU. + virtual void handle_dl_nas_transport_message(byte_buffer nas_pdu) = 0; +}; + /// Interface to notify F1AP about a new SRB PDU. class rrc_pdu_f1ap_notifier { @@ -406,8 +440,7 @@ class rrc_ue_context_handler /// Combined entry point for the RRC UE handling. /// It will contain getters for the interfaces for the various logical channels handled by RRC. -class rrc_ue_interface : public rrc_ul_ccch_pdu_handler, - public rrc_ul_dcch_pdu_handler, +class rrc_ue_interface : public rrc_ul_pdu_handler, public rrc_dl_nas_message_handler, public rrc_ue_srb_handler, public rrc_ue_control_message_handler, @@ -424,8 +457,7 @@ class rrc_ue_interface : public rrc_ul_ccch_pdu_handler, virtual ~rrc_ue_interface() = default; virtual rrc_ue_controller& get_controller() = 0; - virtual rrc_ul_ccch_pdu_handler& get_ul_ccch_pdu_handler() = 0; - virtual rrc_ul_dcch_pdu_handler& get_ul_dcch_pdu_handler() = 0; + virtual rrc_ul_pdu_handler& get_ul_pdu_handler() = 0; virtual rrc_dl_nas_message_handler& get_rrc_dl_nas_message_handler() = 0; virtual rrc_ue_srb_handler& get_rrc_ue_srb_handler() = 0; virtual rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() = 0; diff --git a/lib/cu_cp/adapters/f1ap_adapters.h b/lib/cu_cp/adapters/f1ap_adapters.h index bdd11467d1..86b066dcba 100644 --- a/lib/cu_cp/adapters/f1ap_adapters.h +++ b/lib/cu_cp/adapters/f1ap_adapters.h @@ -23,27 +23,22 @@ class cu_cp_controller; class f1ap_rrc_ue_adapter : public f1ap_rrc_message_notifier { public: - void connect_rrc_ue(rrc_ul_ccch_pdu_handler& rrc_ul_ccch_handler_, rrc_ul_dcch_pdu_handler& rrc_ul_dcch_handler_) - { - rrc_ul_ccch_handler = &rrc_ul_ccch_handler_; - rrc_ul_dcch_handler = &rrc_ul_dcch_handler_; - } + void connect_rrc_ue(rrc_ul_pdu_handler& rrc_pdu_handler_) { rrc_pdu_handler = &rrc_pdu_handler_; } void on_ul_ccch_pdu(byte_buffer pdu) override { - srsran_assert(rrc_ul_ccch_handler != nullptr, "RRC UL CCCH handler must not be nullptr"); - rrc_ul_ccch_handler->handle_ul_ccch_pdu(std::move(pdu)); + srsran_assert(rrc_pdu_handler != nullptr, "RRC UL handler must not be nullptr"); + rrc_pdu_handler->handle_ul_ccch_pdu(std::move(pdu)); } void on_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdu) override { - srsran_assert(rrc_ul_dcch_handler != nullptr, "RRC UL DCCH handler must not be nullptr"); - rrc_ul_dcch_handler->handle_ul_dcch_pdu(srb_id, std::move(pdu)); + srsran_assert(rrc_pdu_handler != nullptr, "RRC UL handler must not be nullptr"); + rrc_pdu_handler->handle_ul_dcch_pdu(srb_id, std::move(pdu)); } private: - rrc_ul_ccch_pdu_handler* rrc_ul_ccch_handler = nullptr; - rrc_ul_dcch_pdu_handler* rrc_ul_dcch_handler = nullptr; + rrc_ul_pdu_handler* rrc_pdu_handler = nullptr; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index 753c8f1875..23a3414e71 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -16,7 +16,7 @@ #include "../ue_manager/cu_cp_ue_impl_interface.h" #include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/ngap/ngap.h" -#include "srsran/rrc/rrc.h" +#include "srsran/rrc/rrc_ue.h" namespace srsran { namespace srs_cu_cp { diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index 36583e5d70..89db582ddd 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -237,8 +237,7 @@ du_processor_impl::handle_ue_rrc_context_creation_request(const ue_rrc_context_c } rrc_ue_interface* rrc_ue = rrc->find_ue(ue_index); f1ap_rrc_ue_adapters[ue_index] = {}; - f1ap_rrc_ue_adapters.at(ue_index).connect_rrc_ue(rrc_ue->get_ul_ccch_pdu_handler(), - rrc_ue->get_ul_dcch_pdu_handler()); + f1ap_rrc_ue_adapters.at(ue_index).connect_rrc_ue(rrc_ue->get_ul_pdu_handler()); // Signal back that the UE was successfully created. logger.info("ue={} c-rnti={}: UE created", ue->get_ue_index(), req.c_rnti); diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index 86c47c558c..604e3a9d7b 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -38,15 +38,13 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller std::optional rrc_context); ~rrc_ue_impl(); - // rrc_ul_ccch_pdu_handler + // rrc_ul_pdu_handler void handle_ul_ccch_pdu(byte_buffer pdu) override; - // rrc_ul_dcch_pdu_handler void handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdcp_pdu) override; // rrc_ue_interface rrc_ue_controller& get_controller() override { return *this; } - rrc_ul_ccch_pdu_handler& get_ul_ccch_pdu_handler() override { return *this; } - rrc_ul_dcch_pdu_handler& get_ul_dcch_pdu_handler() override { return *this; } + rrc_ul_pdu_handler& get_ul_pdu_handler() override { return *this; } rrc_dl_nas_message_handler& get_rrc_dl_nas_message_handler() override { return *this; } rrc_ue_srb_handler& get_rrc_ue_srb_handler() override { return *this; } rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() override { return *this; } diff --git a/tests/unittests/rrc/rrc_ue_test_helpers.h b/tests/unittests/rrc/rrc_ue_test_helpers.h index eec3d8ec49..05cadebe2c 100644 --- a/tests/unittests/rrc/rrc_ue_test_helpers.h +++ b/tests/unittests/rrc/rrc_ue_test_helpers.h @@ -214,54 +214,53 @@ class rrc_ue_test_helper void receive_setup_request() { // inject RRC setup into UE object - rrc_ue->get_ul_ccch_pdu_handler().handle_ul_ccch_pdu(byte_buffer::create(rrc_setup_pdu).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_ccch_pdu(byte_buffer::create(rrc_setup_pdu).value()); } void receive_invalid_setup_request() { // inject corrupted RRC setup into UE object - rrc_ue->get_ul_ccch_pdu_handler().handle_ul_ccch_pdu( - byte_buffer::create({0x9d, 0xec, 0x89, 0xde, 0x57, 0x66}).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_ccch_pdu(byte_buffer::create({0x9d, 0xec, 0x89, 0xde, 0x57, 0x66}).value()); } void receive_invalid_reestablishment_request(pci_t pci, rnti_t c_rnti) { // inject RRC Reestablishment Request into UE object - rrc_ue->get_ul_ccch_pdu_handler().handle_ul_ccch_pdu(generate_invalid_rrc_reestablishment_request_pdu(pci, c_rnti)); + rrc_ue->get_ul_pdu_handler().handle_ul_ccch_pdu(generate_invalid_rrc_reestablishment_request_pdu(pci, c_rnti)); } void receive_valid_reestablishment_request(pci_t pci, rnti_t c_rnti) { // inject RRC Reestablishment Request into UE object - rrc_ue->get_ul_ccch_pdu_handler().handle_ul_ccch_pdu(generate_valid_rrc_reestablishment_request_pdu(pci, c_rnti)); + rrc_ue->get_ul_pdu_handler().handle_ul_ccch_pdu(generate_valid_rrc_reestablishment_request_pdu(pci, c_rnti)); } void receive_valid_reestablishment_request_with_cause_recfg_fail(pci_t pci, rnti_t c_rnti) { // inject RRC Reestablishment Request into UE object - rrc_ue->get_ul_ccch_pdu_handler().handle_ul_ccch_pdu(generate_valid_rrc_reestablishment_request_pdu( + rrc_ue->get_ul_pdu_handler().handle_ul_ccch_pdu(generate_valid_rrc_reestablishment_request_pdu( pci, c_rnti, "0111011100001000", asn1::rrc_nr::reest_cause_opts::options::recfg_fail)); } void receive_reestablishment_complete() { // inject RRC Reestablishment complete - rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, - byte_buffer::create(rrc_reest_complete_pdu).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, + byte_buffer::create(rrc_reest_complete_pdu).value()); } void receive_setup_complete() { // inject RRC setup complete - rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, - byte_buffer::create(rrc_setup_complete_pdu).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, + byte_buffer::create(rrc_setup_complete_pdu).value()); } void receive_corrupted_setup_complete() { // inject corrupted RRC setup complete - rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, - byte_buffer::create(corrupted_rrc_setup_complete_pdu).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, + byte_buffer::create(corrupted_rrc_setup_complete_pdu).value()); } void send_dl_info_transfer(byte_buffer nas_pdu) @@ -305,8 +304,7 @@ class rrc_ue_test_helper void receive_smc_complete() { // inject RRC SMC complete into UE object - rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, - byte_buffer::create(rrc_smc_complete_pdu).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, byte_buffer::create(rrc_smc_complete_pdu).value()); } void check_smc_pdu() { ASSERT_EQ(rrc_ue_f1ap_notifier.last_rrc_pdu, byte_buffer::create(rrc_smc_pdu).value()); } @@ -325,7 +323,7 @@ class rrc_ue_test_helper byte_buffer ul_dcch_msg_pdu = byte_buffer::create(span{rrc_ue_capability_information_pdu}).value(); // inject RRC UE capability information into UE object - rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, std::move(ul_dcch_msg_pdu)); + rrc_ue->get_ul_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, std::move(ul_dcch_msg_pdu)); } void check_rrc_reconfig_pdu() { ASSERT_EQ(rrc_ue_f1ap_notifier.last_rrc_pdu, rrc_reconfig_pdu); } @@ -333,8 +331,8 @@ class rrc_ue_test_helper void receive_reconfig_complete() { // inject RRC Reconfiguration complete into UE object - rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, - byte_buffer::create(rrc_reconfig_complete_pdu).value()); + rrc_ue->get_ul_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, + byte_buffer::create(rrc_reconfig_complete_pdu).value()); } void add_ue_reestablishment_context(ue_index_t ue_index) From 8c5b3a1574b5553164f314f54e78a7f1f702bf69 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Aug 2024 10:10:53 +0200 Subject: [PATCH 349/407] cu_cp: simplify du processor to rrc ue notifier --- lib/cu_cp/adapters/du_processor_adapters.h | 3 +- lib/cu_cp/cu_cp_impl.cpp | 2 +- lib/cu_cp/du_processor/du_processor.h | 13 ++----- lib/cu_cp/du_processor/du_processor_impl.cpp | 1 - .../inter_cu_handover_target_routine.cpp | 2 +- .../mobility/inter_du_handover_routine.cpp | 4 +-- ..._session_resource_modification_routine.cpp | 2 +- ...du_session_resource_modification_routine.h | 16 ++++----- .../pdu_session_resource_release_routine.cpp | 2 +- .../pdu_session_resource_release_routine.h | 16 ++++----- .../pdu_session_resource_setup_routine.cpp | 2 +- .../pdu_session_resource_setup_routine.h | 16 ++++----- ...blishment_context_modification_routine.cpp | 18 +++++----- ...tablishment_context_modification_routine.h | 36 +++++++++---------- lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp | 24 +++---------- lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 22 ++++-------- .../handover_reconfiguration_routine_test.cpp | 22 ++++++------ tests/unittests/cu_cp/test_helpers.h | 28 ++++++--------- .../ue_manager/ue_manager_test_helpers.h | 4 +-- 19 files changed, 97 insertions(+), 136 deletions(-) diff --git a/lib/cu_cp/adapters/du_processor_adapters.h b/lib/cu_cp/adapters/du_processor_adapters.h index f786619438..2020e4f8a3 100644 --- a/lib/cu_cp/adapters/du_processor_adapters.h +++ b/lib/cu_cp/adapters/du_processor_adapters.h @@ -141,8 +141,7 @@ class du_processor_rrc_du_adapter : public du_processor_rrc_du_ue_notifier }; // Adapter between DU processor and RRC UE -class du_processor_rrc_ue_adapter : public du_processor_rrc_ue_control_message_notifier, - public du_processor_rrc_ue_srb_control_notifier +class du_processor_rrc_ue_adapter : public du_processor_rrc_ue_notifier { public: du_processor_rrc_ue_adapter() = default; diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 49fe05d912..06de67b687 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -217,7 +217,7 @@ cu_cp_impl::handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, return reest_context; } - auto srbs = old_ue->get_rrc_ue_srb_notifier().get_srbs(); + auto srbs = old_ue->get_rrc_ue_notifier().get_srbs(); if (std::find(srbs.begin(), srbs.end(), srb_id_t::srb2) == srbs.end()) { logger.debug("ue={}: SRB2 not setup for this UE - rejecting RRC reestablishment", old_ue_index); reest_context.ue_index = old_ue_index; diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 5ac6d3f60f..ade2c889c7 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -98,11 +98,11 @@ class du_processor_rrc_du_ue_notifier virtual void on_release_ues() = 0; }; -/// Interface to notify an RRC UE about control messages. -class du_processor_rrc_ue_control_message_notifier +/// Interface to notify an RRC UE about control and srb messages. +class du_processor_rrc_ue_notifier { public: - virtual ~du_processor_rrc_ue_control_message_notifier() = default; + virtual ~du_processor_rrc_ue_notifier() = default; /// \brief Notify the RRC UE to trigger a UE capability transfer procedure. /// \param[in] msg The new request msg containing the RAT type, etc. @@ -153,13 +153,6 @@ class du_processor_rrc_ue_control_message_notifier /// \returns The RRC Handover Command PDU. virtual byte_buffer on_rrc_handover_command_required(const rrc_reconfiguration_procedure_request& request, unsigned transaction_id) = 0; -}; - -/// Interface to notify an RRC UE about SRB control queries (e.g. SRB creation). -class du_processor_rrc_ue_srb_control_notifier -{ -public: - virtual ~du_processor_rrc_ue_srb_control_notifier() = default; /// \brief Create an SRB at the target RRC UE. virtual void create_srb(const srb_creation_message& msg) = 0; diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index 89db582ddd..0cf4adea54 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -182,7 +182,6 @@ bool du_processor_impl::create_rrc_ue(cu_cp_ue& ue, rrc_ue_adapters.at(ue.get_ue_index()) .connect_rrc_ue(rrc_ue->get_rrc_ue_control_message_handler(), rrc_ue->get_rrc_ue_srb_handler()); ue.set_rrc_ue_notifier(rrc_ue_adapters.at(ue.get_ue_index())); - ue.set_rrc_ue_srb_notifier(rrc_ue_adapters.at(ue.get_ue_index())); // Notify CU-CP about the creation of the RRC UE cu_cp_notifier.on_rrc_ue_created(ue.get_ue_index(), *rrc_ue); diff --git a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp index 97fb62b9b8..a169f6b21a 100644 --- a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp @@ -273,7 +273,7 @@ void inter_cu_handover_target_routine::create_srb1() srb1_msg.srb_id = srb_id_t::srb1; srb1_msg.pdcp_cfg = {}; srb1_msg.enable_security = true; - ue_mng.find_du_ue(request.ue_index)->get_rrc_ue_srb_notifier().create_srb(srb1_msg); + ue_mng.find_du_ue(request.ue_index)->get_rrc_ue_notifier().create_srb(srb1_msg); } ngap_handover_resource_allocation_response diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index c3338eacb2..c2309bb731 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -97,7 +97,7 @@ void inter_du_handover_routine::operator()(coro_contextget_rrc_ue_srb_notifier().get_srbs(), source_rrc_context)) { + target_ue_context_setup_request, source_ue->get_rrc_ue_notifier().get_srbs(), source_rrc_context)) { logger.warning("ue={}: \"{}\" failed to generate UeContextSetupRequest", request.source_ue_index, name()); CORO_EARLY_RETURN(response_msg); } @@ -298,7 +298,7 @@ void inter_du_handover_routine::create_srb(cu_cp_ue* ue, srb_id_t srb_id) srb_msg.srb_id = srb_id; srb_msg.enable_security = true; // TODO: add support for non-default PDCP config. - ue->get_rrc_ue_srb_notifier().create_srb(srb_msg); + ue->get_rrc_ue_notifier().create_srb(srb_msg); } bool inter_du_handover_routine::add_security_context_to_bearer_context_modification( diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index 0986f59482..a4b84f86d2 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -45,7 +45,7 @@ pdu_session_resource_modification_routine::pdu_session_resource_modification_rou const cu_cp_pdu_session_resource_modify_request& modify_request_, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& ue_task_sched_, up_resource_manager& up_resource_mng_, diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.h b/lib/cu_cp/routines/pdu_session_resource_modification_routine.h index 44b56be8fd..de28fb01e5 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.h @@ -28,7 +28,7 @@ class pdu_session_resource_modification_routine pdu_session_resource_modification_routine(const cu_cp_pdu_session_resource_modify_request& modify_request_, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& ue_task_sched_, up_resource_manager& up_resource_mng_, @@ -49,13 +49,13 @@ class pdu_session_resource_modification_routine up_config_update next_config; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP - ue_task_scheduler& ue_task_sched; // to schedule UE release request - up_resource_manager& up_resource_mng; // to get RRC DRB config - srslog::basic_logger& logger; + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP + ue_task_scheduler& ue_task_sched; // to schedule UE release request + up_resource_manager& up_resource_mng; // to get RRC DRB config + srslog::basic_logger& logger; // (sub-)routine requests e1ap_bearer_context_modification_request bearer_context_modification_request; diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp index 0af073ffde..ff1bdca7d3 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -19,7 +19,7 @@ pdu_session_resource_release_routine::pdu_session_resource_release_routine( const cu_cp_pdu_session_resource_release_command& release_cmd_, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& task_sched_, up_resource_manager& up_resource_mng_, diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.h b/lib/cu_cp/routines/pdu_session_resource_release_routine.h index 3eeb4ec344..88e3cf30bd 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.h @@ -28,7 +28,7 @@ class pdu_session_resource_release_routine pdu_session_resource_release_routine(const cu_cp_pdu_session_resource_release_command& release_cmd_, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& task_sched_, up_resource_manager& up_resource_mng_, @@ -48,13 +48,13 @@ class pdu_session_resource_release_routine up_config_update next_config; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP - ue_task_scheduler& task_sched; // to schedule UE release request - up_resource_manager& up_resource_mng; // to get RRC DRB config - srslog::basic_logger& logger; + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP + ue_task_scheduler& task_sched; // to schedule UE release request + up_resource_manager& up_resource_mng; // to get RRC DRB config + srslog::basic_logger& logger; // (sub-)routine requests f1ap_ue_context_modification_request ue_context_mod_request; diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 1fd215a2fa..1b204e1e93 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -59,7 +59,7 @@ pdu_session_resource_setup_routine::pdu_session_resource_setup_routine( const security_indication_t& default_security_indication_, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& ue_task_sched_, up_resource_manager& up_resource_mng_, diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.h b/lib/cu_cp/routines/pdu_session_resource_setup_routine.h index eae1bb21e8..064f33aa79 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.h @@ -47,7 +47,7 @@ class pdu_session_resource_setup_routine const security_indication_t& default_security_indication_, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& ue_task_sched_, up_resource_manager& up_resource_mng_, @@ -70,13 +70,13 @@ class pdu_session_resource_setup_routine up_config_update next_config; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP - ue_task_scheduler& ue_task_sched; // to schedule UE release request - up_resource_manager& up_resource_mng; // to get RRC DRB config - srslog::basic_logger& logger; + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP + ue_task_scheduler& ue_task_sched; // to schedule UE release request + up_resource_manager& up_resource_mng; // to get RRC DRB config + srslog::basic_logger& logger; // (sub-)routine requests e1ap_bearer_context_setup_request bearer_context_setup_request; diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index fe061138ef..2f42a55c73 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -18,15 +18,15 @@ using namespace srsran::srs_cu_cp; using namespace asn1::rrc_nr; reestablishment_context_modification_routine::reestablishment_context_modification_routine( - ue_index_t ue_index_, - const srsran::security::sec_as_config& security_cfg_, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - cu_cp_rrc_ue_interface& cu_cp_notifier_, - ue_task_scheduler& ue_task_sched_, - up_resource_manager& up_resource_mng_, - srslog::basic_logger& logger_) : + ue_index_t ue_index_, + const srsran::security::sec_as_config& security_cfg_, + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, + f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, + cu_cp_rrc_ue_interface& cu_cp_notifier_, + ue_task_scheduler& ue_task_sched_, + up_resource_manager& up_resource_mng_, + srslog::basic_logger& logger_) : ue_index(ue_index_), security_cfg(security_cfg_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.h b/lib/cu_cp/routines/reestablishment_context_modification_routine.h index 163eb9494e..6b016f9d4f 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.h +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.h @@ -26,15 +26,15 @@ namespace srs_cu_cp { class reestablishment_context_modification_routine { public: - reestablishment_context_modification_routine(ue_index_t ue_index_, - const srsran::security::sec_as_config& security_cfg_, - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, - f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - cu_cp_rrc_ue_interface& cu_cp_notifier_, - ue_task_scheduler& ue_task_sched_, - up_resource_manager& up_resource_mng_, - srslog::basic_logger& logger_); + reestablishment_context_modification_routine(ue_index_t ue_index_, + const srsran::security::sec_as_config& security_cfg_, + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, + f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, + du_processor_rrc_ue_notifier& rrc_ue_notifier_, + cu_cp_rrc_ue_interface& cu_cp_notifier_, + ue_task_scheduler& ue_task_sched_, + up_resource_manager& up_resource_mng_, + srslog::basic_logger& logger_); void operator()(coro_context>& ctx); @@ -53,15 +53,15 @@ class reestablishment_context_modification_routine up_resource_manager& up_resource_manager, bool reestablish_pdcp); - ue_index_t ue_index = ue_index_t::invalid; - security::sec_as_config security_cfg; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP - ue_task_scheduler& ue_task_sched; // to schedule UE release request - up_resource_manager& up_resource_mng; // to get RRC DRB config - srslog::basic_logger& logger; + ue_index_t ue_index = ue_index_t::invalid; + security::sec_as_config security_cfg; + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + cu_cp_rrc_ue_interface& cu_cp_notifier; // to trigger UE release at CU-CP + ue_task_scheduler& ue_task_sched; // to schedule UE release request + up_resource_manager& up_resource_mng; // to get RRC DRB config + srslog::basic_logger& logger; // (sub-)routine requests e1ap_bearer_context_modification_request bearer_context_modification_request; diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp index 857b0dd8e7..97c9a37a17 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp @@ -76,20 +76,13 @@ void cu_cp_ue::update_meas_context(cell_meas_manager_ue_context meas_ctxt) meas_context = std::move(meas_ctxt); } -/// \brief Set the RRC UE control message notifier of the UE. -/// \param[in] rrc_ue_notifier_ RRC UE control message notifier of the UE. -void cu_cp_ue::set_rrc_ue_notifier(du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_) +/// \brief Set the RRC UE notifier of the UE. +/// \param[in] rrc_ue_notifier_ RRC UE notifier of the UE. +void cu_cp_ue::set_rrc_ue_notifier(du_processor_rrc_ue_notifier& rrc_ue_notifier_) { rrc_ue_notifier = &rrc_ue_notifier_; } -/// \brief Set the RRC UE SRB notifier of the UE. -/// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. -void cu_cp_ue::set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_) -{ - rrc_ue_srb_notifier = &rrc_ue_srb_notifier_; -} - /// \brief Set the RRC UE of the UE. /// \param[in] rrc_ue_ RRC UE of the UE. void cu_cp_ue::set_rrc_ue(rrc_ue_interface& rrc_ue_) @@ -103,16 +96,9 @@ ngap_rrc_ue_notifier& cu_cp_ue::get_ngap_rrc_ue_notifier() return ngap_rrc_ue_ev_notifier; } -/// \brief Get the RRC UE control message notifier of the UE. -du_processor_rrc_ue_control_message_notifier& cu_cp_ue::get_rrc_ue_notifier() +/// \brief Get the RRC UE notifier of the UE. +du_processor_rrc_ue_notifier& cu_cp_ue::get_rrc_ue_notifier() { srsran_assert(rrc_ue_notifier != nullptr, "ue={}: RRC UE notifier was not set", ue_index); return *rrc_ue_notifier; } - -/// \brief Get the RRC UE SRB control notifier of the UE. -du_processor_rrc_ue_srb_control_notifier& cu_cp_ue::get_rrc_ue_srb_notifier() -{ - srsran_assert(rrc_ue_srb_notifier != nullptr, "ue={}: RRC UE SRB notifier was not set", ue_index); - return *rrc_ue_srb_notifier; -} diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index e36e5f9c73..9e19ee65ef 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -96,13 +96,9 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \return True if the DU UE context is created, false otherwise. [[nodiscard]] bool du_ue_created() const { return ue_ctxt.du_idx != du_index_t::invalid; } - /// \brief Set the RRC UE control message notifier of the UE. - /// \param[in] rrc_ue_notifier_ RRC UE control message notifier of the UE. - void set_rrc_ue_notifier(du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_); - - /// \brief Set the RRC UE SRB notifier of the UE. - /// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. - void set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_); + /// \brief Set the RRC UE notifier of the UE. + /// \param[in] rrc_ue_notifier_ RRC UE notifier of the UE. + void set_rrc_ue_notifier(du_processor_rrc_ue_notifier& rrc_ue_notifier_); /// \brief Set the RRC UE of the UE. void set_rrc_ue(rrc_ue_interface& rrc_ue_); @@ -116,11 +112,8 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \brief Get the RRC UE CU-CP UE notifier of the UE. rrc_ue_cu_cp_ue_notifier& get_rrc_ue_cu_cp_ue_notifier() { return rrc_ue_cu_cp_ue_ev_notifier; } - /// \brief Get the RRC UE control message notifier of the UE. - du_processor_rrc_ue_control_message_notifier& get_rrc_ue_notifier(); - - /// \brief Get the RRC UE SRB control notifier of the UE. - du_processor_rrc_ue_srb_control_notifier& get_rrc_ue_srb_notifier(); + /// \brief Get the RRC UE notifier of the UE. + du_processor_rrc_ue_notifier& get_rrc_ue_notifier(); rrc_ue_context_update_notifier& get_rrc_ue_context_update_notifier() { return rrc_ue_cu_cp_ev_notifier; } @@ -148,9 +141,8 @@ class cu_cp_ue : public cu_cp_ue_impl_interface du_cell_index_t pcell_index = du_cell_index_t::invalid; pci_t pci = INVALID_PCI; - rrc_ue_cu_cp_ue_adapter rrc_ue_cu_cp_ue_ev_notifier; - du_processor_rrc_ue_control_message_notifier* rrc_ue_notifier = nullptr; - du_processor_rrc_ue_srb_control_notifier* rrc_ue_srb_notifier = nullptr; + rrc_ue_cu_cp_ue_adapter rrc_ue_cu_cp_ue_ev_notifier; + du_processor_rrc_ue_notifier* rrc_ue_notifier = nullptr; // rrc ue rrc_ue_interface* rrc_ue = nullptr; diff --git a/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp b/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp index 2673c2a006..1e25d8a1b2 100644 --- a/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp +++ b/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp @@ -62,19 +62,19 @@ class handover_reconfiguration_routine_test : public mobility_test private: // source UE parameters. - du_index_t source_du_index = uint_to_du_index(0); - pci_t source_pci = 1; - rnti_t source_rnti = to_rnti(0x4601); - dummy_du_processor_rrc_ue_control_message_notifier source_rrc_ue_notifier; - dummy_f1ap_ue_context_manager source_f1ap_ue_ctxt_mng; - cu_cp_ue* source_ue = nullptr; + du_index_t source_du_index = uint_to_du_index(0); + pci_t source_pci = 1; + rnti_t source_rnti = to_rnti(0x4601); + dummy_du_processor_rrc_ue_notifier source_rrc_ue_notifier; + dummy_f1ap_ue_context_manager source_f1ap_ue_ctxt_mng; + cu_cp_ue* source_ue = nullptr; // target UE parameters. - du_index_t target_du_index = uint_to_du_index(1); - pci_t target_pci = 2; - rnti_t target_rnti = to_rnti(0x4601); - dummy_du_processor_rrc_ue_control_message_notifier target_rrc_ue_notifier; - cu_cp_ue* target_ue = nullptr; + du_index_t target_du_index = uint_to_du_index(1); + pci_t target_pci = 2; + rnti_t target_rnti = to_rnti(0x4601); + dummy_du_processor_rrc_ue_notifier target_rrc_ue_notifier; + cu_cp_ue* target_ue = nullptr; async_task t; std::optional> t_launcher; diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index 887bcbcf34..9d48fd4330 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -515,9 +515,9 @@ struct dummy_f1ap_ue_context_manager : public f1ap_ue_context_manager { f1ap_ue_context_modification_request ue_context_modifcation_request; }; -struct dummy_du_processor_rrc_ue_control_message_notifier : public du_processor_rrc_ue_control_message_notifier { +struct dummy_du_processor_rrc_ue_notifier : public du_processor_rrc_ue_notifier { public: - dummy_du_processor_rrc_ue_control_message_notifier() = default; + dummy_du_processor_rrc_ue_notifier() = default; void set_rrc_reconfiguration_outcome(bool outcome) { rrc_reconfiguration_outcome = outcome; } @@ -595,21 +595,6 @@ struct dummy_du_processor_rrc_ue_control_message_notifier : public du_processor_ return byte_buffer{}; } - std::optional last_radio_bearer_cfg; - - void reset() { last_radio_bearer_cfg.reset(); } - - unsigned last_transaction_id; - -private: - srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); - bool ue_cap_transfer_outcome = true; - bool rrc_reconfiguration_outcome = false; - unsigned transaction_id; -}; - -struct dummy_du_processor_rrc_ue_srb_control_notifier : public du_processor_rrc_ue_srb_control_notifier { -public: void create_srb(const srb_creation_message& msg) override { logger.info("ue={} Creating {}", msg.ue_index, msg.srb_id); @@ -619,10 +604,17 @@ struct dummy_du_processor_rrc_ue_srb_control_notifier : public du_processor_rrc_ static_vector get_srbs() override { return srb_vec; } + std::optional last_radio_bearer_cfg; + void reset() { last_radio_bearer_cfg.reset(); } + + unsigned last_transaction_id; srb_id_t last_srb_id; private: - srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); + srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); + bool ue_cap_transfer_outcome = true; + bool rrc_reconfiguration_outcome = false; + unsigned transaction_id; static_vector srb_vec; }; diff --git a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h index 09e0c1ede2..714e525a18 100644 --- a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h +++ b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h @@ -41,8 +41,8 @@ class ue_manager_test : public ::testing::Test ue_manager ue_mng{cu_cp_cfg}; // DU processor to RRC UE adapters - std::unordered_map rrc_ue_adapters; - dummy_ngap_rrc_ue_notifier rrc_ue_pdu_notifier; + std::unordered_map rrc_ue_adapters; + dummy_ngap_rrc_ue_notifier rrc_ue_pdu_notifier; }; } // namespace srs_cu_cp From e7e75122d1001f3c6a3246df1ffe30fab1536321 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Aug 2024 10:27:12 +0200 Subject: [PATCH 350/407] cu_cp,ngap,rrc: simplify rrc ue ngap message handler --- include/srsran/rrc/rrc_ue.h | 54 +++++++------------ lib/cu_cp/adapters/ngap_adapters.h | 25 +++------ lib/cu_cp/cu_cp_impl.cpp | 4 +- lib/rrc/ue/rrc_ue_impl.h | 24 ++++----- tests/unittests/ngap/ngap_handover_test.cpp | 2 +- .../unittests/ngap/ngap_nas_message_test.cpp | 4 +- tests/unittests/ngap/ngap_test_helpers.cpp | 8 +-- tests/unittests/ngap/ngap_test_helpers.h | 6 +-- ...p_ue_context_management_procedure_test.cpp | 14 ++--- tests/unittests/ngap/test_helpers.h | 28 ++-------- 10 files changed, 56 insertions(+), 113 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index df51057e97..1eeb70d291 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -67,16 +67,23 @@ class rrc_ul_pdu_handler virtual void handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdu) = 0; }; -/// This interface represents the data entry point for the RRC receiving NAS PDUs. +/// This interface represents the data entry point for the RRC receiving NAS and control messages from the NGAP. /// The higher-layers will use this class to pass PDUs into the RRC. -class rrc_dl_nas_message_handler +class rrc_ngap_message_handler { public: - virtual ~rrc_dl_nas_message_handler() = default; + virtual ~rrc_ngap_message_handler() = default; /// \brief Handle the received Downlink NAS Transport message. /// \param[in] nas_pdu The received NAS PDU. virtual void handle_dl_nas_transport_message(byte_buffer nas_pdu) = 0; + + /// \brief Get the packed UE Radio Access Cap Info. + /// \returns The packed UE Radio Access Cap Info. + virtual byte_buffer get_packed_ue_radio_access_cap_info() const = 0; + + /// \brief Get the packed Handover Preparation Message. + virtual byte_buffer get_packed_handover_preparation_message() = 0; }; /// Interface to notify F1AP about a new SRB PDU. @@ -296,27 +303,6 @@ class rrc_ue_control_message_handler virtual byte_buffer get_packed_handover_preparation_message() = 0; }; -/// Handler to get the UE radio access capability info to the NGAP. -class rrc_ue_radio_access_capability_handler -{ -public: - virtual ~rrc_ue_radio_access_capability_handler() = default; - - /// \brief Get the packed UE Radio Access Cap Info. - /// \returns The packed UE Radio Access Cap Info. - virtual byte_buffer get_packed_ue_radio_access_cap_info() const = 0; -}; - -/// Handler to get the handover preparation context to the NGAP. -class rrc_ue_handover_preparation_handler -{ -public: - virtual ~rrc_ue_handover_preparation_handler() = default; - - /// \brief Get the packed Handover Preparation Message. - virtual byte_buffer get_packed_handover_preparation_message() = 0; -}; - class rrc_ue_cu_cp_ue_notifier { public: @@ -441,29 +427,25 @@ class rrc_ue_context_handler /// Combined entry point for the RRC UE handling. /// It will contain getters for the interfaces for the various logical channels handled by RRC. class rrc_ue_interface : public rrc_ul_pdu_handler, - public rrc_dl_nas_message_handler, + public rrc_ngap_message_handler, public rrc_ue_srb_handler, public rrc_ue_control_message_handler, - public rrc_ue_radio_access_capability_handler, public rrc_ue_setup_proc_notifier, public rrc_ue_security_mode_command_proc_notifier, public rrc_ue_reconfiguration_proc_notifier, public rrc_ue_context_handler, - public rrc_ue_reestablishment_proc_notifier, - public rrc_ue_handover_preparation_handler + public rrc_ue_reestablishment_proc_notifier { public: rrc_ue_interface() = default; virtual ~rrc_ue_interface() = default; - virtual rrc_ue_controller& get_controller() = 0; - virtual rrc_ul_pdu_handler& get_ul_pdu_handler() = 0; - virtual rrc_dl_nas_message_handler& get_rrc_dl_nas_message_handler() = 0; - virtual rrc_ue_srb_handler& get_rrc_ue_srb_handler() = 0; - virtual rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() = 0; - virtual rrc_ue_radio_access_capability_handler& get_rrc_ue_radio_access_capability_handler() = 0; - virtual rrc_ue_context_handler& get_rrc_ue_context_handler() = 0; - virtual rrc_ue_handover_preparation_handler& get_rrc_ue_handover_preparation_handler() = 0; + virtual rrc_ue_controller& get_controller() = 0; + virtual rrc_ul_pdu_handler& get_ul_pdu_handler() = 0; + virtual rrc_ngap_message_handler& get_rrc_ngap_message_handler() = 0; + virtual rrc_ue_srb_handler& get_rrc_ue_srb_handler() = 0; + virtual rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() = 0; + virtual rrc_ue_context_handler& get_rrc_ue_context_handler() = 0; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index 23a3414e71..9c70a7dfad 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -173,37 +173,28 @@ class ngap_rrc_ue_adapter : public ngap_rrc_ue_notifier public: ngap_rrc_ue_adapter() = default; - void connect_rrc_ue(rrc_dl_nas_message_handler& rrc_ue_msg_handler_, - rrc_ue_radio_access_capability_handler& rrc_ue_radio_access_cap_handler_, - rrc_ue_handover_preparation_handler& rrc_ue_ho_prep_handler_) - { - rrc_ue_msg_handler = &rrc_ue_msg_handler_; - rrc_ue_radio_access_cap_handler = &rrc_ue_radio_access_cap_handler_; - rrc_ue_ho_prep_handler = &rrc_ue_ho_prep_handler_; - } + void connect_rrc_ue(rrc_ngap_message_handler& rrc_ue_handler_) { rrc_ue_handler = &rrc_ue_handler_; } void on_new_pdu(byte_buffer nas_pdu) override { - srsran_assert(rrc_ue_msg_handler != nullptr, "RRC UE message handler must not be nullptr"); - rrc_ue_msg_handler->handle_dl_nas_transport_message(std::move(nas_pdu)); + srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); + rrc_ue_handler->handle_dl_nas_transport_message(std::move(nas_pdu)); } byte_buffer on_ue_radio_access_cap_info_required() override { - srsran_assert(rrc_ue_radio_access_cap_handler != nullptr, "RRC UE Radio Access Cap handler must not be nullptr"); - return rrc_ue_radio_access_cap_handler->get_packed_ue_radio_access_cap_info(); + srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); + return rrc_ue_handler->get_packed_ue_radio_access_cap_info(); } byte_buffer on_handover_preparation_message_required() override { - srsran_assert(rrc_ue_ho_prep_handler != nullptr, "RRC UE UP manager must not be nullptr"); - return rrc_ue_ho_prep_handler->get_packed_handover_preparation_message(); + srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); + return rrc_ue_handler->get_packed_handover_preparation_message(); } private: - rrc_dl_nas_message_handler* rrc_ue_msg_handler = nullptr; - rrc_ue_radio_access_capability_handler* rrc_ue_radio_access_cap_handler = nullptr; - rrc_ue_handover_preparation_handler* rrc_ue_ho_prep_handler = nullptr; + rrc_ngap_message_handler* rrc_ue_handler = nullptr; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 06de67b687..e108be01fe 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -664,9 +664,7 @@ void cu_cp_impl::handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& r ue->set_rrc_ue(rrc_ue); // Connect RRC UE to NGAP to RRC UE adapter - ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(rrc_ue.get_rrc_dl_nas_message_handler(), - rrc_ue.get_rrc_ue_radio_access_capability_handler(), - rrc_ue.get_rrc_ue_handover_preparation_handler()); + ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(rrc_ue.get_rrc_ngap_message_handler()); // Connect cu-cp to rrc ue adapters ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp(get_cu_cp_rrc_ue_interface(), diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index 604e3a9d7b..4b6fc6c04e 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -43,21 +43,20 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller void handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdcp_pdu) override; // rrc_ue_interface - rrc_ue_controller& get_controller() override { return *this; } - rrc_ul_pdu_handler& get_ul_pdu_handler() override { return *this; } - rrc_dl_nas_message_handler& get_rrc_dl_nas_message_handler() override { return *this; } - rrc_ue_srb_handler& get_rrc_ue_srb_handler() override { return *this; } - rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() override { return *this; } - rrc_ue_radio_access_capability_handler& get_rrc_ue_radio_access_capability_handler() override { return *this; } - rrc_ue_context_handler& get_rrc_ue_context_handler() override { return *this; } - rrc_ue_handover_preparation_handler& get_rrc_ue_handover_preparation_handler() override { return *this; } + rrc_ue_controller& get_controller() override { return *this; } + rrc_ul_pdu_handler& get_ul_pdu_handler() override { return *this; } + rrc_ngap_message_handler& get_rrc_ngap_message_handler() override { return *this; } + rrc_ue_srb_handler& get_rrc_ue_srb_handler() override { return *this; } + rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() override { return *this; } + rrc_ue_context_handler& get_rrc_ue_context_handler() override { return *this; } // rrc_ue_srb_handler void create_srb(const srb_creation_message& msg) override; static_vector get_srbs() override; - // rrc_dl_nas_message_handler - void handle_dl_nas_transport_message(byte_buffer nas_pdu) override; + // rrc_ngap_message_handler + void handle_dl_nas_transport_message(byte_buffer nas_pdu) override; + byte_buffer get_packed_handover_preparation_message() override; // rrc_ue_control_message_handler rrc_ue_security_mode_command_context get_security_mode_command_context() override; @@ -75,10 +74,7 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller std::optional generate_meas_config(std::optional current_meas_config) override; byte_buffer get_rrc_handover_command(const rrc_reconfiguration_procedure_request& request, unsigned transaction_id) override; - - // rrc_ue_handover_preparation_handler - byte_buffer get_packed_handover_preparation_message() override; - byte_buffer handle_rrc_handover_command(byte_buffer cmd) override; + byte_buffer handle_rrc_handover_command(byte_buffer cmd) override; // rrc_ue_context_handler rrc_ue_reestablishment_context_response get_context() override; diff --git a/tests/unittests/ngap/ngap_handover_test.cpp b/tests/unittests/ngap/ngap_handover_test.cpp index ea27ad1a5f..51846830d5 100644 --- a/tests/unittests/ngap/ngap_handover_test.cpp +++ b/tests/unittests/ngap/ngap_handover_test.cpp @@ -51,7 +51,7 @@ TEST_F(ngap_test, when_source_gnb_handover_preparation_triggered_then_ho_command add_pdu_session_to_up_manager(ue_index, uint_to_pdu_session_id(1), uint_to_drb_id(0), uint_to_qos_flow_id(0)); auto& ue = test_ues.at(ue_index); - ue.rrc_ue_ho_prep_handler.set_ho_preparation_message({}); + ue.rrc_ue_handler.set_ho_preparation_message({}); ngap_handover_preparation_request request = generate_handover_preparation_request(ue_index, diff --git a/tests/unittests/ngap/ngap_nas_message_test.cpp b/tests/unittests/ngap/ngap_nas_message_test.cpp index 6580473fd0..cadff55433 100644 --- a/tests/unittests/ngap/ngap_nas_message_test.cpp +++ b/tests/unittests/ngap/ngap_nas_message_test.cpp @@ -35,10 +35,10 @@ class ngap_nas_message_routine_test : public ngap_test bool was_dl_nas_transport_forwarded(const test_ue& ue) const { - return ue.rrc_ue_dl_nas_handler.last_nas_pdu.length() == nas_pdu_len; + return ue.rrc_ue_handler.last_nas_pdu.length() == nas_pdu_len; } - bool was_dl_nas_transport_dropped(const test_ue& ue) const { return ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty(); } + bool was_dl_nas_transport_dropped(const test_ue& ue) const { return ue.rrc_ue_handler.last_nas_pdu.empty(); } bool was_ue_radio_capability_info_indication_sent() const { diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index 0e7141d74b..d109bf3f0d 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -66,9 +66,7 @@ ue_index_t ngap_test::create_ue(rnti_t rnti) test_ues.emplace(ue_index, test_ue(ue_index)); test_ue& new_test_ue = test_ues.at(ue_index); - ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(new_test_ue.rrc_ue_dl_nas_handler, - new_test_ue.rrc_ue_radio_access_cap_handler, - new_test_ue.rrc_ue_ho_prep_handler); + ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(new_test_ue.rrc_ue_handler); // generate and inject valid initial ue message cu_cp_initial_ue_message msg = generate_initial_ue_message(ue_index); @@ -94,9 +92,7 @@ ue_index_t ngap_test::create_ue_without_init_ue_message(rnti_t rnti) test_ues.emplace(ue_index, test_ue(ue_index)); test_ue& new_test_ue = test_ues.at(ue_index); - ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(new_test_ue.rrc_ue_dl_nas_handler, - new_test_ue.rrc_ue_radio_access_cap_handler, - new_test_ue.rrc_ue_ho_prep_handler); + ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(new_test_ue.rrc_ue_handler); return ue_index; } diff --git a/tests/unittests/ngap/ngap_test_helpers.h b/tests/unittests/ngap/ngap_test_helpers.h index b4dc924214..2e2c4a24fb 100644 --- a/tests/unittests/ngap/ngap_test_helpers.h +++ b/tests/unittests/ngap/ngap_test_helpers.h @@ -30,15 +30,13 @@ class ngap_test : public ::testing::Test class test_ue { public: - test_ue(ue_index_t ue_index_) : ue_index(ue_index_), rrc_ue_dl_nas_handler(ue_index_) {} + test_ue(ue_index_t ue_index_) : ue_index(ue_index_), rrc_ue_handler(ue_index_) {} ue_index_t ue_index = ue_index_t::invalid; std::optional amf_ue_id; std::optional ran_ue_id; - dummy_rrc_dl_nas_message_handler rrc_ue_dl_nas_handler; - dummy_rrc_ue_radio_access_capability_handler rrc_ue_radio_access_cap_handler; - dummy_rrc_ue_handover_preparation_handler rrc_ue_ho_prep_handler; + dummy_rrc_ngap_message_handler rrc_ue_handler; }; ngap_test(); diff --git a/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp b/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp index 706986704c..cf7242079a 100644 --- a/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp @@ -399,25 +399,25 @@ TEST_F(ngap_ue_context_management_procedure_test, when_ue_context_is_tranfered_a ASSERT_NE(ran_id, ran_ue_id_t::invalid); // Clear NAS PDU. - ue.rrc_ue_dl_nas_handler.last_nas_pdu.clear(); - ASSERT_TRUE(ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); + ue.rrc_ue_handler.last_nas_pdu.clear(); + ASSERT_TRUE(ue.rrc_ue_handler.last_nas_pdu.empty()); // Inject new DL NAS transport from core. ngap_message dl_nas_transport = generate_downlink_nas_transport_message(amf_id, ue.ran_ue_id.value()); ngap->handle_message(dl_nas_transport); // Check NAS PDU has been passed to RRC. - ASSERT_FALSE(ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); + ASSERT_FALSE(ue.rrc_ue_handler.last_nas_pdu.empty()); // Clear PDU again. - ue.rrc_ue_dl_nas_handler.last_nas_pdu.clear(); + ue.rrc_ue_handler.last_nas_pdu.clear(); // Create new UE object (with own RRC UE notifier). ue_index_t target_ue_index = create_ue_without_init_ue_message(rnti_t::MAX_CRNTI); ASSERT_NE(target_ue_index, ue_index_t::invalid); ASSERT_NE(target_ue_index, ue_index); auto& target_ue = test_ues.at(target_ue_index); - ASSERT_TRUE(target_ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); + ASSERT_TRUE(target_ue.rrc_ue_handler.last_nas_pdu.empty()); // Transfer NGAP UE context to new target UE. ngap->update_ue_index(target_ue_index, ue_index, ue_mng.find_ue(target_ue_index)->get_ngap_cu_cp_ue_notifier()); @@ -426,8 +426,8 @@ TEST_F(ngap_ue_context_management_procedure_test, when_ue_context_is_tranfered_a ngap->handle_message(dl_nas_transport); // Check that RRC notifier of initial UE has not been called. - ASSERT_TRUE(ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); + ASSERT_TRUE(ue.rrc_ue_handler.last_nas_pdu.empty()); // Verify that RRC notifier of target UE has indeed benn called. - ASSERT_FALSE(target_ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); + ASSERT_FALSE(target_ue.rrc_ue_handler.last_nas_pdu.empty()); } diff --git a/tests/unittests/ngap/test_helpers.h b/tests/unittests/ngap/test_helpers.h index a549c0fcd1..3c2a707e75 100644 --- a/tests/unittests/ngap/test_helpers.h +++ b/tests/unittests/ngap/test_helpers.h @@ -371,10 +371,10 @@ class dummy_ngap_cu_cp_notifier : public ngap_cu_cp_notifier uint64_t ue_id = ue_index_to_uint(srs_cu_cp::ue_index_t::min); }; -class dummy_rrc_dl_nas_message_handler : public rrc_dl_nas_message_handler +class dummy_rrc_ngap_message_handler : public rrc_ngap_message_handler { public: - dummy_rrc_dl_nas_message_handler(ue_index_t ue_index_) : + dummy_rrc_ngap_message_handler(ue_index_t ue_index_) : ue_index(ue_index_), logger(srslog::fetch_basic_logger("TEST")){}; void handle_dl_nas_transport_message(byte_buffer nas_pdu) override @@ -383,29 +383,8 @@ class dummy_rrc_dl_nas_message_handler : public rrc_dl_nas_message_handler last_nas_pdu = std::move(nas_pdu); } - byte_buffer last_nas_pdu; - -private: - ue_index_t ue_index = ue_index_t::invalid; - srslog::basic_logger& logger; -}; - -class dummy_rrc_ue_radio_access_capability_handler : public rrc_ue_radio_access_capability_handler -{ -public: - dummy_rrc_ue_radio_access_capability_handler() : logger(srslog::fetch_basic_logger("TEST")){}; - byte_buffer get_packed_ue_radio_access_cap_info() const override { return make_byte_buffer("deadbeef").value(); } -private: - srslog::basic_logger& logger; -}; - -class dummy_rrc_ue_handover_preparation_handler : public rrc_ue_handover_preparation_handler -{ -public: - dummy_rrc_ue_handover_preparation_handler() : logger(srslog::fetch_basic_logger("TEST")){}; - void set_ho_preparation_message(byte_buffer ho_preparation_message_) { ho_preparation_message = std::move(ho_preparation_message_); @@ -413,7 +392,10 @@ class dummy_rrc_ue_handover_preparation_handler : public rrc_ue_handover_prepara byte_buffer get_packed_handover_preparation_message() override { return ho_preparation_message.copy(); } + byte_buffer last_nas_pdu; + private: + ue_index_t ue_index = ue_index_t::invalid; srslog::basic_logger& logger; byte_buffer ho_preparation_message; }; From 112dbcec2487a9ac2d9adc4d4959fba813ed61d6 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Aug 2024 10:37:31 +0200 Subject: [PATCH 351/407] cu_cp,rrc: combine control message handler and srb handler --- include/srsran/rrc/rrc_ue.h | 25 ++++++----------- lib/cu_cp/adapters/du_processor_adapters.h | 15 ++++------ lib/cu_cp/du_processor/du_processor_impl.cpp | 3 +- .../rrc_reconfiguration_procedure.cpp | 2 +- .../rrc_reconfiguration_procedure.h | 4 +-- .../rrc_reestablishment_procedure.cpp | 2 +- .../rrc_reestablishment_procedure.h | 4 +-- lib/rrc/ue/procedures/rrc_setup_procedure.cpp | 14 +++++----- lib/rrc/ue/procedures/rrc_setup_procedure.h | 24 ++++++++-------- lib/rrc/ue/rrc_ue_impl.h | 19 ++++++------- lib/rrc/ue/rrc_ue_message_handlers.cpp | 28 ++++++++++--------- tests/unittests/rrc/rrc_ue_test_helpers.h | 2 +- 12 files changed, 63 insertions(+), 79 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 1eeb70d291..b70233611c 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -120,21 +120,6 @@ struct srb_creation_message { srb_pdcp_config pdcp_cfg; }; -/// Interface to handle the creation of SRBs. -class rrc_ue_srb_handler -{ -public: - virtual ~rrc_ue_srb_handler() = default; - - /// \brief Instruct the RRC UE to create a new SRB. It creates all - /// required intermediate objects (e.g. PDCP) and connects them with one another. - /// \param[in] msg The UE index, SRB ID and config. - virtual void create_srb(const srb_creation_message& msg) = 0; - - /// \brief Get all SRBs of the UE. - virtual static_vector get_srbs() = 0; -}; - /// Interface used by the RRC reconfiguration procedure to /// invoke actions carried out by the main RRC UE class (i.e. send DL message, remove UE). class rrc_ue_reconfiguration_proc_notifier @@ -301,6 +286,14 @@ class rrc_ue_control_message_handler /// \brief Get the packed RRC Handover Preparation Message. virtual byte_buffer get_packed_handover_preparation_message() = 0; + + /// \brief Instruct the RRC UE to create a new SRB. It creates all + /// required intermediate objects (e.g. PDCP) and connects them with one another. + /// \param[in] msg The UE index, SRB ID and config. + virtual void create_srb(const srb_creation_message& msg) = 0; + + /// \brief Get all SRBs of the UE. + virtual static_vector get_srbs() = 0; }; class rrc_ue_cu_cp_ue_notifier @@ -428,7 +421,6 @@ class rrc_ue_context_handler /// It will contain getters for the interfaces for the various logical channels handled by RRC. class rrc_ue_interface : public rrc_ul_pdu_handler, public rrc_ngap_message_handler, - public rrc_ue_srb_handler, public rrc_ue_control_message_handler, public rrc_ue_setup_proc_notifier, public rrc_ue_security_mode_command_proc_notifier, @@ -443,7 +435,6 @@ class rrc_ue_interface : public rrc_ul_pdu_handler, virtual rrc_ue_controller& get_controller() = 0; virtual rrc_ul_pdu_handler& get_ul_pdu_handler() = 0; virtual rrc_ngap_message_handler& get_rrc_ngap_message_handler() = 0; - virtual rrc_ue_srb_handler& get_rrc_ue_srb_handler() = 0; virtual rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() = 0; virtual rrc_ue_context_handler& get_rrc_ue_context_handler() = 0; }; diff --git a/lib/cu_cp/adapters/du_processor_adapters.h b/lib/cu_cp/adapters/du_processor_adapters.h index 2020e4f8a3..c9e55161cb 100644 --- a/lib/cu_cp/adapters/du_processor_adapters.h +++ b/lib/cu_cp/adapters/du_processor_adapters.h @@ -146,11 +146,7 @@ class du_processor_rrc_ue_adapter : public du_processor_rrc_ue_notifier public: du_processor_rrc_ue_adapter() = default; - void connect_rrc_ue(rrc_ue_control_message_handler& rrc_ue_handler_, rrc_ue_srb_handler& srb_handler_) - { - rrc_ue_handler = &rrc_ue_handler_; - srb_handler = &srb_handler_; - } + void connect_rrc_ue(rrc_ue_control_message_handler& rrc_ue_handler_) { rrc_ue_handler = &rrc_ue_handler_; } async_task on_ue_capability_transfer_request(const rrc_ue_capability_transfer_request& msg) override { @@ -222,19 +218,18 @@ class du_processor_rrc_ue_adapter : public du_processor_rrc_ue_notifier void create_srb(const srb_creation_message& msg) override { - srsran_assert(srb_handler != nullptr, "RRC UE SRB handler must not be nullptr"); - return srb_handler->create_srb(msg); + srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); + return rrc_ue_handler->create_srb(msg); } static_vector get_srbs() override { - srsran_assert(srb_handler != nullptr, "RRC UE SRB handler must not be nullptr"); - return srb_handler->get_srbs(); + srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); + return rrc_ue_handler->get_srbs(); } private: rrc_ue_control_message_handler* rrc_ue_handler = nullptr; - rrc_ue_srb_handler* srb_handler = nullptr; }; class du_processor_cu_cp_connection_adapter final : public du_connection_notifier diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index 0cf4adea54..13398da92f 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -179,8 +179,7 @@ bool du_processor_impl::create_rrc_ue(cu_cp_ue& ue, // Create and connect DU Processor to RRC UE adapter rrc_ue_adapters[ue.get_ue_index()] = {}; - rrc_ue_adapters.at(ue.get_ue_index()) - .connect_rrc_ue(rrc_ue->get_rrc_ue_control_message_handler(), rrc_ue->get_rrc_ue_srb_handler()); + rrc_ue_adapters.at(ue.get_ue_index()).connect_rrc_ue(rrc_ue->get_rrc_ue_control_message_handler()); ue.set_rrc_ue_notifier(rrc_ue_adapters.at(ue.get_ue_index())); // Notify CU-CP about the creation of the RRC UE diff --git a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp index c7d0120ebf..7af6656b3f 100644 --- a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp @@ -20,7 +20,7 @@ rrc_reconfiguration_procedure::rrc_reconfiguration_procedure(rrc_ue_context_t& const rrc_reconfiguration_procedure_request& args_, rrc_ue_reconfiguration_proc_notifier& rrc_ue_notifier_, rrc_ue_event_manager& event_mng_, - rrc_ue_srb_handler& srb_notifier_, + rrc_ue_control_message_handler& srb_notifier_, rrc_ue_logger& logger_) : context(context_), args(args_), diff --git a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h index 665dac38a2..f8adab3068 100644 --- a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h +++ b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h @@ -29,7 +29,7 @@ class rrc_reconfiguration_procedure const rrc_reconfiguration_procedure_request& args_, rrc_ue_reconfiguration_proc_notifier& rrc_ue_notifier_, rrc_ue_event_manager& event_mng_, - rrc_ue_srb_handler& srb_notifier_, + rrc_ue_control_message_handler& srb_notifier_, rrc_ue_logger& logger_); void operator()(coro_context>& ctx); @@ -45,7 +45,7 @@ class rrc_reconfiguration_procedure rrc_ue_reconfiguration_proc_notifier& rrc_ue; // handler to the parent RRC UE object rrc_ue_event_manager& event_mng; // event manager for the RRC UE entity - rrc_ue_srb_handler& srb_notifier; // For creating SRBs + rrc_ue_control_message_handler& srb_notifier; // For creating SRBs rrc_ue_logger& logger; rrc_transaction transaction; diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp index 19e9cde949..b42f6e89c0 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp @@ -24,7 +24,7 @@ rrc_reestablishment_procedure::rrc_reestablishment_procedure( const byte_buffer& du_to_cu_container_, rrc_ue_setup_proc_notifier& rrc_ue_setup_notifier_, rrc_ue_reestablishment_proc_notifier& rrc_ue_reest_notifier_, - rrc_ue_srb_handler& srb_notifier_, + rrc_ue_control_message_handler& srb_notifier_, rrc_ue_context_update_notifier& cu_cp_notifier_, rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, rrc_ue_nas_notifier& nas_notifier_, diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h index 8d6294e33a..bc37cb15d5 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h @@ -28,7 +28,7 @@ class rrc_reestablishment_procedure const byte_buffer& du_to_cu_container_, rrc_ue_setup_proc_notifier& rrc_setup_notifier_, rrc_ue_reestablishment_proc_notifier& rrc_ue_notifier_, - rrc_ue_srb_handler& srb_notifier_, + rrc_ue_control_message_handler& srb_notifier_, rrc_ue_context_update_notifier& cu_cp_notifier_, rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, rrc_ue_nas_notifier& nas_notifier_, @@ -64,7 +64,7 @@ class rrc_reestablishment_procedure const byte_buffer& du_to_cu_container; rrc_ue_setup_proc_notifier& rrc_ue_setup_notifier; rrc_ue_reestablishment_proc_notifier& rrc_ue_reest_notifier; // handler to the parent RRC UE object - rrc_ue_srb_handler& srb_notifier; // for creating SRBs + rrc_ue_control_message_handler& srb_notifier; // for creating SRBs rrc_ue_context_update_notifier& cu_cp_notifier; // notifier to the CU-CP rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier; // notifier to the CU-CP UE rrc_ue_nas_notifier& nas_notifier; // notifier to the NGAP diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp index 01f09e676d..17dde14f83 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp @@ -18,13 +18,13 @@ using namespace srsran; using namespace srsran::srs_cu_cp; using namespace asn1::rrc_nr; -rrc_setup_procedure::rrc_setup_procedure(rrc_ue_context_t& context_, - const byte_buffer& du_to_cu_container_, - rrc_ue_setup_proc_notifier& rrc_ue_notifier_, - rrc_ue_srb_handler& srb_notifier_, - rrc_ue_nas_notifier& nas_notifier_, - rrc_ue_event_manager& event_mng_, - rrc_ue_logger& logger_) : +rrc_setup_procedure::rrc_setup_procedure(rrc_ue_context_t& context_, + const byte_buffer& du_to_cu_container_, + rrc_ue_setup_proc_notifier& rrc_ue_notifier_, + rrc_ue_control_message_handler& srb_notifier_, + rrc_ue_nas_notifier& nas_notifier_, + rrc_ue_event_manager& event_mng_, + rrc_ue_logger& logger_) : context(context_), du_to_cu_container(du_to_cu_container_), rrc_ue(rrc_ue_notifier_), diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.h b/lib/rrc/ue/procedures/rrc_setup_procedure.h index e8570fdbc9..17afc18e17 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.h +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.h @@ -57,13 +57,13 @@ namespace srs_cu_cp { class rrc_setup_procedure { public: - rrc_setup_procedure(rrc_ue_context_t& context_, - const byte_buffer& du_to_cu_container_, - rrc_ue_setup_proc_notifier& rrc_ue_notifier_, - rrc_ue_srb_handler& srb_notifier_, - rrc_ue_nas_notifier& nas_notifier_, - rrc_ue_event_manager& event_mng_, - rrc_ue_logger& logger_); + rrc_setup_procedure(rrc_ue_context_t& context_, + const byte_buffer& du_to_cu_container_, + rrc_ue_setup_proc_notifier& rrc_ue_notifier_, + rrc_ue_control_message_handler& srb_notifier_, + rrc_ue_nas_notifier& nas_notifier_, + rrc_ue_event_manager& event_mng_, + rrc_ue_logger& logger_); void operator()(coro_context>& ctx); @@ -82,11 +82,11 @@ class rrc_setup_procedure rrc_ue_context_t& context; const byte_buffer& du_to_cu_container; - rrc_ue_setup_proc_notifier& rrc_ue; // handler to the parent RRC UE object - rrc_ue_srb_handler& srb_notifier; // for creation of SRBs - rrc_ue_nas_notifier& nas_notifier; // notifier to the NGAP - rrc_ue_event_manager& event_mng; // event manager for the RRC UE entity - rrc_ue_logger& logger; + rrc_ue_setup_proc_notifier& rrc_ue; // handler to the parent RRC UE object + rrc_ue_control_message_handler& srb_notifier; // for creation of SRBs + rrc_ue_nas_notifier& nas_notifier; // notifier to the NGAP + rrc_ue_event_manager& event_mng; // event manager for the RRC UE entity + rrc_ue_logger& logger; rrc_transaction transaction; eager_async_task task; diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index 4b6fc6c04e..a19c9ddfb1 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -46,14 +46,9 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller rrc_ue_controller& get_controller() override { return *this; } rrc_ul_pdu_handler& get_ul_pdu_handler() override { return *this; } rrc_ngap_message_handler& get_rrc_ngap_message_handler() override { return *this; } - rrc_ue_srb_handler& get_rrc_ue_srb_handler() override { return *this; } rrc_ue_control_message_handler& get_rrc_ue_control_message_handler() override { return *this; } rrc_ue_context_handler& get_rrc_ue_context_handler() override { return *this; } - // rrc_ue_srb_handler - void create_srb(const srb_creation_message& msg) override; - static_vector get_srbs() override; - // rrc_ngap_message_handler void handle_dl_nas_transport_message(byte_buffer nas_pdu) override; byte_buffer get_packed_handover_preparation_message() override; @@ -69,12 +64,14 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller async_task handle_handover_reconfiguration_complete_expected(uint8_t transaction_id) override; bool store_ue_capabilities(byte_buffer ue_capabilities) override; async_task handle_rrc_ue_capability_transfer_request(const rrc_ue_capability_transfer_request& msg) override; - rrc_ue_release_context get_rrc_ue_release_context(bool requires_rrc_message) override; - rrc_ue_transfer_context get_transfer_context() override; - std::optional generate_meas_config(std::optional current_meas_config) override; - byte_buffer get_rrc_handover_command(const rrc_reconfiguration_procedure_request& request, - unsigned transaction_id) override; - byte_buffer handle_rrc_handover_command(byte_buffer cmd) override; + rrc_ue_release_context get_rrc_ue_release_context(bool requires_rrc_message) override; + rrc_ue_transfer_context get_transfer_context() override; + std::optional generate_meas_config(std::optional current_meas_config) override; + byte_buffer get_rrc_handover_command(const rrc_reconfiguration_procedure_request& request, + unsigned transaction_id) override; + byte_buffer handle_rrc_handover_command(byte_buffer cmd) override; + void create_srb(const srb_creation_message& msg) override; + static_vector get_srbs() override; // rrc_ue_context_handler rrc_ue_reestablishment_context_response get_context() override; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 2667323d14..b31ea8608c 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -93,23 +93,24 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request // Launch RRC setup procedure cu_cp_ue_notifier.schedule_async_task(launch_async( - context, du_to_cu_container, *this, get_rrc_ue_srb_handler(), nas_notifier, *event_mng, logger)); + context, du_to_cu_container, *this, get_rrc_ue_control_message_handler(), nas_notifier, *event_mng, logger)); } void rrc_ue_impl::handle_rrc_reest_request(const asn1::rrc_nr::rrc_reest_request_s& msg) { // Launch RRC re-establishment procedure - cu_cp_ue_notifier.schedule_async_task(launch_async(msg, - context, - du_to_cu_container, - *this, - *this, - get_rrc_ue_srb_handler(), - cu_cp_notifier, - cu_cp_ue_notifier, - nas_notifier, - *event_mng, - logger)); + cu_cp_ue_notifier.schedule_async_task( + launch_async(msg, + context, + du_to_cu_container, + *this, + *this, + get_rrc_ue_control_message_handler(), + cu_cp_notifier, + cu_cp_ue_notifier, + nas_notifier, + *event_mng, + logger)); } void rrc_ue_impl::stop() @@ -369,7 +370,8 @@ byte_buffer rrc_ue_impl::get_packed_ue_radio_access_cap_info() const async_task rrc_ue_impl::handle_rrc_reconfiguration_request(const rrc_reconfiguration_procedure_request& msg) { - return launch_async(context, msg, *this, *event_mng, get_rrc_ue_srb_handler(), logger); + return launch_async( + context, msg, *this, *event_mng, get_rrc_ue_control_message_handler(), logger); } rrc_ue_handover_reconfiguration_context diff --git a/tests/unittests/rrc/rrc_ue_test_helpers.h b/tests/unittests/rrc/rrc_ue_test_helpers.h index 05cadebe2c..47b1e4105b 100644 --- a/tests/unittests/rrc/rrc_ue_test_helpers.h +++ b/tests/unittests/rrc/rrc_ue_test_helpers.h @@ -208,7 +208,7 @@ class rrc_ue_test_helper srb_creation_message msg; msg.ue_index = allocated_ue_index; msg.srb_id = srb_id_t::srb2; - rrc_ue->get_rrc_ue_srb_handler().create_srb(msg); + rrc_ue->get_rrc_ue_control_message_handler().create_srb(msg); } void receive_setup_request() From 403f38417a5eb7e641d8beb3369e72049a86a3a5 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 26 Aug 2024 14:10:07 +0200 Subject: [PATCH 352/407] sched: add unittest for fallback ue w/out pucch cfg Signed-off-by: Carlo Galiotto --- .../ue_scheduling/fallback_scheduler_test.cpp | 67 ++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index af4a1b4924..b836552556 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -282,10 +282,11 @@ class base_fallback_tester return total_cw_tb_size_bytes >= exp_size; } - bool add_ue(rnti_t tc_rnti, du_ue_index_t ue_index) + bool add_ue(rnti_t tc_rnti, du_ue_index_t ue_index, bool remove_ded_cfg = false) { // Add cell to UE cell grid allocator. - auto ue_create_req = test_helpers::create_default_sched_ue_creation_request(bench->builder_params); + auto ue_create_req = remove_ded_cfg ? test_helpers::create_empty_spcell_cfg_sched_ue_creation_request() + : test_helpers::create_default_sched_ue_creation_request(bench->builder_params); ue_create_req.crnti = tc_rnti; ue_create_req.ue_index = ue_index; return bench->add_ue(ue_create_req); @@ -1395,6 +1396,68 @@ INSTANTIATE_TEST_SUITE_P(test_fdd_and_tdd, testing::Values(ul_fallback_sched_test_params{.duplx_mode = duplex_mode::FDD}, ul_fallback_sched_test_params{.duplx_mode = duplex_mode::TDD})); +class fallback_sched_ue_w_out_pucch_cfg : public base_fallback_tester, public ::testing::Test +{ +protected: + fallback_sched_ue_w_out_pucch_cfg() : base_fallback_tester(srsran::duplex_mode::TDD) + { + const unsigned k0 = 0; + const sch_mcs_index max_msg4_mcs_index = 8; + auto cell_cfg = create_custom_cell_config_request(k0); + setup_sched(create_expert_config(max_msg4_mcs_index), cell_cfg); + } + + // Helper that generates the slot for the SRB0 buffer update. + static unsigned generate_srb0_traffic_slot() { return test_rgen::uniform_int(20U, 30U); } + + const unsigned MAC_SRB_SDU_SIZE = 101; + const unsigned MAX_TEST_RUN_SLOTS = 50; +}; + +TEST_F(fallback_sched_ue_w_out_pucch_cfg, when_srb0_is_retx_ed_only_pucch_common_is_scheduled) +{ + add_ue(to_rnti(0x4601), to_du_ue_index(0), true); + auto& u = bench->ue_db[to_du_ue_index(0)]; + + ASSERT_FALSE(u.get_pcell().cfg().cfg_dedicated().ul_config.has_value()); + + slot_point slot_update_srb_traffic{current_slot.numerology(), generate_srb0_traffic_slot()}; + + // Check if the SRB0 gets transmitted at least once. + bool srb_transmitted = false; + for (unsigned idx = 1; idx < MAX_TEST_RUN_SLOTS * (1U << current_slot.numerology()); idx++) { + run_slot(); + + // Allocate buffer for SRB0. + if (current_slot == slot_update_srb_traffic) { + push_buffer_state_to_dl_ue(to_du_ue_index(0), current_slot, MAC_SRB_SDU_SIZE, true); + } + + // If PUCCH is detected, then it must be 1 grant only (PUCCH common). + auto& pucchs = bench->res_grid[0].result.ul.pucchs; + if (not pucchs.empty()) { + srb_transmitted = true; + const auto* pucch_srb0 = std::find_if( + pucchs.begin(), pucchs.end(), [rnti = u.crnti](const pucch_info& pucch) { return pucch.crnti == rnti; }); + ASSERT_TRUE(pucch_srb0 != pucchs.end()); + ASSERT_TRUE(pucch_srb0->pdu_context.is_common); + ASSERT_EQ(1, std::count_if(pucchs.begin(), pucchs.end(), [rnti = u.crnti](const pucch_info& pucch) { + return pucch.crnti == rnti; + })); + } + + // NACK the HARQ processes that are waiting for ACK to trigger a retransmissions. + const unsigned bit_index_1_harq_only = 0U; + dl_harq_process* dl_harq = u.get_pcell().harqs.find_dl_harq_waiting_ack_slot(current_slot, bit_index_1_harq_only); + if (dl_harq != nullptr) { + static constexpr unsigned tb_idx = 0U; + dl_harq->ack_info(tb_idx, mac_harq_ack_report_status::nack, {}); + } + } + + ASSERT_TRUE(srb_transmitted); +} + int main(int argc, char** argv) { srslog::fetch_basic_logger("SCHED", true).set_level(srslog::basic_levels::debug); From 8a130b31c367387f801fb3cd357d3d67939b4ba9 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 28 Aug 2024 13:14:10 +0200 Subject: [PATCH 353/407] ci: skip builders check for ubuntu20 --- .gitlab-ci.yml | 3 ++- .gitlab/ci/build.yml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 916c33d9d1..b3b42c020b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -465,7 +465,8 @@ create-tags: stage: .post rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ - when: always + when: delayed + start_in: 30 minutes script: - | for name in $TAG_NAME_ARRAY; do diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 865739fd1c..84437e2098 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -756,6 +756,8 @@ check builders ubuntu versions: stage: static rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + variables: + VERSIONS_TO_IGNORE: "20.04" script: - check_if_image_exists ${CR_REGISTRY_URI}/srsgnb/builder-ubuntu- :${DOCKER_BUILDER_VERSION} From 1f50ac91c01d5a17b1a3fa96976117a87ca95549 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 28 Aug 2024 15:44:00 +0200 Subject: [PATCH 354/407] ci,e2e: simplify jobs --- .gitlab/ci/e2e.yml | 138 +++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 93 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 8a4000b338..6797e3c829 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -268,64 +268,81 @@ smoke zmq: - *txrx-lib - *retina-needs -srsue: - extends: .zmq +.zmq-uesim: + stage: zmq + extends: .e2e-run variables: - TESTBED: "zmq_srsue" - MARKERS: "zmq_srsue" + TESTBED: zmq_uesim E2E_LOG_LEVEL: "info" needs: - job: "basic relwithdeb" artifacts: true - - *txrx-lib + - job: "build uesim zmq driver" + artifacts: true - *retina-needs + allow_failure: true + +srsue: + extends: .zmq + variables: + TESTBED: "zmq_srsue" amari 1UE: extends: .zmq variables: MARKERS: "zmq_single_ue" - E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" + +amari 1UE 4x4 mimo: + extends: .zmq + variables: + MARKERS: "zmq_4x4_mimo" + RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" + +amari 4UE deb: + extends: .zmq + variables: + TESTBED: "zmq_deb" + MARKERS: "smoke" + RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" needs: - - job: "basic relwithdeb" + - job: "basic package" artifacts: true - *txrx-lib - *retina-needs -amari 32UE 2x2 mimo: +amari 4UE asan: extends: .zmq variables: - MARKERS: "zmq_2x2_mimo" - E2E_LOG_LEVEL: "info" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + MARKERS: "smoke" + KEYWORDS: "iperf" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" needs: - - job: "basic relwithdeb" + - job: "basic asan" artifacts: true - *txrx-lib - *retina-needs - allow_failure: true -amari 1UE 4x4 mimo: +amari 4UE tsan: extends: .zmq variables: - MARKERS: "zmq_4x4_mimo" - E2E_LOG_LEVEL: "info" - RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" + MARKERS: "smoke" + KEYWORDS: "iperf" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" needs: - - job: "basic relwithdeb" + - job: "basic tsan" artifacts: true - *txrx-lib - *retina-needs -amari 4UE deb: +amari 4UE memcheck: extends: .zmq variables: - TESTBED: "zmq_deb" - MARKERS: "smoke" - E2E_LOG_LEVEL: "info" - RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" + MARKERS: "zmq_valgrind" + E2E_LOG_LEVEL: "warning" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" needs: - - job: "basic package" + - job: "basic memcheck" artifacts: true - *txrx-lib - *retina-needs @@ -334,13 +351,7 @@ amari 8UE: extends: .zmq variables: MARKERS: "zmq and not smoke" - E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - needs: - - job: "basic relwithdeb" - artifacts: true - - *txrx-lib - - *retina-needs parallel: matrix: - KEYWORDS: @@ -365,13 +376,7 @@ amari 32UE: extends: .zmq variables: MARKERS: "zmq and not smoke" - E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - needs: - - job: "basic relwithdeb" - artifacts: true - - *txrx-lib - - *retina-needs parallel: matrix: - KEYWORDS: @@ -383,54 +388,18 @@ amari 32UE: "iperf and tcp and not band:3", ] -amari 4UE asan: - extends: .zmq - variables: - MARKERS: "smoke" - KEYWORDS: "iperf" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - needs: - - job: "basic asan" - artifacts: true - - *txrx-lib - - *retina-needs - -amari 4UE tsan: - extends: .zmq - variables: - MARKERS: "smoke" - KEYWORDS: "iperf" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - needs: - - job: "basic tsan" - artifacts: true - - *txrx-lib - - *retina-needs - -amari 4UE memcheck: +amari 32UE 2x2 mimo: extends: .zmq variables: - MARKERS: "zmq_valgrind" - E2E_LOG_LEVEL: "warning" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - needs: - - job: "basic memcheck" - artifacts: true - - *txrx-lib - - *retina-needs + MARKERS: "zmq_2x2_mimo" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" cudu amari 8UE: extends: .zmq variables: TESTBED: zmq_cudu MARKERS: "zmq and not smoke" - E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - needs: - - job: "basic relwithdeb" - artifacts: true - - *txrx-lib - - *retina-needs parallel: matrix: - KEYWORDS: ["reestablishment and sequentially"] @@ -440,35 +409,18 @@ cudu amari 32UE: variables: TESTBED: zmq_cudu MARKERS: "zmq and not smoke" - E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - needs: - - job: "basic relwithdeb" - artifacts: true - - *txrx-lib - - *retina-needs parallel: matrix: - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] uesim 32UE beta: stage: zmq - extends: .e2e-run - timeout: 8h + extends: .zmq-uesim variables: - GROUP: uesim - TESTBED: zmq_uesim MARKERS: "zmq and not smoke" KEYWORDS: ping - E2E_LOG_LEVEL: "info" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - needs: - - job: "basic relwithdeb" - artifacts: true - - job: "build uesim zmq driver" - artifacts: true - - *retina-needs - allow_failure: true ################################################################################ # TEST MODE From 77bdb6b4080ca4c95253911d2f5dd798d56a796f Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 28 Aug 2024 15:58:02 +0200 Subject: [PATCH 355/407] ci: more uesim jobs --- .gitlab/ci/e2e.yml | 109 ++++++++++++++++++++++++++++++++++++++++++-- .gitlab/ci/e2e/.env | 2 +- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 6797e3c829..5e3b0e1661 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -293,12 +293,24 @@ amari 1UE: MARKERS: "zmq_single_ue" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" +amari 1UE uesim: + extends: .zmq-uesim + variables: + MARKERS: "zmq_single_ue" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" + amari 1UE 4x4 mimo: extends: .zmq variables: MARKERS: "zmq_4x4_mimo" RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" +amari 1UE 4x4 mimo uesim: + extends: .zmq-uesim + variables: + MARKERS: "zmq_4x4_mimo" + RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" + amari 4UE deb: extends: .zmq variables: @@ -311,6 +323,18 @@ amari 4UE deb: - *txrx-lib - *retina-needs +amari 4UE deb uesim: + extends: .zmq-uesim + variables: + TESTBED: "zmq_deb" + MARKERS: "smoke" + RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" + needs: + - job: "basic package" + artifacts: true + - *txrx-lib + - *retina-needs + amari 4UE asan: extends: .zmq variables: @@ -323,6 +347,18 @@ amari 4UE asan: - *txrx-lib - *retina-needs +amari 4UE asan uesim: + extends: .zmq-uesim + variables: + MARKERS: "smoke" + KEYWORDS: "iperf" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" + needs: + - job: "basic asan" + artifacts: true + - *txrx-lib + - *retina-needs + amari 4UE tsan: extends: .zmq variables: @@ -335,6 +371,18 @@ amari 4UE tsan: - *txrx-lib - *retina-needs +amari 4UE tsan uesim: + extends: .zmq-uesim + variables: + MARKERS: "smoke" + KEYWORDS: "iperf" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" + needs: + - job: "basic tsan" + artifacts: true + - *txrx-lib + - *retina-needs + amari 4UE memcheck: extends: .zmq variables: @@ -347,6 +395,18 @@ amari 4UE memcheck: - *txrx-lib - *retina-needs +amari 4UE memcheck uesim: + extends: .zmq-uesim + variables: + MARKERS: "zmq_valgrind" + E2E_LOG_LEVEL: "warning" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" + needs: + - job: "basic memcheck" + artifacts: true + - *txrx-lib + - *retina-needs + amari 8UE: extends: .zmq variables: @@ -361,6 +421,20 @@ amari 8UE: "handover and sequentially", ] +amari 8UE uesim: + extends: .zmq-uesim + variables: + MARKERS: "zmq and not smoke" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + parallel: + matrix: + - KEYWORDS: + [ + "attach_detach", + "reestablishment and sequentially", + "handover and sequentially", + ] + amari 8UE beta: extends: amari 8UE parallel: @@ -372,6 +446,17 @@ amari 8UE beta: ] allow_failure: true +amari 8UE beta uesim: + extends: amari 8UE uesim + parallel: + matrix: + - KEYWORDS: + [ + "reestablishment and not sequentially", + "handover and not sequentially", + ] + allow_failure: true + amari 32UE: extends: .zmq variables: @@ -394,6 +479,12 @@ amari 32UE 2x2 mimo: MARKERS: "zmq_2x2_mimo" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" +amari 32UE 2x2 mimo uesim: + extends: .zmq-uesim + variables: + MARKERS: "zmq_2x2_mimo" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + cudu amari 8UE: extends: .zmq variables: @@ -404,6 +495,16 @@ cudu amari 8UE: matrix: - KEYWORDS: ["reestablishment and sequentially"] +cudu amari 8UE uesim: + extends: .zmq-uesim + variables: + TESTBED: zmq_cudu + MARKERS: "zmq and not smoke" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + parallel: + matrix: + - KEYWORDS: ["reestablishment and sequentially"] + cudu amari 32UE: extends: .zmq variables: @@ -414,13 +515,15 @@ cudu amari 32UE: matrix: - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] -uesim 32UE beta: - stage: zmq +cudu amari 32UE uesim: extends: .zmq-uesim variables: + TESTBED: zmq_cudu MARKERS: "zmq and not smoke" - KEYWORDS: ping RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + parallel: + matrix: + - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] ################################################################################ # TEST MODE diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index b821573216..d293370563 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.7 +RETINA_VERSION=0.52.8 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From cbafc9bdb634805cc1e54b82737b67d50999919b Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 27 Aug 2024 16:37:31 +0200 Subject: [PATCH 356/407] du: add parameter for max PUCCH symbols per slot... ... to leave room for SRS resources Signed-off-by: Carlo Galiotto --- include/srsran/du/du_cell_config.h | 5 ++ lib/du/du_cell_config_validation.cpp | 3 +- lib/du/du_update_config_helpers.cpp | 3 +- .../du_pucch_resource_manager.cpp | 3 +- .../pucch_resource_generator.cpp | 61 +++++++++++-------- .../pucch_resource_generator.h | 12 ++-- .../config/sched_cell_config_helpers.cpp | 3 +- .../pucch_resource_generator_test.cpp | 12 ++-- .../uci_and_pucch/pucch_res_manager_test.cpp | 3 +- 9 files changed, 65 insertions(+), 40 deletions(-) diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index 9dc21b183e..81939a98b7 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -91,6 +91,11 @@ struct pucch_builder_params { // NOTE: Having \c pucch_f1_params force the varint to use the Format 1 in the default constructor. std::variant f0_or_f1_params; pucch_f2_params f2_params; + /// Maximum number of symbols per UL slot dedicated for PUCCH. + /// \remark In case of Sounding Reference Signals (SRS) being used, the number of symbols should be reduced so that + /// the PUCCH resources do not overlap in symbols with the SRS resources. + /// \remark This parameter should be computed the GNB and not exposed to the user configuration interface. + bounded_integer max_nof_symbols = NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; }; /// Parameters that are used to initialize or build the \c PhysicalCellGroupConfig, TS 38.331. diff --git a/lib/du/du_cell_config_validation.cpp b/lib/du/du_cell_config_validation.cpp index 32c0d856e1..39e372b09e 100644 --- a/lib/du/du_cell_config_validation.cpp +++ b/lib/du/du_cell_config_validation.cpp @@ -709,7 +709,8 @@ check_outcome srsran::is_du_cell_config_valid(const du_cell_config& cell_cfg) pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint(), pucch_cfg.f0_or_f1_params, pucch_cfg.f2_params, - cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length())); + cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(), + pucch_cfg.max_nof_symbols)); HANDLE_ERROR(config_validators::validate_csi_meas_cfg(cell_cfg.ue_ded_serv_cell_cfg, cell_cfg.tdd_ul_dl_cfg_common)); HANDLE_ERROR(check_dl_config_dedicated(cell_cfg)); HANDLE_ERROR(check_ul_config_dedicated(cell_cfg)); diff --git a/lib/du/du_update_config_helpers.cpp b/lib/du/du_update_config_helpers.cpp index 5b42a07b1b..dc69a019ef 100644 --- a/lib/du/du_update_config_helpers.cpp +++ b/lib/du/du_update_config_helpers.cpp @@ -74,7 +74,8 @@ unsigned srsran::config_helpers::compute_prach_frequency_start(const pucch_build user_params.nof_csi_resources, user_params.f0_or_f1_params, user_params.f2_params, - bwp_size); + bwp_size, + user_params.max_nof_symbols); srsran_assert(not res_list.empty(), "The PUCCH resource list cannot be empty"); diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index e5a630eca7..94d3e40a6f 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -57,7 +57,8 @@ du_pucch_resource_manager::du_pucch_resource_manager(span cell_cfg_list_[0].pucch_cfg.nof_csi_resources, cell_cfg_list_[0].pucch_cfg.f0_or_f1_params, cell_cfg_list_[0].pucch_cfg.f2_params, - cell_cfg_list_[0].ul_cfg_common.init_ul_bwp.generic_params.crbs.length())), + cell_cfg_list_[0].ul_cfg_common.init_ul_bwp.generic_params.crbs.length(), + cell_cfg_list_[0].pucch_cfg.max_nof_symbols)), default_pucch_cfg( build_default_pucch_cfg(cell_cfg_list_[0].ue_ded_serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value(), user_defined_pucch_cfg)), diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp index cc5fa459f5..a7abf85b33 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -59,7 +59,10 @@ static unsigned occ_cs_index_to_occ(unsigned occ_cs_idx, unsigned nof_css) return occ_cs_idx / nof_css; } -static std::vector compute_f0_res(unsigned nof_res_f0, pucch_f0_params params, unsigned bwp_size_rbs) +static std::vector compute_f0_res(unsigned nof_res_f0, + pucch_f0_params params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { // Compute the number of symbols and RBs for F0. std::vector res_list; @@ -74,8 +77,7 @@ static std::vector compute_f0_res(unsigned nof_res_f0, pucch_f0_par const prb_interval freq_hop_prbs{bwp_size_rbs - 1U - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. - for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; - sym_idx += nof_f0_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f0_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f0_symbols}; // Allocate resources for first hop. @@ -110,8 +112,7 @@ static std::vector compute_f0_res(unsigned nof_res_f0, pucch_f0_par const prb_interval prbs_hi_spectrum{bwp_size_rbs - 1U - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. - for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; - sym_idx += nof_f0_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f0_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f0_symbols}; res_list.emplace_back( pucch_grant{.format = srsran::pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs_low_spectrum}); @@ -143,8 +144,11 @@ static std::vector compute_f0_res(unsigned nof_res_f0, pucch_f0_par return res_list; } -static std::vector -compute_f1_res(unsigned nof_res_f1, pucch_f1_params params, unsigned bwp_size_rbs, unsigned nof_occ_css) +static std::vector compute_f1_res(unsigned nof_res_f1, + pucch_f1_params params, + unsigned bwp_size_rbs, + unsigned nof_occ_css, + bounded_integer max_nof_symbols) { std::vector res_list; @@ -157,7 +161,7 @@ compute_f1_res(unsigned nof_res_f1, pucch_f1_params params, unsigned bwp_size_rb const prb_interval freq_hop_prbs{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. - for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= max_nof_symbols.to_uint(); sym_idx += params.nof_symbols.to_uint()) { const ofdm_symbol_range symbols{sym_idx, sym_idx + params.nof_symbols.to_uint()}; @@ -209,7 +213,7 @@ compute_f1_res(unsigned nof_res_f1, pucch_f1_params params, unsigned bwp_size_rb const prb_interval prbs_hi_spectrum{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. - for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= max_nof_symbols.to_uint(); sym_idx += params.nof_symbols.to_uint()) { const ofdm_symbol_range symbols{sym_idx, sym_idx + params.nof_symbols.to_uint()}; @@ -233,7 +237,7 @@ compute_f1_res(unsigned nof_res_f1, pucch_f1_params params, unsigned bwp_size_rb // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of // the BWP. - for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= max_nof_symbols.to_uint(); sym_idx += params.nof_symbols.to_uint()) { const ofdm_symbol_range symbols{sym_idx, sym_idx + params.nof_symbols.to_uint()}; @@ -260,7 +264,10 @@ compute_f1_res(unsigned nof_res_f1, pucch_f1_params params, unsigned bwp_size_rb return res_list; } -static std::vector compute_f2_res(unsigned nof_res_f2, pucch_f2_params params, unsigned bwp_size_rbs) +static std::vector compute_f2_res(unsigned nof_res_f2, + pucch_f2_params params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { // Compute the number of symbols and RBs for F2. std::vector res_list; @@ -284,8 +291,7 @@ static std::vector compute_f2_res(unsigned nof_res_f2, pucch_f2_par const prb_interval freq_hop_prbs{bwp_size_rbs - f2_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. - for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; - sym_idx += nof_f2_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f2_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f2_symbols}; // Allocate resources for first hop. @@ -320,8 +326,7 @@ static std::vector compute_f2_res(unsigned nof_res_f2, pucch_f2_par const prb_interval prbs_hi_spectrum{bwp_size_rbs - f2_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. - for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; - sym_idx += nof_f2_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f2_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f2_symbols}; res_list.emplace_back( pucch_grant{.format = srsran::pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs_low_spectrum}); @@ -358,10 +363,12 @@ srsran::srs_du::pucch_parameters_validator(unsigned unsigned nof_res_f2, std::variant f0_f1_params, pucch_f2_params f2_params, - unsigned bwp_size_rbs) + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { const bool has_f0 = std::holds_alternative(f0_f1_params); unsigned nof_f0_f1_rbs = 0; + srsran_assert(max_nof_symbols.to_uint() <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP, "Invalid number of symbols"); if (has_f0) { const auto& f0_params = std::get(f0_f1_params); @@ -371,7 +378,7 @@ srsran::srs_du::pucch_parameters_validator(unsigned } // We define a block as a set of Resources (either F0/F1 or F2) aligned over the same starting PRB. - const unsigned nof_f0_per_block = NOF_OFDM_SYM_PER_SLOT_NORMAL_CP / f0_params.nof_symbols.to_uint(); + const unsigned nof_f0_per_block = max_nof_symbols.to_uint() / f0_params.nof_symbols.to_uint(); nof_f0_f1_rbs = static_cast(std::ceil(static_cast(nof_res_f0_f1) / static_cast(nof_f0_per_block))); } else { @@ -382,7 +389,7 @@ srsran::srs_du::pucch_parameters_validator(unsigned // We define a block as a set of Resources (either F0/F1 or F2) aligned over the same starting PRB. const unsigned nof_f1_per_block = nof_occ_codes * format1_cp_step_to_uint(f1_params.nof_cyc_shifts) * - (NOF_OFDM_SYM_PER_SLOT_NORMAL_CP / f1_params.nof_symbols.to_uint()); + (max_nof_symbols.to_uint() / f1_params.nof_symbols.to_uint()); nof_f0_f1_rbs = static_cast(std::ceil(static_cast(nof_res_f0_f1) / static_cast(nof_f1_per_block))); // With intraslot_freq_hopping, the nof of RBs is an even number. @@ -406,7 +413,7 @@ srsran::srs_du::pucch_parameters_validator(unsigned return make_unexpected("The number of PRBs for PUCCH Format 2 exceeds the limit of 16"); } - const unsigned nof_f2_blocks = NOF_OFDM_SYM_PER_SLOT_NORMAL_CP / f2_params.nof_symbols.to_uint(); + const unsigned nof_f2_blocks = max_nof_symbols.to_uint() / f2_params.nof_symbols.to_uint(); unsigned nof_f2_rbs = static_cast(std::ceil(static_cast(nof_res_f2) / static_cast(nof_f2_blocks))) * f2_max_rbs; // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. @@ -557,9 +564,11 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned unsigned nof_res_f2, std::variant f0_f1_params, pucch_f2_params f2_params, - unsigned bwp_size_rbs) + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { - auto outcome = pucch_parameters_validator(nof_res_f0_f1, nof_res_f2, f0_f1_params, f2_params, bwp_size_rbs); + auto outcome = + pucch_parameters_validator(nof_res_f0_f1, nof_res_f2, f0_f1_params, f2_params, bwp_size_rbs, max_nof_symbols); if (not outcome.has_value()) { srsran_assertion_failure("The cell list could not be generated due to: {}", outcome.error()); return {}; @@ -572,17 +581,19 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned unsigned nof_css = 0; if (has_f0 and nof_res_f0_f1 > 0) { const pucch_f0_params f0_params = std::get(f0_f1_params); - pucch_f0_f1_resource_list = compute_f0_res(nof_res_f0_f1, f0_params, bwp_size_rbs); + pucch_f0_f1_resource_list = compute_f0_res(nof_res_f0_f1, f0_params, bwp_size_rbs, max_nof_symbols); } else if (nof_res_f0_f1 > 0) { const pucch_f1_params f1_params = std::get(f0_f1_params); const unsigned nof_occ_codes = f1_params.occ_supported ? format1_symb_to_spreading_factor(f1_params.nof_symbols) : 1; - nof_css = format1_cp_step_to_uint(f1_params.nof_cyc_shifts); - pucch_f0_f1_resource_list = compute_f1_res(nof_res_f0_f1, f1_params, bwp_size_rbs, nof_css * nof_occ_codes); + nof_css = format1_cp_step_to_uint(f1_params.nof_cyc_shifts); + pucch_f0_f1_resource_list = + compute_f1_res(nof_res_f0_f1, f1_params, bwp_size_rbs, nof_css * nof_occ_codes, max_nof_symbols); } const std::vector pucch_f2_resource_list = - nof_res_f2 > 0 ? compute_f2_res(nof_res_f2, f2_params, bwp_size_rbs) : std::vector{}; + nof_res_f2 > 0 ? compute_f2_res(nof_res_f2, f2_params, bwp_size_rbs, max_nof_symbols) + : std::vector{}; auto res_list = merge_f0_f1_f2_resource_lists(pucch_f0_f1_resource_list, pucch_f2_resource_list, diff --git a/lib/du_manager/ran_resource_management/pucch_resource_generator.h b/lib/du_manager/ran_resource_management/pucch_resource_generator.h index 4df0a71b05..07cb99ab40 100644 --- a/lib/du_manager/ran_resource_management/pucch_resource_generator.h +++ b/lib/du_manager/ran_resource_management/pucch_resource_generator.h @@ -14,8 +14,7 @@ #include "srsran/adt/optional.h" #include "srsran/ran/pucch/pucch_configuration.h" -namespace srsran { -namespace srs_du { +namespace srsran::srs_du { /// The following values have to be set according to the \ref pucch_resource_manager capabilities. /// Maximum number of PUCCH F0/F1 resources per UE for HARQ-ACK reporting. @@ -34,7 +33,8 @@ error_type pucch_parameters_validator(unsigned unsigned nof_res_f2, std::variant f0_f1_params, pucch_f2_params f2_params, - unsigned bwp_size_rbs); + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols); /// \brief Generates the list of cell PUCCH resources (Format 0/1 and 2) given the number of requested resources. /// @@ -54,7 +54,8 @@ std::vector generate_cell_pucch_res_list(unsigned unsigned nof_res_f2, std::variant f0_f1_params, pucch_f2_params f2_params, - unsigned bwp_size_rbs); + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols); /// \brief Generates the list of PUCCH resources for a given UE. /// @@ -115,5 +116,4 @@ bool ue_pucch_config_builder(serving_cell_config& unsigned nof_harq_pucch_sets, unsigned nof_cell_pucch_f0_f1_res_sr, unsigned nof_cell_pucch_f2_res_csi = 1); -} // namespace srs_du -} // namespace srsran +} // namespace srsran::srs_du diff --git a/lib/scheduler/config/sched_cell_config_helpers.cpp b/lib/scheduler/config/sched_cell_config_helpers.cpp index ea625049a9..da5268f49b 100644 --- a/lib/scheduler/config/sched_cell_config_helpers.cpp +++ b/lib/scheduler/config/sched_cell_config_helpers.cpp @@ -27,7 +27,8 @@ srsran::config_helpers::build_pucch_guardbands_list(const pucch_builder_params& user_params.nof_csi_resources, user_params.f0_or_f1_params, user_params.f2_params, - bwp_size); + bwp_size, + user_params.max_nof_symbols); srsran_assert(not res_list.empty(), "The PUCCH resource list cannot be empty"); diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index de81f98ee8..7e2d94e2c6 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -395,9 +395,11 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) std::vector res_list; if (nof_res_f0 != 0) { - res_list = generate_cell_pucch_res_list(nof_res_f0, nof_res_f2, params_f0, params_f2, bwp_size); + res_list = generate_cell_pucch_res_list( + nof_res_f0, nof_res_f2, params_f0, params_f2, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); } else { - res_list = generate_cell_pucch_res_list(nof_res_f1, nof_res_f2, params_f1, params_f2, bwp_size); + res_list = generate_cell_pucch_res_list( + nof_res_f1, nof_res_f2, params_f1, params_f2, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); } ASSERT_TRUE(res_list.size() > 0); @@ -910,9 +912,11 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) << "PUCCH Format 0 and Format 1 resources cannot be used together"; if (nof_f0_res_harq_per_ue != 0) { - res_list = generate_cell_pucch_res_list(nof_f0_res, nof_f2_res, f0_params, f2_params, bwp_size); + res_list = generate_cell_pucch_res_list( + nof_f0_res, nof_f2_res, f0_params, f2_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); } else { - res_list = generate_cell_pucch_res_list(nof_f1_res, nof_f2_res, f1_params, f2_params, bwp_size); + res_list = generate_cell_pucch_res_list( + nof_f1_res, nof_f2_res, f1_params, f2_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); } const unsigned harq_idx_cfg = test_rgen::uniform_int(0, nof_harq_cfg_per_ue - 1); diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp index 190c92228d..7e20f4cc09 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp @@ -614,7 +614,8 @@ class test_pucch_res_manager_multiple_cfg : public test_pucch_resource_manager (nof_res_per_ue + 1) * nof_configurations, pucch_f1_params{}, pucch_f2_params{}, - cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length()); + cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(), + NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); for (unsigned ue_idx = 0; ue_idx != nof_ues; ++ue_idx) { sched_ue_creation_request_message ue_req = test_helpers::create_default_sched_ue_creation_request(); serving_cell_config& serv_cfg = ue_req.cfg.cells->front().serv_cell_cfg; From 310f71d3965c88aafbab8f922791c818972a65a4 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 27 Aug 2024 18:55:14 +0200 Subject: [PATCH 357/407] du: compute max nof pucch symbols from srs config Signed-off-by: Carlo Galiotto --- apps/units/flexible_du/du_high/du_high_config.h | 9 +++++++++ .../du_high/du_high_config_translators.cpp | 8 ++++++++ include/srsran/du/du_cell_config.h | 15 ++++++++++++++- include/srsran/du/du_update_config_helpers.h | 2 ++ lib/du/du_update_config_helpers.cpp | 10 ++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) 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 48821dfbbd..40dda6746d 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -270,6 +270,13 @@ struct du_high_unit_pucch_config { unsigned max_consecutive_kos = 100; }; +struct du_high_unit_srs_config { + /// Enable Sound Reference Signals (SRS) for the UEs within this cell. + bool srs_enabled = false; + /// Defines the maximum number of symbols dedicated to the cell SRS resources in a slot. Values: {1,...,6}. + unsigned max_nof_symbols_per_slot = 2U; +}; + /// Parameters that are used to initialize or build the \c PhysicalCellGroupConfig, TS 38.331. struct du_high_unit_phy_cell_group_config { /// \brief \c p-NR-FR1, part of \c PhysicalCellGroupConfig, TS 38.331. Values: {-30,...,33}. @@ -553,6 +560,8 @@ struct du_high_unit_base_cell_config { du_high_unit_pusch_config pusch_cfg; /// PUCCH configuration. du_high_unit_pucch_config pucch_cfg; + /// srs configuration. + du_high_unit_srs_config srs_cfg; /// Physical Cell Group parameters. du_high_unit_phy_cell_group_config pcg_cfg; /// MAC Cell Gropup parameters. 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 dad4d59bd2..4c181bb06a 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 @@ -532,6 +532,12 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c du_pucch_cfg.f2_params.intraslot_freq_hopping = user_pucch_cfg.f2_intraslot_freq_hopping; du_pucch_cfg.f2_params.max_payload_bits = user_pucch_cfg.max_payload_bits; + // Parameters for SRS-Config. + srs_builder_params& du_srs_cfg = out_cell.srs_cfg; + const du_high_unit_srs_config& user_srs_cfg = base_cell.srs_cfg; + du_srs_cfg.srs_enabled = user_srs_cfg.srs_enabled; + du_srs_cfg.max_nof_symbols = user_srs_cfg.max_nof_symbols_per_slot; + // Parameters for PUSCH-Config. if (not out_cell.ue_ded_serv_cell_cfg.ul_config.has_value()) { out_cell.ue_ded_serv_cell_cfg.ul_config.emplace(); @@ -604,6 +610,8 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c base_cell.csi_cfg.csi_rs_enabled ? std::optional{base_cell.csi_cfg.csi_rs_period_msec} : std::nullopt); + // The maximum number of symbols for cell PUCCH resources is computed based on the SRS configuration. + du_pucch_cfg.max_nof_symbols = config_helpers::compute_max_nof_pucch_symbols(du_srs_cfg); if (update_msg1_frequency_start) { rach_cfg.rach_cfg_generic.msg1_frequency_start = config_helpers::compute_prach_frequency_start( du_pucch_cfg, out_cell.ul_cfg_common.init_ul_bwp.generic_params.crbs.length(), is_long_prach); diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index 81939a98b7..c7673ea32b 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -94,10 +94,20 @@ struct pucch_builder_params { /// Maximum number of symbols per UL slot dedicated for PUCCH. /// \remark In case of Sounding Reference Signals (SRS) being used, the number of symbols should be reduced so that /// the PUCCH resources do not overlap in symbols with the SRS resources. - /// \remark This parameter should be computed the GNB and not exposed to the user configuration interface. + /// \remark This parameter should be computed by the GNB and not exposed to the user configuration interface. bounded_integer max_nof_symbols = NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; }; +struct srs_builder_params { + /// Enable Sound Reference Signals (SRS) for the UEs within this cell. + bool srs_enabled = false; + /// Maximum number of symbols per UL slot dedicated for SRS resources. + /// \remark In case of Sounding Reference Signals (SRS) being used, the number of symbols should be reduced so that + /// the PUCCH resources do not overlap in symbols with the SRS resources. + /// \remark The SRS resources are always placed at the end of the slot. + bounded_integer max_nof_symbols = 2U; +}; + /// Parameters that are used to initialize or build the \c PhysicalCellGroupConfig, TS 38.331. struct phy_cell_group_params { /// \brief \c p-NR-FR1, part \c PhysicalCellGroupConfig, TS 38.331. @@ -171,6 +181,9 @@ struct du_cell_config { /// Parameters for PUCCH-Config generation. pucch_builder_params pucch_cfg; + /// Parameters for SRS-Config generation. + srs_builder_params srs_cfg; + /// Defines the maximum allowable channel delay in slots when runnning in NTN mode. seee (TS 38.300 section 16.14.2) unsigned ntn_cs_koffset = 0; diff --git a/include/srsran/du/du_update_config_helpers.h b/include/srsran/du/du_update_config_helpers.h index edf0701251..ab64346216 100644 --- a/include/srsran/du/du_update_config_helpers.h +++ b/include/srsran/du/du_update_config_helpers.h @@ -39,5 +39,7 @@ void compute_nof_sr_csi_pucch_res(pucch_builder_params& user_params, float sr_period_msec, std::optional csi_period_msec); +bounded_integer compute_max_nof_pucch_symbols(const srs_builder_params& user_srs_params); + } // namespace config_helpers } // namespace srsran diff --git a/lib/du/du_update_config_helpers.cpp b/lib/du/du_update_config_helpers.cpp index dc69a019ef..8b9364560a 100644 --- a/lib/du/du_update_config_helpers.cpp +++ b/lib/du/du_update_config_helpers.cpp @@ -118,3 +118,13 @@ void srsran::config_helpers::compute_nof_sr_csi_pucch_res(pucch_builder_params& user_params.nof_csi_resources = 0; } } + +bounded_integer +srsran::config_helpers::compute_max_nof_pucch_symbols(const srs_builder_params& user_srs_params) +{ + // [Implementation-defined] In the following, we compute the maximum number of PUCCH symbols that can be used in a + // slot based on the PUCCH and SRS configurations. The maximum number of PUCCH symbols is computed so that PUCCH and + // SRS resources occupy all symbols in a slot and in such a way that they do not overlap each other. + return user_srs_params.srs_enabled ? NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - user_srs_params.max_nof_symbols.to_uint() + : NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; +} From f2c486bddce7407ee5ca0d2dbafbb4fdfbe5a59d Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 28 Aug 2024 11:42:58 +0200 Subject: [PATCH 358/407] du: improve comments in DU parameter definitions Signed-off-by: Carlo Galiotto --- apps/units/flexible_du/du_high/du_high_config.h | 6 ++++-- include/srsran/du/du_cell_config.h | 1 + include/srsran/du/du_update_config_helpers.h | 2 +- 3 files changed, 6 insertions(+), 3 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 40dda6746d..69f8b63692 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -273,7 +273,9 @@ struct du_high_unit_pucch_config { struct du_high_unit_srs_config { /// Enable Sound Reference Signals (SRS) for the UEs within this cell. bool srs_enabled = false; - /// Defines the maximum number of symbols dedicated to the cell SRS resources in a slot. Values: {1,...,6}. + /// \brief Defines the maximum number of symbols dedicated to the cell SRS resources in a slot. Values: {1,...,6}. + /// This is the space that the GNB reserves for all the cell SRS resources in the UL slots, not to be confused with + /// the symbols per SRS resource configured in the UE dedicated configuration. unsigned max_nof_symbols_per_slot = 2U; }; @@ -560,7 +562,7 @@ struct du_high_unit_base_cell_config { du_high_unit_pusch_config pusch_cfg; /// PUCCH configuration. du_high_unit_pucch_config pucch_cfg; - /// srs configuration. + /// SRS configuration. du_high_unit_srs_config srs_cfg; /// Physical Cell Group parameters. du_high_unit_phy_cell_group_config pcg_cfg; diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index c7673ea32b..d15c8e4892 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -105,6 +105,7 @@ struct srs_builder_params { /// \remark In case of Sounding Reference Signals (SRS) being used, the number of symbols should be reduced so that /// the PUCCH resources do not overlap in symbols with the SRS resources. /// \remark The SRS resources are always placed at the end of the slot. + /// \remark As per TS 38.211, Section 6.4.1.4.1, SRS resource can only be placed in the last 6 symbols of a slot. bounded_integer max_nof_symbols = 2U; }; diff --git a/include/srsran/du/du_update_config_helpers.h b/include/srsran/du/du_update_config_helpers.h index ab64346216..b62e3df709 100644 --- a/include/srsran/du/du_update_config_helpers.h +++ b/include/srsran/du/du_update_config_helpers.h @@ -39,7 +39,7 @@ void compute_nof_sr_csi_pucch_res(pucch_builder_params& user_params, float sr_period_msec, std::optional csi_period_msec); -bounded_integer compute_max_nof_pucch_symbols(const srs_builder_params& user_srs_params); +bounded_integer compute_max_nof_pucch_symbols(const srs_builder_params& user_srs_params); } // namespace config_helpers } // namespace srsran From b269a341adae997c06c4d0561861a90f49993941 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 27 Aug 2024 14:55:52 +0200 Subject: [PATCH 359/407] du_high_unit: add option to configure the scheduling of TA CMD MAC CE --- .../flexible_du/du_high/du_high_config.h | 13 ++++++++++ .../du_high/du_high_config_cli11_schema.cpp | 24 +++++++++++++++++++ 2 files changed, 37 insertions(+) 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 69f8b63692..efe87c62f5 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -57,10 +57,23 @@ struct du_high_unit_logger_config { bool f1ap_json_enabled = false; }; +/// Timing Advance MAC CE scheduling expert configuration. +struct du_high_unit_ta_sched_expert_config { + /// Measurements periodicity in nof. slots over which the new Timing Advance Command is computed. + unsigned ta_measurement_slot_period = 80; + /// Timing Advance Command (T_A) offset threshold above which Timing Advance Command is triggered. Possible valid + /// values {0,...,32}. If set to less than zero, issuing of TA Command is disabled. + int ta_cmd_offset_threshold = 1; + /// UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid. + float ta_update_measurement_ul_sinr_threshold = 0.0F; +}; + /// Scheduler expert configuration. struct du_high_unit_scheduler_expert_config { /// Policy scheduler expert parameters. policy_scheduler_expert_config policy_sched_expert_cfg = time_rr_scheduler_expert_config{}; + /// Timing Advance MAC CE scheduling expert configuration. + du_high_unit_ta_sched_expert_config ta_sched_cfg; }; struct du_high_unit_ssb_config { 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 52eb637db3..454516aa7f 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 @@ -563,11 +563,35 @@ static void configure_cli11_policy_scheduler_expert_args(CLI::App& app, policy_s pf_sched_cfg_subcmd->parse_complete_callback(pf_sched_verify_callback); } +static void configure_cli11_ta_scheduler_expert_args(CLI::App& app, du_high_unit_ta_sched_expert_config& ta_params) +{ + add_option(app, + "--ta_measurement_slot_period", + ta_params.ta_measurement_slot_period, + "Measurements periodicity in nof. slots over which the new Timing Advance Command is computed") + ->capture_default_str(); + add_option(app, + "--ta_cmd_offset_threshold", + ta_params.ta_cmd_offset_threshold, + "Timing Advance Command (T_A) offset threshold above which Timing Advance Command is triggered. If set to " + "less than zero, issuing of TA Command is disabled") + ->capture_default_str() + ->check(CLI::Range(-1, 31)); + add_option(app, + "--ta_update_measurement_ul_sinr_threshold", + ta_params.ta_update_measurement_ul_sinr_threshold, + "UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid") + ->capture_default_str(); +} + static void configure_cli11_scheduler_expert_args(CLI::App& app, du_high_unit_scheduler_expert_config& expert_params) { CLI::App* policy_sched_cfg_subcmd = add_subcommand(app, "policy_sched_cfg", "Policy scheduler expert configuration")->configurable(); configure_cli11_policy_scheduler_expert_args(*policy_sched_cfg_subcmd, expert_params.policy_sched_expert_cfg); + CLI::App* ta_sched_cfg_subcmd = + add_subcommand(app, "ta_sched_cfg", "Timing Advance MAC CE scheduling expert configuration")->configurable(); + configure_cli11_ta_scheduler_expert_args(*ta_sched_cfg_subcmd, expert_params.ta_sched_cfg); } static void configure_cli11_ul_common_args(CLI::App& app, du_high_unit_ul_common_config& ul_common_params) From 7438abbd109aa14d2ab322f86d9cf0d73492a2b0 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 27 Aug 2024 14:58:25 +0200 Subject: [PATCH 360/407] du_high_unit: propagate TA CMD MAC CE scheduling parameters to scheduler --- apps/units/flexible_du/du_high/du_high_config_translators.cpp | 4 ++++ 1 file changed, 4 insertions(+) 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 4c181bb06a..aa5129df37 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 @@ -854,6 +854,10 @@ scheduler_expert_config srsran::generate_scheduler_expert_config(const du_high_u if (std::holds_alternative(app_sched_expert_cfg.policy_sched_expert_cfg)) { out_cfg.ue.strategy_cfg = app_sched_expert_cfg.policy_sched_expert_cfg; } + out_cfg.ue.ta_cmd_offset_threshold = app_sched_expert_cfg.ta_sched_cfg.ta_cmd_offset_threshold; + out_cfg.ue.ta_measurement_slot_period = app_sched_expert_cfg.ta_sched_cfg.ta_measurement_slot_period; + out_cfg.ue.ta_update_measurement_ul_sinr_threshold = + app_sched_expert_cfg.ta_sched_cfg.ta_update_measurement_ul_sinr_threshold; // PUCCH and scheduler expert parameters. out_cfg.ue.max_ul_grants_per_slot = cell.ul_common_cfg.max_ul_grants_per_slot; From 3bda22423392fa9b8d48fe5cfe85773c95f6f613 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 29 Aug 2024 12:12:09 +0200 Subject: [PATCH 361/407] du_high_unit,sched: add TS reference for T_A --- apps/units/flexible_du/du_high/du_high_config.h | 1 + include/srsran/scheduler/config/scheduler_expert_config.h | 1 + 2 files changed, 2 insertions(+) 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 efe87c62f5..486b9d6cb0 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -63,6 +63,7 @@ struct du_high_unit_ta_sched_expert_config { unsigned ta_measurement_slot_period = 80; /// Timing Advance Command (T_A) offset threshold above which Timing Advance Command is triggered. Possible valid /// values {0,...,32}. If set to less than zero, issuing of TA Command is disabled. + /// \remark T_A is defined in TS 38.213, clause 4.2. int ta_cmd_offset_threshold = 1; /// UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid. float ta_update_measurement_ul_sinr_threshold = 0.0F; diff --git a/include/srsran/scheduler/config/scheduler_expert_config.h b/include/srsran/scheduler/config/scheduler_expert_config.h index ebd5243e1b..aec3a096db 100644 --- a/include/srsran/scheduler/config/scheduler_expert_config.h +++ b/include/srsran/scheduler/config/scheduler_expert_config.h @@ -65,6 +65,7 @@ struct scheduler_ue_expert_config { unsigned ta_measurement_slot_period{80}; /// Timing Advance Command (T_A) offset threshold above which Timing Advance Command is triggered. Possible valid /// values {0,...,32}. If set to less than zero, issuing of TA Command is disabled. + /// \remark T_A is defined in TS 38.213, clause 4.2. int8_t ta_cmd_offset_threshold; /// UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid. float ta_update_measurement_ul_sinr_threshold; From 8629074d4c60933b63edee13b38fa14e530edcd7 Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 29 Aug 2024 10:00:43 +0200 Subject: [PATCH 362/407] ci: add delay to create tags --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b3b42c020b..6a7d06417c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -466,7 +466,7 @@ create-tags: rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 30 minutes + start_in: 3 hours script: - | for name in $TAG_NAME_ARRAY; do From a75459aa4b47a349e7623b0e64bbe70397e9358a Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 29 Aug 2024 10:00:50 +0200 Subject: [PATCH 363/407] ci,e2e: uesim related changes --- .gitlab/ci/e2e.yml | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 5e3b0e1661..7ac5434e70 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -272,6 +272,7 @@ smoke zmq: stage: zmq extends: .e2e-run variables: + GROUP: uesim TESTBED: zmq_uesim E2E_LOG_LEVEL: "info" needs: @@ -495,16 +496,6 @@ cudu amari 8UE: matrix: - KEYWORDS: ["reestablishment and sequentially"] -cudu amari 8UE uesim: - extends: .zmq-uesim - variables: - TESTBED: zmq_cudu - MARKERS: "zmq and not smoke" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - parallel: - matrix: - - KEYWORDS: ["reestablishment and sequentially"] - cudu amari 32UE: extends: .zmq variables: @@ -515,16 +506,6 @@ cudu amari 32UE: matrix: - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] -cudu amari 32UE uesim: - extends: .zmq-uesim - variables: - TESTBED: zmq_cudu - MARKERS: "zmq and not smoke" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - parallel: - matrix: - - KEYWORDS: ["ping", "iperf and tcp and not band:3 and bandwidth:50"] - ################################################################################ # TEST MODE ################################################################################ From 8c319814f37370cab0c7ff9409d1f1a5c9fa207f Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 29 Aug 2024 15:16:28 +0200 Subject: [PATCH 364/407] ci,e2e: fix srsue job --- .gitlab/ci/e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 7ac5434e70..4f39f9ded3 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -287,6 +287,7 @@ srsue: extends: .zmq variables: TESTBED: "zmq_srsue" + MARKERS: "zmq_srsue" amari 1UE: extends: .zmq From c447e003dfc1d2f71c86f01a8a9f4164a596900a Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 22 Aug 2024 11:00:03 +0200 Subject: [PATCH 365/407] f1ap_du: forward UE capabilities to DU manager during UE context setup --- .../du/procedures/f1ap_du_ue_context_setup_procedure.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index f9ff933420..e37e8a99f7 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -159,6 +159,11 @@ async_task f1ap_du_ue_context_setup_procedure:: } } + // > Add UE capabilities information. + if (not msg->cu_to_du_rrc_info.ue_cap_rat_container_list.empty()) { + du_request.ue_cap_rat_list = msg->cu_to_du_rrc_info.ue_cap_rat_container_list.copy(); + } + return ue->du_handler.request_ue_context_update(du_request); } From 4cadf712deebc5de86c9d04183238cafe9c2adad Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 28 Aug 2024 13:18:51 +0200 Subject: [PATCH 366/407] cu_up: extend life-time of cancelled flag to avoid that pending tasks outlive it --- lib/cu_up/cu_up_executor_pool.cpp | 53 +++++++++++++++++++------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/cu_up/cu_up_executor_pool.cpp b/lib/cu_up/cu_up_executor_pool.cpp index b95a5b4bf9..d316da11e1 100644 --- a/lib/cu_up/cu_up_executor_pool.cpp +++ b/lib/cu_up/cu_up_executor_pool.cpp @@ -9,6 +9,7 @@ */ #include "srsran/cu_up/cu_up_executor_pool.h" +#include "srsran/srslog/srslog.h" #include "srsran/support/async/execute_on.h" using namespace srsran; @@ -22,14 +23,26 @@ class cancellable_task_executor final : public task_executor public: cancellable_task_executor(task_executor& exec_) : exec(&exec_) {} - /// \brief Cancel pending tasks. /// Note: This needs to be called from within the executor's context. - void cancel() { cancelled = true; } + ~cancellable_task_executor() override + { + // cancel pending tasks. + *cancelled = true; + + // extend life-time of cancelled flag by moving it into an executor. + while (not exec->defer([flag_moved = std::move(cancelled)]() mutable { + // flag is finally destroyed. + flag_moved.reset(); + })) { + srslog::fetch_basic_logger("ALL").warning("Unable to dispatch UE task executor deletion. Retrying..."); + std::this_thread::sleep_for(std::chrono::microseconds{100}); + } + } [[nodiscard]] bool execute(unique_task task) override { - return exec->execute([this, task = std::move(task)]() { - if (cancelled) { + return exec->execute([cancelled_ref = *cancelled, task = std::move(task)]() { + if (cancelled_ref) { return; } task(); @@ -38,8 +51,8 @@ class cancellable_task_executor final : public task_executor [[nodiscard]] bool defer(unique_task task) override { - return exec->defer([this, task = std::move(task)]() { - if (cancelled) { + return exec->defer([cancelled_ref = *cancelled, task = std::move(task)]() { + if (cancelled_ref) { return; } task(); @@ -47,8 +60,8 @@ class cancellable_task_executor final : public task_executor } private: - task_executor* exec; - bool cancelled = false; + task_executor* exec; + std::unique_ptr cancelled = std::make_unique(false); }; /// Implementation of the UE executor mapper. @@ -72,13 +85,13 @@ class ue_executor_mapper_impl final : public ue_executor_mapper CORO_BEGIN(ctx); // Switch to the UE execution context. - CORO_AWAIT(defer_to_blocking(ctrl_exec)); + CORO_AWAIT(defer_to_blocking(*ctrl_exec)); // Cancel all pending tasks. // Note: this operation is only thread-safe because we are calling it from the UE executor's context. - ctrl_exec.cancel(); - ul_exec.cancel(); - dl_exec.cancel(); + ctrl_exec.reset(); + ul_exec.reset(); + dl_exec.reset(); // Return back to main control execution context. CORO_AWAIT(defer_to_blocking(main_exec)); @@ -87,17 +100,17 @@ class ue_executor_mapper_impl final : public ue_executor_mapper }); } - task_executor& ctrl_executor() override { return ctrl_exec; } - task_executor& ul_pdu_executor() override { return ul_exec; } - task_executor& dl_pdu_executor() override { return dl_exec; } + task_executor& ctrl_executor() override { return *ctrl_exec; } + task_executor& ul_pdu_executor() override { return *ul_exec; } + task_executor& dl_pdu_executor() override { return *dl_exec; } task_executor& crypto_executor() override { return crypto_exec; } private: - cancellable_task_executor ctrl_exec; - cancellable_task_executor ul_exec; - cancellable_task_executor dl_exec; - task_executor& crypto_exec; - task_executor& main_exec; + std::optional ctrl_exec; + std::optional ul_exec; + std::optional dl_exec; + task_executor& crypto_exec; + task_executor& main_exec; }; } // namespace From 35ea28c9bc5a11b3304c823c4a57ee1212d72273 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 28 Aug 2024 14:10:14 +0200 Subject: [PATCH 367/407] cu_up: fix capture-by-reference in cu_up executor mapper --- lib/cu_up/cu_up_executor_pool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cu_up/cu_up_executor_pool.cpp b/lib/cu_up/cu_up_executor_pool.cpp index d316da11e1..d8b3d4fc1c 100644 --- a/lib/cu_up/cu_up_executor_pool.cpp +++ b/lib/cu_up/cu_up_executor_pool.cpp @@ -41,7 +41,7 @@ class cancellable_task_executor final : public task_executor [[nodiscard]] bool execute(unique_task task) override { - return exec->execute([cancelled_ref = *cancelled, task = std::move(task)]() { + return exec->execute([&cancelled_ref = *cancelled, task = std::move(task)]() { if (cancelled_ref) { return; } @@ -51,7 +51,7 @@ class cancellable_task_executor final : public task_executor [[nodiscard]] bool defer(unique_task task) override { - return exec->defer([cancelled_ref = *cancelled, task = std::move(task)]() { + return exec->defer([&cancelled_ref = *cancelled, task = std::move(task)]() { if (cancelled_ref) { return; } From 7e9ac15e4d090b6ed88012b49a21823477fa8bd5 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 28 Aug 2024 16:31:26 +0200 Subject: [PATCH 368/407] log: pass log_label as const& until copy is actually needed... ...to avoid atomic ops of shared_ptr copy when log level is disabled. --- include/srsran/srslog/log_channel.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/srsran/srslog/log_channel.h b/include/srsran/srslog/log_channel.h index 3a097a307b..91bbfe17cf 100644 --- a/include/srsran/srslog/log_channel.h +++ b/include/srsran/srslog/log_channel.h @@ -139,7 +139,7 @@ class log_channel /// Builds the provided log entry and passes it to the backend. When the /// channel is disabled the log entry will be discarded. template - void operator()(std::shared_ptr log_label, const char* fmtstr, Args&&... args) + void operator()(const std::shared_ptr& log_label, const char* fmtstr, Args&&... args) { if (!enabled()) { return; @@ -164,7 +164,7 @@ class log_channel store, log_name, log_tag, - std::move(log_label)}}; + log_label}}; backend.push(std::move(entry)); } @@ -240,10 +240,10 @@ class log_channel /// Builds the provided log entry and passes it to the backend. When the /// channel is disabled the log entry will be discarded. template - void operator()(std::shared_ptr log_label, - const uint8_t* buffer, - size_t len, - const char* fmtstr, + void operator()(const std::shared_ptr& log_label, + const uint8_t* buffer, + size_t len, + const char* fmtstr, Args&&... args) { if (!enabled()) { @@ -389,7 +389,7 @@ class log_channel store, log_name, log_tag, - std::move(log_label), + log_label, std::vector(it_begin, it_end)}}; backend.push(std::move(entry)); } From b6ffd938e0ddf2c33d516a433950641349ecaaab Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 29 Aug 2024 12:00:43 +0200 Subject: [PATCH 369/407] sched: update TA CMD CE if its pending to be scheduled --- .../ue_scheduling/dl_logical_channel_manager.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h b/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h index 30c262a3cd..f1935eac51 100644 --- a/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_scheduling/dl_logical_channel_manager.h @@ -119,9 +119,18 @@ class dl_logical_channel_manager { if (ce.ce_lcid == lcid_dl_sch_t::UE_CON_RES_ID) { pending_con_res_id = true; - } else { - pending_ces.push_back(ce); + return; } + if (ce.ce_lcid == lcid_dl_sch_t::TA_CMD) { + auto ce_it = std::find_if(pending_ces.begin(), pending_ces.end(), [](const mac_ce_info& c) { + return c.ce_lcid == lcid_dl_sch_t::TA_CMD; + }); + if (ce_it != pending_ces.end()) { + ce_it->ce_payload = ce.ce_payload; + return; + } + } + pending_ces.push_back(ce); } /// \brief Allocates highest priority MAC SDU within space of \c rem_bytes bytes. Updates \c lch_info with allocated From 1deea3f5afac3077cc1de6396c1ef8335dd47d79 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 29 Aug 2024 12:01:16 +0200 Subject: [PATCH 370/407] unittest: add test to verify update of TA CMD CE if its pending to be scheduled --- .../ue_scheduling/logical_channel_test.cpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index d075ad49cf..955e6c2c77 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -295,3 +295,25 @@ TEST(dl_logical_channel_test, assign_leftover_bytes_to_sdu_if_leftover_bytes_is_ // Verify leftover bytes are assigned to the last SDU. ASSERT_EQ(allocated_bytes, tb_size); } + +TEST(dl_logical_channel_test, ta_cmd_mac_ce_gets_updated_if_already_in_pending_ces_queue) +{ + dl_logical_channel_manager lch_mng; + const auto first_ta_cmd_ce_payload = ta_cmd_ce_payload{.tag_id = 0, .ta_cmd = 29}; + lch_mng.handle_mac_ce_indication({.ce_lcid = lcid_dl_sch_t::TA_CMD, .ce_payload = first_ta_cmd_ce_payload}); + ASSERT_TRUE(lch_mng.has_pending_bytes()); + ASSERT_TRUE(lch_mng.has_pending_ces()); + + const auto second_ta_cmd_ce_payload = ta_cmd_ce_payload{.tag_id = 0, .ta_cmd = 33}; + lch_mng.handle_mac_ce_indication({.ce_lcid = lcid_dl_sch_t::TA_CMD, .ce_payload = second_ta_cmd_ce_payload}); + ASSERT_TRUE(lch_mng.has_pending_bytes()); + ASSERT_TRUE(lch_mng.has_pending_ces()); + + dl_msg_lc_info subpdu; + lch_mng.allocate_mac_ce(subpdu, 100000); + + ASSERT_EQ(subpdu.lcid, lcid_dl_sch_t::TA_CMD); + ASSERT_EQ(subpdu.sched_bytes, lcid_dl_sch_t{lcid_dl_sch_t::TA_CMD}.sizeof_ce()); + ASSERT_TRUE(std::holds_alternative(subpdu.ce_payload)); + ASSERT_EQ(std::get(subpdu.ce_payload).ta_cmd, second_ta_cmd_ce_payload.ta_cmd); +} From 51519cfb2e186712522020c5d83781e71b8147a4 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 29 Aug 2024 13:42:07 +0200 Subject: [PATCH 371/407] sched: add helper methods to return whether UE has pending CE bytes to be scheduled or not --- lib/scheduler/ue_scheduling/ue.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/scheduler/ue_scheduling/ue.h b/lib/scheduler/ue_scheduling/ue.h index 5874b1388b..19de4ada24 100644 --- a/lib/scheduler/ue_scheduling/ue.h +++ b/lib/scheduler/ue_scheduling/ue.h @@ -139,6 +139,9 @@ class ue /// \brief Returns the UE pending CEs' bytes to be scheduled, if any. unsigned pending_ce_bytes() const { return dl_lc_ch_mgr.pending_ce_bytes(); } + /// \brief Returns whether the UE has pending CEs' bytes to be scheduled, if any. + bool has_pending_ce_bytes() const { return dl_lc_ch_mgr.is_con_res_id_pending() or dl_lc_ch_mgr.has_pending_ces(); } + /// \brief Computes the number of DL pending bytes that are not already allocated in a DL HARQ. The value is used /// to derive the required transport block size for an DL grant. /// param[in] lcid If the LCID is provided, the method will return the number of pending bytes for that LCID. From c85a4e9b4f826a8694904614b0290fcc1aceb5fb Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 29 Aug 2024 13:43:07 +0200 Subject: [PATCH 372/407] sched: check for pending CEs to be scheduled along with pending bytes of LCIDs belonging to a slice --- lib/scheduler/slicing/slice_ue_repository.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index 0bfc372e1e..17a88ed515 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -42,6 +42,9 @@ void slice_ue::rem_logical_channel(lcid_t lcid) bool slice_ue::has_pending_dl_newtx_bytes() const { + if (u.has_pending_ce_bytes()) { + return true; + } for (unsigned lcid = 0, e = bearers.size(); lcid != e; ++lcid) { if (bearers.test(lcid) and u.has_pending_dl_newtx_bytes(uint_to_lcid(lcid))) { return true; @@ -52,7 +55,7 @@ bool slice_ue::has_pending_dl_newtx_bytes() const unsigned slice_ue::pending_dl_newtx_bytes() const { - unsigned pending_bytes = 0; + unsigned pending_bytes = u.pending_ce_bytes(); for (unsigned lcid = 0, e = bearers.size(); lcid != e; ++lcid) { if (bearers.test(lcid)) { pending_bytes += u.pending_dl_newtx_bytes(uint_to_lcid(lcid)); From 208dec7473f152cec0003f55de5ae016e1b52723 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 29 Aug 2024 14:01:04 +0200 Subject: [PATCH 373/407] unittest: add unittest to verify scheduling of PDSCH when only MAC CEs are pending and no pending data in bearers --- .../scheduler/policy/scheduler_policy_test.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index 4101b135f5..627464c070 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -408,6 +408,23 @@ TEST_P(scheduler_policy_test, scheduler_allocates_ues_with_dl_srb_newtx_first_th ASSERT_EQ(this->res_grid[0].result.dl.ue_grants[0].context.ue_index, u2.ue_index); } +TEST_P(scheduler_policy_test, scheduler_allocates_pdsch_even_when_only_pending_ces_are_enqueued) +{ + const lcg_id_t drb_lcg_id = uint_to_lcg_id(2); + ue& u1 = add_ue(make_ue_create_req(to_du_ue_index(0), to_rnti(0x4601), {LCID_MIN_DRB}, drb_lcg_id)); + + // Enqueue TA CMD MAC CE. + dl_mac_ce_indication ind{}; + ind.ue_index = u1.ue_index; + ind.ce_lcid = lcid_dl_sch_t::TA_CMD; + u1.handle_dl_mac_ce_indication(ind); + + bool pdsch_scheduled = run_until([this]() { return not this->res_grid[0].result.dl.ue_grants.empty(); }); + ASSERT_TRUE(pdsch_scheduled); + ASSERT_EQ(this->res_grid[0].result.dl.ue_grants[0].context.ue_index, u1.ue_index); + ASSERT_EQ(this->res_grid[0].result.dl.ue_grants[0].tb_list.back().lc_chs_to_sched.back().lcid, lcid_dl_sch_t::TA_CMD); +} + class scheduler_policy_partial_slot_tdd_test : public base_scheduler_policy_test, public ::testing::TestWithParam { From 045edb4f75fe1606dac3984dda9a50439b08b853 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 30 Aug 2024 10:52:58 +0200 Subject: [PATCH 374/407] ci: remove duplicate amari jobs --- .gitlab/ci/e2e.yml | 109 +++++++------------------------------------- .gitlab/ci/e2e/.env | 2 +- 2 files changed, 18 insertions(+), 93 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 4f39f9ded3..7452db4f4e 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -281,7 +281,6 @@ smoke zmq: - job: "build uesim zmq driver" artifacts: true - *retina-needs - allow_failure: true srsue: extends: .zmq @@ -290,24 +289,12 @@ srsue: MARKERS: "zmq_srsue" amari 1UE: - extends: .zmq - variables: - MARKERS: "zmq_single_ue" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - -amari 1UE uesim: extends: .zmq-uesim variables: MARKERS: "zmq_single_ue" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" amari 1UE 4x4 mimo: - extends: .zmq - variables: - MARKERS: "zmq_4x4_mimo" - RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" - -amari 1UE 4x4 mimo uesim: extends: .zmq-uesim variables: MARKERS: "zmq_4x4_mimo" @@ -325,31 +312,7 @@ amari 4UE deb: - *txrx-lib - *retina-needs -amari 4UE deb uesim: - extends: .zmq-uesim - variables: - TESTBED: "zmq_deb" - MARKERS: "smoke" - RETINA_PARAM_ARGS: "gnb.all.enable_integrity_protection=True" - needs: - - job: "basic package" - artifacts: true - - *txrx-lib - - *retina-needs - amari 4UE asan: - extends: .zmq - variables: - MARKERS: "smoke" - KEYWORDS: "iperf" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - needs: - - job: "basic asan" - artifacts: true - - *txrx-lib - - *retina-needs - -amari 4UE asan uesim: extends: .zmq-uesim variables: MARKERS: "smoke" @@ -362,18 +325,6 @@ amari 4UE asan uesim: - *retina-needs amari 4UE tsan: - extends: .zmq - variables: - MARKERS: "smoke" - KEYWORDS: "iperf" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - needs: - - job: "basic tsan" - artifacts: true - - *txrx-lib - - *retina-needs - -amari 4UE tsan uesim: extends: .zmq-uesim variables: MARKERS: "smoke" @@ -386,18 +337,6 @@ amari 4UE tsan uesim: - *retina-needs amari 4UE memcheck: - extends: .zmq - variables: - MARKERS: "zmq_valgrind" - E2E_LOG_LEVEL: "warning" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" - needs: - - job: "basic memcheck" - artifacts: true - - *txrx-lib - - *retina-needs - -amari 4UE memcheck uesim: extends: .zmq-uesim variables: MARKERS: "zmq_valgrind" @@ -410,32 +349,29 @@ amari 4UE memcheck uesim: - *retina-needs amari 8UE: - extends: .zmq + extends: .zmq-uesim variables: MARKERS: "zmq and not smoke" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" parallel: matrix: - KEYWORDS: - [ - "attach_detach", - "reestablishment and sequentially", - "handover and sequentially", - ] + ["reestablishment and sequentially", "handover and sequentially"] -amari 8UE uesim: +amari 8UE [attach_detach 2024-03-15]: extends: .zmq-uesim variables: MARKERS: "zmq and not smoke" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - parallel: - matrix: - - KEYWORDS: - [ - "attach_detach", - "reestablishment and sequentially", - "handover and sequentially", - ] + KEYWORDS: "attach_detach" + allow_failure: true + +amari 8UE [attach_detach 2023-09-08]: + extends: .zmq + variables: + MARKERS: "zmq and not smoke" + RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + KEYWORDS: "attach_detach" amari 8UE beta: extends: amari 8UE @@ -448,17 +384,6 @@ amari 8UE beta: ] allow_failure: true -amari 8UE beta uesim: - extends: amari 8UE uesim - parallel: - matrix: - - KEYWORDS: - [ - "reestablishment and not sequentially", - "handover and not sequentially", - ] - allow_failure: true - amari 32UE: extends: .zmq variables: @@ -468,20 +393,20 @@ amari 32UE: matrix: - KEYWORDS: [ - "ping", "iperf and udp and band:3", "iperf and udp and not band:3", "iperf and tcp and band:3", "iperf and tcp and not band:3", ] -amari 32UE 2x2 mimo: - extends: .zmq +amari 32UE [ping]: + extends: .zmq-uesim variables: - MARKERS: "zmq_2x2_mimo" + MARKERS: "zmq and not smoke" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + KEYWORDS: ping -amari 32UE 2x2 mimo uesim: +amari 32UE 2x2 mimo: extends: .zmq-uesim variables: MARKERS: "zmq_2x2_mimo" diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index d293370563..06a123f5e8 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.52.8 +RETINA_VERSION=0.52.9 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From 6d7885731bf7fb32387cf2daa5d9aa956a45ed4a Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 21 Aug 2024 09:12:20 +0200 Subject: [PATCH 375/407] sched: track PUSCH grant allocation on a per PUSCH slot basis in a slice --- lib/scheduler/slicing/ran_slice_candidate.h | 12 +- lib/scheduler/slicing/ran_slice_instance.cpp | 8 +- lib/scheduler/slicing/ran_slice_instance.h | 22 +++- lib/scheduler/slicing/slice_scheduler.cpp | 50 ++++++-- lib/scheduler/slicing/slice_scheduler.h | 15 ++- .../pusch/pusch_td_resource_indices.cpp | 10 ++ .../ue_scheduling/ue_scheduler_impl.cpp | 2 +- .../policy/scheduler_policy_test.cpp | 2 +- .../slicing/slice_scheduler_test.cpp | 111 +++++++++++------- 9 files changed, 160 insertions(+), 72 deletions(-) diff --git a/lib/scheduler/slicing/ran_slice_candidate.h b/lib/scheduler/slicing/ran_slice_candidate.h index e75e436b09..b7bc55b62c 100644 --- a/lib/scheduler/slicing/ran_slice_candidate.h +++ b/lib/scheduler/slicing/ran_slice_candidate.h @@ -20,8 +20,8 @@ template class common_ran_slice_candidate { public: - common_ran_slice_candidate(ran_slice_instance& instance_, unsigned max_rbs_ = 0) : - inst(&instance_), max_rbs(max_rbs_ == 0 ? inst->cfg.max_prb : max_rbs_) + common_ran_slice_candidate(ran_slice_instance& instance_, slot_point slot_tx_, unsigned max_rbs_ = 0) : + inst(&instance_), max_rbs(max_rbs_ == 0 ? inst->cfg.max_prb : max_rbs_), slot_tx(slot_tx_) { } @@ -40,7 +40,7 @@ class common_ran_slice_candidate if constexpr (IsDl) { inst->store_pdsch_grant(nof_rbs); } else { - inst->store_pusch_grant(nof_rbs); + inst->store_pusch_grant(nof_rbs, slot_tx); } } @@ -50,12 +50,16 @@ class common_ran_slice_candidate if constexpr (IsDl) { return max_rbs < inst->pdsch_rb_count ? 0 : max_rbs - inst->pdsch_rb_count; } - return max_rbs < inst->pusch_rb_count ? 0 : max_rbs - inst->pusch_rb_count; + return max_rbs < inst->pusch_rb_count_per_slot[slot_tx.to_uint()] + ? 0 + : max_rbs - inst->pusch_rb_count_per_slot[slot_tx.to_uint()]; } protected: ran_slice_instance* inst = nullptr; unsigned max_rbs = 0; + /// Slot at which PUSCH/PDSCH needs to be scheduled for this slice candidate. + slot_point slot_tx; }; } // namespace detail diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index f1be415539..ee8a9ada0e 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -17,12 +17,16 @@ ran_slice_instance::ran_slice_instance(ran_slice_id_t id_, const slice_rrm_policy_config& cfg_) : id(id_), cell_cfg(&cell_cfg_), cfg(cfg_) { + std::fill(pusch_rb_count_per_slot.begin(), pusch_rb_count_per_slot.end(), 0); } -void ran_slice_instance::slot_indication() +void ran_slice_instance::slot_indication(slot_point slot_tx) { pdsch_rb_count = 0; - pusch_rb_count = 0; + // Clear RB count in previous slots. + for (unsigned count = 0; count < nof_slots_to_clear; ++count) { + pusch_rb_count_per_slot[(slot_tx - 1 - count).to_uint()] = 0; + } } void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index b3c434a924..fc76e7a509 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -10,6 +10,7 @@ #pragma once +#include "../../scheduler/cell/resource_grid.h" #include "../config/cell_configuration.h" #include "../ue_scheduling/ue_repository.h" #include "ran_slice_id.h" @@ -21,10 +22,14 @@ namespace srsran { /// This class stores all the internal information relative to a RAN slice instantiation. class ran_slice_instance { + /// Number of slots for which allocated PUSCH grant is maintained. + static const size_t RING_ALLOCATOR_SIZE = + get_allocator_ring_size_gt_min(SCHEDULER_MAX_K2 + NTN_CELL_SPECIFIC_KOFFSET_MAX); + public: ran_slice_instance(ran_slice_id_t id_, const cell_configuration& cell_cfg_, const slice_rrm_policy_config& cfg_); - void slot_indication(); + void slot_indication(slot_point slot_tx); bool active() const { return not slice_ues.empty(); } @@ -32,7 +37,10 @@ class ran_slice_instance void store_pdsch_grant(unsigned crbs) { pdsch_rb_count += crbs; } /// Save PUSCH grant. - void store_pusch_grant(unsigned crbs) { pusch_rb_count += crbs; } + void store_pusch_grant(unsigned crbs, slot_point pusch_slot) + { + pusch_rb_count_per_slot[pusch_slot.to_uint()] += crbs; + } /// Determine if at least one bearer of the given UE is currently managed by this slice. bool contains(du_ue_index_t ue_idx) const @@ -65,8 +73,14 @@ class ran_slice_instance /// Counter of how many RBs have been scheduled for PDSCH in the current slot for this slice. unsigned pdsch_rb_count = 0; - /// Counter of how many RBs have been scheduled for PUSCH in the current slot for this slice. - unsigned pusch_rb_count = 0; + /// Ring of counters of how many RBs have been scheduled for PUSCH in a particular slot for this slice. + circular_array pusch_rb_count_per_slot; + + /// Nof. of previous slots in which RB count needs to be cleared in \c pusch_rb_count_per_slot upon receiving slot + /// indication. + /// \remark This is needed since slot_indication() is called only over DL slots. + unsigned nof_slots_to_clear = + cell_cfg->tdd_cfg_common.has_value() ? nof_slots_per_tdd_period(*cell_cfg->tdd_cfg_common) : 1; private: slice_ue_repository slice_ues; diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 07d93ad3b6..6367fc9003 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -10,6 +10,7 @@ #include "slice_scheduler.h" #include "../policy/scheduler_policy_factory.h" +#include "../support/pusch/pusch_td_resource_indices.h" #include "srsran/srslog/srslog.h" using namespace srsran; @@ -41,24 +42,48 @@ slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, ue_reposit slices.back().policy = create_scheduler_strategy(slice_scheduler_ue_expert_cfg); ++id_count; } + + // NOTE: Below derivation assumes that only pusch-ConfigCommon includes pusch-TimeDomainAllocationList. + // NOTE: [Implementation-defined] In case of FDD, we use only single value of k2. + unsigned nof_slots = cell_cfg.is_tdd() ? nof_slots_per_tdd_period(*cell_cfg.tdd_cfg_common) : 1; + valid_pusch_td_list_per_slot.resize(nof_slots); + for (unsigned slot_period_idx = 0, e = nof_slots; slot_period_idx != e; ++slot_period_idx) { + slot_point pdcch_slot{to_numerology_value(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs), slot_period_idx}; + if (cell_cfg.is_dl_enabled(pdcch_slot)) { + // TODO: Revisit when PUSCH time domain resource list is also defined in UE dedicated configuration. + valid_pusch_td_list_per_slot[slot_period_idx] = get_pusch_td_resource_indices(cell_cfg, pdcch_slot); + } + } } -void slice_scheduler::slot_indication() +void slice_scheduler::slot_indication(slot_point slot_tx) { slot_count++; // Update the context of each slice. for (auto& slice : slices) { - slice.inst.slot_indication(); + slice.inst.slot_indication(slot_tx); } + // TODO: Update slices (store_grant()) with already allocated grant in the previous slots. + // Recompute the priority queues. dl_prio_queue.clear(); ul_prio_queue.clear(); for (const auto& slice : slices) { unsigned max_rbs = slice.inst.cfg.min_prb > 0 ? slice.inst.cfg.min_prb : slice.inst.cfg.max_prb; - dl_prio_queue.push(slice_candidate_context{slice.inst.id, slice.get_prio(true, slot_count, false), {0, max_rbs}}); - ul_prio_queue.push(slice_candidate_context{slice.inst.id, slice.get_prio(false, slot_count, false), {0, max_rbs}}); + dl_prio_queue.push(slice_candidate_context{ + slice.inst.id, slice.get_prio(true, slot_count, false, slot_tx), {0, max_rbs}, slot_tx}); + + // TODO: Revisit when PUSCH time domain resource list is also defined in UE dedicated configuration. + span pusch_time_domain_list = + cell_cfg.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().pusch_td_alloc_list; + for (const unsigned pusch_td_res_idx : + valid_pusch_td_list_per_slot[slot_tx.to_uint() % valid_pusch_td_list_per_slot.size()]) { + slot_point pusch_slot = slot_tx + pusch_time_domain_list[pusch_td_res_idx].k2; + ul_prio_queue.push(slice_candidate_context{ + slice.inst.id, slice.get_prio(false, slot_count, false, pusch_slot), {0, max_rbs}, pusch_slot}); + } } } @@ -189,9 +214,11 @@ slice_scheduler::get_next_candidate() while (not prio_queue.empty()) { ran_slice_sched_context& chosen_slice = slices[prio_queue.top().id.value()]; interval rb_lims = prio_queue.top().rb_lims; + slot_point slot_tx = prio_queue.top().slot_tx; prio_queue.pop(); - unsigned rb_count = IsDownlink ? chosen_slice.inst.pdsch_rb_count : chosen_slice.inst.pusch_rb_count; + unsigned rb_count = + IsDownlink ? chosen_slice.inst.pdsch_rb_count : chosen_slice.inst.pusch_rb_count_per_slot[slot_tx.to_uint()]; if (not rb_lims.contains(rb_count)) { // The slice has been scheduled in this slot with a number of RBs that is not within the limits for this // candidate. This could happen, for instance, if the scheduler could not schedule all RBs of a candidate @@ -204,8 +231,8 @@ slice_scheduler::get_next_candidate() if (cfg.min_prb != cfg.max_prb and rb_lims.stop() == cfg.min_prb) { // For the special case when minRB ratio>0, the first candidate for this slice was bounded between {0, minRB}. // We re-add the slice as a candidate, this time, with RB bounds {minRB, maxRB}. - priority_type prio = chosen_slice.get_prio(true, slot_count, true); - prio_queue.push(slice_candidate_context{chosen_slice.inst.id, prio, {cfg.min_prb, cfg.max_prb}}); + priority_type prio = chosen_slice.get_prio(IsDownlink, slot_count, true, slot_tx); + prio_queue.push(slice_candidate_context{chosen_slice.inst.id, prio, {cfg.min_prb, cfg.max_prb}, slot_tx}); } // Save current slot count. @@ -213,8 +240,8 @@ slice_scheduler::get_next_candidate() count_to_set = slot_count; // Return the candidate. - return std::conditional_t{chosen_slice.inst, - rb_lims.stop()}; + return std::conditional_t{ + chosen_slice.inst, slot_tx, rb_lims.stop()}; } return std::nullopt; } @@ -231,7 +258,8 @@ std::optional slice_scheduler::get_next_ul_candidate() slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_prio(bool is_dl, slot_count_type current_slot_count, - bool slice_resched) const + bool slice_resched, + slot_point slot_tx) const { // Note: The positive integer representing the priority of a slice consists of a concatenation of three priority // values: @@ -248,7 +276,7 @@ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_pri constexpr static priority_type delay_bitsize = 8U; constexpr static priority_type rr_bitsize = 8U; - unsigned rb_count = is_dl ? inst.pdsch_rb_count : inst.pusch_rb_count; + unsigned rb_count = is_dl ? inst.pdsch_rb_count : inst.pusch_rb_count_per_slot[slot_tx.to_uint()]; if (not inst.active() or rb_count >= inst.cfg.max_prb) { // If the slice is not in a state to be scheduled in this slot, return skip priority level. return skip_prio; diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index be57405bf0..84a3c0a3a0 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -28,7 +28,7 @@ class slice_scheduler slice_scheduler(const cell_configuration& cell_cfg_, ue_repository& ues_); /// Reset the state of the slices. - void slot_indication(); + void slot_indication(slot_point slot_tx); /// Update the state of the slice with the provided UE configs. void add_ue(du_ue_index_t ue_idx); @@ -66,16 +66,19 @@ class slice_scheduler } /// Determines the slice candidate priority. - priority_type get_prio(bool is_dl, slot_count_type current_slot_count, bool slice_resched) const; + priority_type + get_prio(bool is_dl, slot_count_type current_slot_count, bool slice_resched, slot_point slot_tx) const; }; struct slice_candidate_context { ran_slice_id_t id; priority_type prio; interval rb_lims; + /// Slot at which PUSCH/PDSCH needs to be scheduled for this slice candidate. + slot_point slot_tx; - slice_candidate_context(ran_slice_id_t id_, priority_type prio_, interval rb_lims_) : - id(id_), prio(prio_), rb_lims(rb_lims_) + slice_candidate_context(ran_slice_id_t id_, priority_type prio_, interval rb_lims_, slot_point slot_tx_) : + id(id_), prio(prio_), rb_lims(rb_lims_), slot_tx(slot_tx_) { } @@ -122,6 +125,10 @@ class slice_scheduler ue_repository& ues; + /// Vector circularly indexed by slot with the list of applicable PUSCH time domain resources per slot. + /// NOTE: The list would be empty for UL slots. + std::vector> valid_pusch_td_list_per_slot; + std::vector slices; // Queue of slice candidates sorted by priority. diff --git a/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp b/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp index 57ed6d42e6..7b814aed2f 100644 --- a/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp +++ b/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp @@ -22,6 +22,12 @@ compute_pusch_td_resource_indices(span pusch_td_res_index_list; + if (pusch_time_domain_list.empty()) { + return pusch_td_res_index_list; + } + // [Implementation-defined] Default PUSCH time domain resource index to use if no valid PUSCH time domain resource is + // found. + const unsigned default_pusch_td_res_index = 0; std::optional nof_full_ul_slots = std::nullopt; std::optional nof_full_dl_slots = std::nullopt; @@ -53,6 +59,10 @@ compute_pusch_td_resource_indices(spanslice_sched.slot_indication(); + cells[cell_index]->slice_sched.slot_indication(slot_tx); // Perform round-robin prioritization of UL and DL scheduling. This gives unfair preference to DL over UL. This is // done to avoid the issue of sending wrong DAI value in DCI format 0_1 to UE while the PDSCH is allocated diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index 627464c070..457276bcc0 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -67,7 +67,7 @@ class base_scheduler_policy_test logger.set_context(next_slot.sfn(), next_slot.slot_index()); grid_alloc.slot_indication(next_slot); - slice_sched.slot_indication(); + slice_sched.slot_indication(next_slot); res_grid.slot_indication(next_slot); pdcch_alloc.slot_indication(next_slot); diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 8b41f002ec..fbf799fb46 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -59,6 +59,9 @@ class slice_scheduler_test ue_repository ues; slice_scheduler slice_sched{cell_cfg, ues}; + +public: + slot_point current_slot{to_numerology_value(cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().scs), 0}; }; class default_slice_scheduler_test : public slice_scheduler_test, public ::testing::Test @@ -85,7 +88,7 @@ TEST_F(default_slice_scheduler_test, if_no_rrm_policy_cfg_exists_then_only_defau TEST_F(default_slice_scheduler_test, when_no_lcid_exists_then_default_slice_is_not_a_candidate) { - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); auto next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); @@ -97,26 +100,32 @@ TEST_F(default_slice_scheduler_test, when_no_lcid_exists_then_default_slice_is_n TEST_F(default_slice_scheduler_test, when_lcid_is_part_of_default_slice_then_default_slice_is_valid_candidate) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); - auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_TRUE(next_dl_slice.has_value()); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); - ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0))); - ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_SRB1)); + for (unsigned count = 0, e = 10; count != e; ++count) { + ++current_slot; + slice_sched.slot_indication(current_slot); - auto next_ul_slice = slice_sched.get_next_ul_candidate(); - ASSERT_TRUE(next_ul_slice.has_value()); - ASSERT_EQ(next_ul_slice->id(), ran_slice_id_t{0}); - ASSERT_TRUE(next_ul_slice->is_candidate(to_du_ue_index(0))); - ASSERT_TRUE(next_ul_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_SRB1)); + auto next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_TRUE(next_dl_slice.has_value()); + ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); + ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0))); + ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_SRB1)); + + auto next_ul_slice = slice_sched.get_next_ul_candidate(); + if (next_ul_slice.has_value()) { + ASSERT_TRUE(next_ul_slice.has_value()); + ASSERT_EQ(next_ul_slice->id(), ran_slice_id_t{0}); + ASSERT_TRUE(next_ul_slice->is_candidate(to_du_ue_index(0))); + ASSERT_TRUE(next_ul_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_SRB1)); + } + } } TEST_F(default_slice_scheduler_test, when_candidate_instance_goes_out_of_scope_then_it_stops_being_a_candidate_for_the_same_slot) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); auto next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_TRUE(next_dl_slice.has_value()); @@ -134,11 +143,11 @@ TEST_F(default_slice_scheduler_test, when_candidate_instance_goes_out_of_scope_t { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); auto next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_TRUE(next_dl_slice.has_value()); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_TRUE(next_dl_slice.has_value()); ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); @@ -147,7 +156,7 @@ TEST_F(default_slice_scheduler_test, when_candidate_instance_goes_out_of_scope_t TEST_F(default_slice_scheduler_test, when_grant_gets_allocated_then_number_of_available_rbs_decreases) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -179,7 +188,7 @@ TEST_F(default_slice_scheduler_test, returns_only_dl_pending_bytes_of_bearers_be ind.bs = srb_pending_bytes; this->ues[ue_idx].handle_dl_buffer_state_indication(ind); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -221,20 +230,25 @@ TEST_F(default_slice_scheduler_test, returns_only_ul_pending_bytes_of_bearers_be msg.reported_lcgs.push_back(ul_bsr_lcg_report{srb_lcg_id, srb_pending_bytes}); this->ues[ue_idx].handle_bsr_indication(msg); - slice_sched.slot_indication(); - - // 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); - const slice_ue_repository& srb_slice_ues = next_dl_slice->get_slice_ues(); - ASSERT_EQ(srb_slice_ues[ue_idx].pending_ul_newtx_bytes(), get_mac_sdu_required_bytes(srb_pending_bytes)); - - // Default DRB slice is next candidate. - next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_drb_slice_id); - const slice_ue_repository& drb_slice_ues = next_dl_slice->get_slice_ues(); - ASSERT_EQ(drb_slice_ues[ue_idx].pending_ul_newtx_bytes(), - RLC_HEADER_SIZE_ESTIMATE + get_mac_sdu_required_bytes(drb_pending_bytes)); + for (unsigned count = 0, e = 10; count != e; ++count) { + ++current_slot; + slice_sched.slot_indication(current_slot); + + auto next_ul_slice = slice_sched.get_next_ul_candidate(); + if (next_ul_slice.has_value()) { + // Default SRB slice has very high priority. + ASSERT_EQ(next_ul_slice->id(), default_srb_slice_id); + const slice_ue_repository& srb_slice_ues = next_ul_slice->get_slice_ues(); + ASSERT_EQ(srb_slice_ues[ue_idx].pending_ul_newtx_bytes(), get_mac_sdu_required_bytes(srb_pending_bytes)); + + // Default DRB slice is next candidate. + next_ul_slice = slice_sched.get_next_ul_candidate(); + ASSERT_EQ(next_ul_slice->id(), default_drb_slice_id); + const slice_ue_repository& drb_slice_ues = next_ul_slice->get_slice_ues(); + ASSERT_EQ(drb_slice_ues[ue_idx].pending_ul_newtx_bytes(), + get_mac_sdu_required_bytes(drb_pending_bytes + RLC_HEADER_SIZE_ESTIMATE)); + } + } } // rb_ratio_slice_scheduler_test @@ -276,7 +290,7 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test TEST_F(rb_ratio_slice_scheduler_test, when_slice_with_min_rb_has_ues_then_it_is_the_first_candidate) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -290,7 +304,7 @@ TEST_F(rb_ratio_slice_scheduler_test, when_slice_with_min_rb_has_ues_then_it_is_ TEST_F(rb_ratio_slice_scheduler_test, when_slice_rb_ratios_are_min_bounded_then_remaining_rbs_is_min_bounded) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -306,7 +320,7 @@ TEST_F(rb_ratio_slice_scheduler_test, when_slice_with_min_rb_is_partially_scheduled_then_it_is_never_a_candidate_again_for_the_same_slot) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -326,7 +340,7 @@ TEST_F(rb_ratio_slice_scheduler_test, when_slice_with_min_rb_is_allocated_until_min_rb_then_it_can_still_a_candidate_until_max_rb_is_reached) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -351,7 +365,7 @@ TEST_F(rb_ratio_slice_scheduler_test, when_candidates_are_scheduled_in_a_slot_then_priorities_are_recomputed_in_a_new_slot) { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -365,7 +379,7 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_FALSE(next_dl_slice.has_value()); // New slot and priorities are reestablished. - slice_sched.slot_indication(); + slice_sched.slot_indication(current_slot); // Default SRB slice has very high priority. next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); @@ -396,7 +410,8 @@ TEST_F(rb_ratio_slice_scheduler_test, unsigned slice_3_count = 0; unsigned slice_2_count = 0; for (unsigned count = 0; count != max_nof_slots; ++count) { - slice_sched.slot_indication(); + ++current_slot; + slice_sched.slot_indication(current_slot); // Either default SRB slice (Slice 0) or DRB1 slice (Slice 2) or DRB2 slice (Slice 3) is selected first since both // have minRBs > 0. @@ -443,13 +458,19 @@ TEST_F(srb_prioritization_slice_scheduler_test, schedules_default_srb_slice_firs { ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); ASSERT_NE(this->add_ue(to_du_ue_index(1)), nullptr); - slice_sched.slot_indication(); - auto next_ul_slice = slice_sched.get_next_ul_candidate(); - ASSERT_TRUE(next_ul_slice.has_value()); - ASSERT_EQ(next_ul_slice->id(), ran_slice_id_t{0}); + for (unsigned count = 0, e = 10; count != e; ++count) { + ++current_slot; + slice_sched.slot_indication(current_slot); - auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_TRUE(next_dl_slice.has_value()); - ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); + auto next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_TRUE(next_dl_slice.has_value()); + ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0}); + + auto next_ul_slice = slice_sched.get_next_ul_candidate(); + if (next_ul_slice.has_value()) { + ASSERT_TRUE(next_ul_slice.has_value()); + ASSERT_EQ(next_ul_slice->id(), ran_slice_id_t{0}); + } + } } From 5600639b5416f375c450133b6f1defd79eae28f3 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 21 Aug 2024 16:09:51 +0200 Subject: [PATCH 376/407] sched: add helper function to fetch the slot to allocated PDSCH/PUSCH in a RAN slice candidate --- lib/scheduler/slicing/ran_slice_candidate.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/scheduler/slicing/ran_slice_candidate.h b/lib/scheduler/slicing/ran_slice_candidate.h index b7bc55b62c..f43e4a66c6 100644 --- a/lib/scheduler/slicing/ran_slice_candidate.h +++ b/lib/scheduler/slicing/ran_slice_candidate.h @@ -55,6 +55,9 @@ class common_ran_slice_candidate : max_rbs - inst->pusch_rb_count_per_slot[slot_tx.to_uint()]; } + /// Returns slot at which PUSCH/PDSCH needs to be scheduled for this slice candidate. + slot_point get_slot_tx() const { return slot_tx; } + protected: ran_slice_instance* inst = nullptr; unsigned max_rbs = 0; From e40603d6df073f683262d5c31d4111acbc12a83c Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 21 Aug 2024 16:12:37 +0200 Subject: [PATCH 377/407] sched: pass to the grid allocater the slot at which PUSCH grant to be allocated --- lib/scheduler/policy/scheduler_time_pf.cpp | 6 ++-- lib/scheduler/policy/scheduler_time_pf.h | 7 +++-- lib/scheduler/policy/scheduler_time_rr.cpp | 33 +++++++++++----------- lib/scheduler/policy/ue_allocator.h | 2 ++ 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index f485b30f89..7a64c2dd7b 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -94,7 +94,7 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, while (not ul_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *ul_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs); + alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs, slice_candidate.get_slot_tx()); } ue.save_ul_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -143,10 +143,12 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, - unsigned max_rbs) + unsigned max_rbs, + slot_point pusch_slot) { alloc_result alloc_result = {alloc_status::invalid_params}; ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; + grant.pusch_slot = pusch_slot; // Prioritize reTx over newTx. if (ctxt.ul_retx_h != nullptr) { grant.h_id = ctxt.ul_retx_h->id; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index c2ddd50fdb..073efde3d3 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -83,8 +83,11 @@ class scheduler_time_pf : public scheduler_policy try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, unsigned max_rbs); /// \brief Attempts to allocate PUSCH for a UE. /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. - alloc_result - try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, unsigned max_rbs); + alloc_result try_ul_alloc(ue_ctxt& ctxt, + const slice_ue_repository& ues, + ue_pusch_allocator& pusch_alloc, + unsigned max_rbs, + slot_point pusch_slot); slotted_id_table ue_history_db; diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 8ec6975dda..56f2bbd36e 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -329,6 +329,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, bool schedule_sr_only, srslog::basic_logger& logger, ran_slice_id_t slice_id, + slot_point pusch_slot, std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) { unsigned pending_newtx_bytes = 0; @@ -358,7 +359,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, // Iterate through allocation parameter candidates. for (const ul_harq_process* h_ul : harq_candidates) { - ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id}; + ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id, pusch_slot}; if (not is_retx) { grant.recommended_nof_bytes = pending_newtx_bytes; grant.max_nof_rbs = ul_new_tx_max_nof_rbs_per_ue_per_slot; @@ -416,9 +417,6 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, }; result = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); next_dl_ue_index = result.first; - if (result.second == alloc_status::skip_slot) { - return; - } } } @@ -426,9 +424,10 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, ul_ran_slice_candidate& slice_candidate) { - const slice_ue_repository& ues = slice_candidate.get_slice_ues(); - const unsigned max_rbs = slice_candidate.remaining_rbs(); - const ran_slice_id_t slice_id = slice_candidate.id(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); + const unsigned max_rbs = slice_candidate.remaining_rbs(); + const ran_slice_id_t slice_id = slice_candidate.id(); + const slot_point pusch_slot = slice_candidate.get_slot_tx(); if (ues.empty() or max_rbs == 0) { // No UEs to be scheduled or if there are no RBs to be scheduled in slice. @@ -439,9 +438,11 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. - auto sr_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, false, true, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); - }; + auto sr_ue_function = + [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id, pusch_slot](const slice_ue& u) { + return alloc_ul_ue( + u, pusch_alloc, false, true, logger, slice_id, pusch_slot, ul_new_tx_max_nof_rbs_per_ue_per_slot); + }; auto result = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); next_ul_ue_index = result.first; if (result.second == alloc_status::skip_slot) { @@ -449,8 +450,8 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, } // Second, schedule UEs with re-transmissions. - auto data_retx_ue_function = [this, &pusch_alloc, slice_id](const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, true, false, logger, slice_id); + auto data_retx_ue_function = [this, &pusch_alloc, slice_id, pusch_slot](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, true, false, logger, slice_id, pusch_slot); }; result = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); next_ul_ue_index = result.first; @@ -461,13 +462,11 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, // Then, schedule UEs with new transmissions. if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { auto data_tx_ue_function = - [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, false, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); + [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id, pusch_slot](const slice_ue& u) { + return alloc_ul_ue( + u, pusch_alloc, false, false, logger, slice_id, pusch_slot, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; result = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); next_ul_ue_index = result.first; - if (result.second == alloc_status::skip_slot) { - return; - } } } diff --git a/lib/scheduler/policy/ue_allocator.h b/lib/scheduler/policy/ue_allocator.h index 77de875655..072f4e8941 100644 --- a/lib/scheduler/policy/ue_allocator.h +++ b/lib/scheduler/policy/ue_allocator.h @@ -35,6 +35,8 @@ struct ue_pusch_grant { const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; + /// Slot at which PUSCH grant needs to be allocated. + slot_point pusch_slot; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. std::optional recommended_nof_bytes; /// Maximum nof. RBs to allocate to the UE. This field is not present/ignored in case of HARQ retransmission. From 8e6ebd884120dd167b450b69c39fe4e421c4b55d Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 22 Aug 2024 17:57:27 +0200 Subject: [PATCH 378/407] sched: fix computation RB limits for slice candidate --- lib/scheduler/slicing/slice_scheduler.cpp | 38 +++++++++++-------- lib/scheduler/slicing/slice_scheduler.h | 3 +- .../slicing/slice_scheduler_test.cpp | 4 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 6367fc9003..bd300d3f7b 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -65,15 +65,15 @@ void slice_scheduler::slot_indication(slot_point slot_tx) slice.inst.slot_indication(slot_tx); } - // TODO: Update slices (store_grant()) with already allocated grant in the previous slots. - // Recompute the priority queues. dl_prio_queue.clear(); ul_prio_queue.clear(); for (const auto& slice : slices) { - unsigned max_rbs = slice.inst.cfg.min_prb > 0 ? slice.inst.cfg.min_prb : slice.inst.cfg.max_prb; + unsigned max_rbs = slice.inst.pdsch_rb_count <= slice.inst.cfg.min_prb and slice.inst.cfg.min_prb > 0 + ? slice.inst.cfg.min_prb + : slice.inst.cfg.max_prb; dl_prio_queue.push(slice_candidate_context{ - slice.inst.id, slice.get_prio(true, slot_count, false, slot_tx), {0, max_rbs}, slot_tx}); + slice.inst.id, slice.get_prio(true, slot_count, slot_tx), {slice.inst.pdsch_rb_count, max_rbs}, slot_tx}); // TODO: Revisit when PUSCH time domain resource list is also defined in UE dedicated configuration. span pusch_time_domain_list = @@ -81,8 +81,14 @@ void slice_scheduler::slot_indication(slot_point slot_tx) for (const unsigned pusch_td_res_idx : valid_pusch_td_list_per_slot[slot_tx.to_uint() % valid_pusch_td_list_per_slot.size()]) { slot_point pusch_slot = slot_tx + pusch_time_domain_list[pusch_td_res_idx].k2; - ul_prio_queue.push(slice_candidate_context{ - slice.inst.id, slice.get_prio(false, slot_count, false, pusch_slot), {0, max_rbs}, pusch_slot}); + max_rbs = slice.inst.pusch_rb_count_per_slot[pusch_slot.to_uint()] <= slice.inst.cfg.min_prb and + slice.inst.cfg.min_prb > 0 + ? slice.inst.cfg.min_prb + : slice.inst.cfg.max_prb; + ul_prio_queue.push(slice_candidate_context{slice.inst.id, + slice.get_prio(false, slot_count, pusch_slot), + {slice.inst.pusch_rb_count_per_slot[pusch_slot.to_uint()], max_rbs}, + pusch_slot}); } } } @@ -222,17 +228,18 @@ slice_scheduler::get_next_candidate() if (not rb_lims.contains(rb_count)) { // The slice has been scheduled in this slot with a number of RBs that is not within the limits for this // candidate. This could happen, for instance, if the scheduler could not schedule all RBs of a candidate - // bounded between {0, minRB}. In this case, the second candidate for the same slice with bounds {minRB, maxRB} - // is skipped. + // bounded between {RBLimsMin, RBLimsMax}. In this case, the second candidate for the same slice with bounds + // {RBLimsMax, maxRB} is skipped. continue; } const slice_rrm_policy_config& cfg = chosen_slice.inst.cfg; - if (cfg.min_prb != cfg.max_prb and rb_lims.stop() == cfg.min_prb) { - // For the special case when minRB ratio>0, the first candidate for this slice was bounded between {0, minRB}. - // We re-add the slice as a candidate, this time, with RB bounds {minRB, maxRB}. - priority_type prio = chosen_slice.get_prio(IsDownlink, slot_count, true, slot_tx); - prio_queue.push(slice_candidate_context{chosen_slice.inst.id, prio, {cfg.min_prb, cfg.max_prb}, slot_tx}); + if (cfg.min_prb > 0 and cfg.min_prb != cfg.max_prb and rb_lims.stop() >= cfg.min_prb) { + // For the special case when minRB ratio>0, the first candidate for this slice was bounded between {RBLimsMin, + // RBLimsMax}. We re-add the slice as a candidate, this time, with RB bounds {RBLimsMax, maxRB}. + priority_type prio = chosen_slice.get_prio(IsDownlink, slot_count, slot_tx); + unsigned min_rbs = rb_count > 0 ? rb_count : cfg.min_prb; + prio_queue.push(slice_candidate_context{chosen_slice.inst.id, prio, {min_rbs, cfg.max_prb}, slot_tx}); } // Save current slot count. @@ -258,7 +265,6 @@ std::optional slice_scheduler::get_next_ul_candidate() slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_prio(bool is_dl, slot_count_type current_slot_count, - bool slice_resched, slot_point slot_tx) const { // Note: The positive integer representing the priority of a slice consists of a concatenation of three priority @@ -282,8 +288,8 @@ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_pri return skip_prio; } - // In case minRB > 0 and this is the first time the slice is proposed as a candidate, we give it a higher priority. - priority_type slice_prio = inst.cfg.min_prb > 0 and not slice_resched ? high_prio : default_prio; + // In case minRB > 0 and minimum RB ratio agreement is not yet reached, we give it a higher priority. + priority_type slice_prio = inst.cfg.min_prb > 0 and rb_count < inst.cfg.min_prb ? high_prio : default_prio; // Increase priorities of slices that have not been scheduled for a long time. unsigned last_count = is_dl ? last_dl_slot : last_ul_slot; diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index 84a3c0a3a0..dee7595280 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -66,8 +66,7 @@ class slice_scheduler } /// Determines the slice candidate priority. - priority_type - get_prio(bool is_dl, slot_count_type current_slot_count, bool slice_resched, slot_point slot_tx) const; + priority_type get_prio(bool is_dl, slot_count_type current_slot_count, slot_point slot_tx) const; }; struct slice_candidate_context { diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index fbf799fb46..953b64b238 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -355,6 +355,7 @@ TEST_F(rb_ratio_slice_scheduler_test, // 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); + next_dl_slice->store_grant(MAX_SLICE_RB - MIN_SLICE_RB); // No more slices to schedule. next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -374,7 +375,7 @@ TEST_F(rb_ratio_slice_scheduler_test, next_dl_slice = slice_sched.get_next_dl_candidate(); next_dl_slice->store_grant(MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); - next_dl_slice = slice_sched.get_next_dl_candidate(); + next_dl_slice->store_grant(MAX_SLICE_RB - MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); @@ -390,6 +391,7 @@ TEST_F(rb_ratio_slice_scheduler_test, 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->store_grant(MAX_SLICE_RB - MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); } From 8651df530a8b4a5e16795ae12ed562c03a8613c9 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 23 Aug 2024 14:38:13 +0200 Subject: [PATCH 379/407] sched: allocate PUSCH only in cell grid allocator at the slot give in PUSCH grant --- .../ue_scheduling/ue_cell_grid_allocator.cpp | 34 ++++++---------- .../ue_pusch_alloc_param_candidate_searcher.h | 15 ++++--- .../ue_scheduling/ue_grid_allocator_test.cpp | 40 +++++++++++++++---- ...ch_alloc_param_candidate_searcher_test.cpp | 18 +++++++-- 4 files changed, 68 insertions(+), 39 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 2ef9e2dfda..b8bff6620a 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -554,9 +554,11 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra return {alloc_status::invalid_params}; } + slot_point pusch_slot = grant.pusch_slot; + // Create PUSCH param candidate search object. ue_pusch_alloc_param_candidate_searcher candidates{ - u, grant.cell_index, h_ul, pdcch_alloc.slot, slots_with_no_pusch_space}; + u, grant.cell_index, h_ul, pdcch_alloc.slot, slots_with_no_pusch_space, pusch_slot}; if (candidates.is_empty()) { // The conditions for a new PUSCH allocation for this UE were not met (e.g. lack of available SearchSpaces). return {alloc_status::skip_ue}; @@ -582,8 +584,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra // transmission starting in symbol j by a PDCCH ending in symbol i, the UE is not expected to be scheduled to // transmit a PUSCH starting earlier than the end of the first PUSCH by a PDCCH that ends later than symbol i". if (ue_cc->last_pusch_allocated_slot.valid() and pusch_alloc.slot <= ue_cc->last_pusch_allocated_slot) { - // Try next candidate. - continue; + return {alloc_status::skip_ue}; } // Check if there is space in PUSCH resource grid. @@ -591,8 +592,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra std::find(slots_with_no_pusch_space.begin(), slots_with_no_pusch_space.end(), pusch_alloc.slot) != slots_with_no_pusch_space.end(); if (is_pusch_full) { - // Try next candidate. - continue; + return {alloc_status::skip_slot}; } if (not cell_cfg.is_ul_enabled(pusch_alloc.slot)) { @@ -602,8 +602,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra u.crnti, pusch_alloc.slot, final_k2); - // Try next candidate. - continue; + return {alloc_status::skip_slot}; } // When checking the number of remaining grants for PUSCH, take into account that the PUCCH grants for this UE will @@ -625,8 +624,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra pusch_alloc.slot, expert_cfg.max_puschs_per_slot); } - // Try next candidate. - continue; + return {alloc_status::skip_slot}; } // [Implementation-defined] We skip allocation of PUSCH if there is already a PUCCH grant scheduled using common @@ -637,8 +635,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra u.ue_index, u.crnti, pusch_alloc.slot); - // Try next candidate. - continue; + return {alloc_status::skip_ue}; } const unsigned start_ul_symbols = @@ -664,16 +661,14 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra pusch_alloc.slot, start_rb, end_rb); - // Try next candidate. - continue; + return {alloc_status::skip_slot}; } const crb_interval ul_crb_lims = {start_rb, end_rb}; const prb_bitmap used_crbs = pusch_alloc.ul_res_grid.used_crbs(scs, ul_crb_lims, pusch_td_cfg.symbols); if (used_crbs.all()) { slots_with_no_pusch_space.push_back(pusch_alloc.slot); - // Try next candidate. - continue; + return {alloc_status::skip_slot}; } // Compute the MCS and the number of PRBs, depending on the pending bytes to transmit. @@ -733,8 +728,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra u.ue_index, u.crnti, pusch_alloc.slot); - // Try next candidate. - continue; + return {alloc_status::skip_slot}; } // In case of Retx, the #CRBs need to stay the same. @@ -745,8 +739,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra u.crnti, pusch_alloc.slot, h_ul.id); - // Try next candidate. - continue; + return {alloc_status::skip_ue}; } // Verify there is no RB collision. @@ -758,8 +751,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra pusch_alloc.slot, crbs.start(), crbs.stop()); - // Try next candidate. - continue; + return {alloc_status::invalid_params}; } const aggregation_level aggr_lvl = diff --git a/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h b/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h index 1a6af2500b..ec690bc901 100644 --- a/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h +++ b/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h @@ -157,13 +157,15 @@ class ue_pusch_alloc_param_candidate_searcher du_cell_index_t cell_index, ul_harq_process& ul_harq_, slot_point pdcch_slot_, - span slots_with_no_pusch_space_) : + span slots_with_no_pusch_space_, + slot_point pusch_slot_) : ue_ref(ue_ref_), ue_cc(ue_ref.find_cell(cell_index)), slots_with_no_pusch_space(slots_with_no_pusch_space_), ul_harq(ul_harq_), is_retx(not ul_harq.empty()), - pdcch_slot(pdcch_slot_) + pdcch_slot(pdcch_slot_), + pusch_slot(pusch_slot_) { // Cell is not part of UE configured cells. if (ue_cc == nullptr) { @@ -233,12 +235,11 @@ class ue_pusch_alloc_param_candidate_searcher } // Check whether PUSCH Time Domain resource index is valid. - if (current.time_res >= (*current.ss_it)->pusch_time_domain_list.size()) { + if ((current.time_res >= (*current.ss_it)->pusch_time_domain_list.size()) or + (pdcch_slot + current.pusch_td_res().k2 != pusch_slot)) { return false; } - const slot_point pusch_slot = pdcch_slot + current.pusch_td_res().k2; - // Check whether PUSCH slot is UL enabled. if (not ue_cc->cfg().cell_cfg_common.is_ul_enabled(pusch_slot)) { return false; @@ -310,8 +311,10 @@ class ue_pusch_alloc_param_candidate_searcher // RNTI type used to generate ss_candidate_list. std::optional preferred_rnti_type; - // PDCCH slot point used to verify if the PUSCH fits a UL slot. + // Slot at which UL PDCCH is scheduled if valid PUSCH allocation candidate is found. slot_point pdcch_slot; + // Slot at which PUSCH needs to be scheduled. + slot_point pusch_slot; }; } // namespace srsran diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index d658c59cee..a74fe9dbb4 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -56,6 +56,15 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam alloc.add_cell(to_du_cell_index(0), pdcch_alloc, uci_alloc, res_grid); } + slot_point get_next_ul_slot(const slot_point starting_slot) const + { + slot_point next_slot = starting_slot + cfg_builder_params.min_k2; + while (not cell_cfg.is_fully_ul_enabled(next_slot)) { + ++next_slot; + } + return next_slot; + } + void run_slot() { ++current_slot; @@ -232,6 +241,7 @@ TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_n const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -255,6 +265,7 @@ TEST_P(ue_grid_allocator_tester, does_not_allocate_pusch_with_all_remaining_rbs_ const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = u1.pending_ul_newtx_bytes()}; const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), @@ -307,16 +318,20 @@ TEST_P(ue_grid_allocator_tester, no_two_puschs_are_allocated_in_same_slot_for_a_ const ue& u = add_ue(ue_creation_req); + slot_point pusch_slot = get_next_ul_slot(current_slot); + // First PUSCH grant for the UE. const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = pusch_slot, .recommended_nof_bytes = nof_bytes_to_schedule}; // Second PUSCH grant for the UE. const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), + .pusch_slot = pusch_slot, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { @@ -338,29 +353,30 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in const ue& u = add_ue(ue_creation_req); + slot_point pusch_slot = get_next_ul_slot(current_slot); + // First PUSCH grant for the UE. const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = pusch_slot, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); - slot_point last_pusch_alloc_slot = current_slot; run_slot(); - // Second PUSCH grant for the UE. + // Second PUSCH grant for the UE trying to allocate PUSCH in a slot previous to grant1. const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), + .pusch_slot = pusch_slot - 1, .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE( + ASSERT_FALSE( run_until([&]() { return alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; })); - ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); - ASSERT_GT(current_slot, last_pusch_alloc_slot); } TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_increasing_order_of_time) @@ -493,6 +509,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -509,6 +526,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -588,15 +606,18 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_ul_rbs_are_alloca const unsigned recommended_nof_bytes_to_schedule = 200U; - const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), - cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; + const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), + cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; + slot_point pusch_to_alloc_slot = get_next_ul_slot(current_slot); const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = pusch_to_alloc_slot, .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; const ue_pusch_grant grant2{.user = &slice_ues[u2.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = pusch_to_alloc_slot, .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { @@ -700,6 +721,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -727,6 +749,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -787,7 +810,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1(), pdsch_vrb_limits); } -TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_within_expert_cfg_pusch_rb_limits) +TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pusch_within_expert_cfg_pusch_rb_limits) { sched_ue_creation_request_message ue_creation_req = test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); @@ -802,6 +825,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), + .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp index 8365880c49..6bee2c2e23 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp @@ -44,6 +44,15 @@ class ue_pxsch_alloc_param_candidate_searcher_test : public ::testing::Test ue_cc = &ue_ptr->get_cell(to_ue_cell_index(0)); } + slot_point get_next_ul_slot(slot_point start_slot) + { + slot_point next_ul_slot = start_slot + sched_cfg.ue.min_k1; + while (not cell_cfg.is_fully_ul_enabled(next_ul_slot)) { + ++next_ul_slot; + } + return next_ul_slot; + } + void run_slot() { next_slot++; } const scheduler_expert_config sched_cfg = config_helpers::make_default_scheduler_expert_config(); @@ -63,11 +72,12 @@ class ue_pxsch_alloc_param_candidate_searcher_test : public ::testing::Test TEST_F(ue_pxsch_alloc_param_candidate_searcher_test, only_searchspaces_in_ue_dedicated_cfg_is_considered) { - const harq_id_t h_id = to_harq_id(0); + const harq_id_t h_id = to_harq_id(0); + const slot_point pdcch_slot{0, 0}; span ss_list = ue_cc->cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces; ue_pdsch_alloc_param_candidate_searcher dl_searcher( - *ue_ptr, to_du_cell_index(0), ue_cc->harqs.dl_harq(h_id), slot_point{0, 0}, {}); + *ue_ptr, to_du_cell_index(0), ue_cc->harqs.dl_harq(h_id), pdcch_slot, {}); ASSERT_TRUE(not dl_searcher.is_empty()); for (const auto& candidate : dl_searcher) { bool ss_present_in_ue_ded_cfg = @@ -77,8 +87,8 @@ TEST_F(ue_pxsch_alloc_param_candidate_searcher_test, only_searchspaces_in_ue_ded ASSERT_TRUE(ss_present_in_ue_ded_cfg); } ue_pusch_alloc_param_candidate_searcher ul_searcher( - *ue_ptr, to_du_cell_index(0), ue_cc->harqs.ul_harq(h_id), slot_point{0, 0}, {}); - ASSERT_TRUE(not dl_searcher.is_empty()); + *ue_ptr, to_du_cell_index(0), ue_cc->harqs.ul_harq(h_id), pdcch_slot, {}, get_next_ul_slot(pdcch_slot)); + ASSERT_TRUE(not ul_searcher.is_empty()); for (const auto& candidate : ul_searcher) { bool ss_present_in_ue_ded_cfg = std::find_if(ss_list.begin(), ss_list.end(), [&candidate](const search_space_configuration& ss_cfg) { From 537ff5776e5017352541001b69a66a64e1ad1696 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 23 Aug 2024 14:40:28 +0200 Subject: [PATCH 380/407] unittest: add test to verify generation of UE PUSCH alloc param candidates only for a given PUSCH slot --- ...e_pxsch_alloc_param_candidate_searcher_test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp index 6bee2c2e23..ed48c2f7a5 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp @@ -97,3 +97,17 @@ TEST_F(ue_pxsch_alloc_param_candidate_searcher_test, only_searchspaces_in_ue_ded ASSERT_TRUE(ss_present_in_ue_ded_cfg); } } + +TEST_F(ue_pxsch_alloc_param_candidate_searcher_test, only_candidates_for_given_pusch_slot_is_returned) +{ + const harq_id_t h_id = to_harq_id(0); + const slot_point pdcch_slot{0, 0}; + const slot_point pusch_slot = get_next_ul_slot(pdcch_slot); + + ue_pusch_alloc_param_candidate_searcher ul_searcher( + *ue_ptr, to_du_cell_index(0), ue_cc->harqs.ul_harq(h_id), pdcch_slot, {}, pusch_slot); + ASSERT_TRUE(not ul_searcher.is_empty()); + for (const auto& candidate : ul_searcher) { + ASSERT_EQ(pdcch_slot + candidate.pusch_td_res().k2, pusch_slot) << "Candidate is not for the given PUSCH slot"; + } +} From fe3204a32fc1f81eece76ead56b01ea36ef633cf Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 26 Aug 2024 11:09:25 +0200 Subject: [PATCH 381/407] sched: refactor passing of slot at which PUSCH needs to be allocated --- lib/scheduler/policy/scheduler_time_pf.cpp | 6 +- lib/scheduler/policy/scheduler_time_pf.h | 7 +- lib/scheduler/policy/scheduler_time_rr.cpp | 27 +++---- lib/scheduler/policy/ue_allocator.h | 2 - .../ue_scheduling/ue_cell_grid_allocator.cpp | 5 +- .../ue_scheduling/ue_cell_grid_allocator.h | 5 +- .../ue_scheduling/ue_grid_allocator_test.cpp | 75 ++++++++++--------- 7 files changed, 59 insertions(+), 68 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index 7a64c2dd7b..f485b30f89 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -94,7 +94,7 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, while (not ul_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *ul_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs, slice_candidate.get_slot_tx()); + alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs); } ue.save_ul_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -143,12 +143,10 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, - unsigned max_rbs, - slot_point pusch_slot) + unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; - grant.pusch_slot = pusch_slot; // Prioritize reTx over newTx. if (ctxt.ul_retx_h != nullptr) { grant.h_id = ctxt.ul_retx_h->id; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index 073efde3d3..c2ddd50fdb 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -83,11 +83,8 @@ class scheduler_time_pf : public scheduler_policy try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, unsigned max_rbs); /// \brief Attempts to allocate PUSCH for a UE. /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. - alloc_result try_ul_alloc(ue_ctxt& ctxt, - const slice_ue_repository& ues, - ue_pusch_allocator& pusch_alloc, - unsigned max_rbs, - slot_point pusch_slot); + alloc_result + try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, unsigned max_rbs); slotted_id_table ue_history_db; diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 56f2bbd36e..7cc0762731 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -329,7 +329,6 @@ static alloc_result alloc_ul_ue(const slice_ue& u, bool schedule_sr_only, srslog::basic_logger& logger, ran_slice_id_t slice_id, - slot_point pusch_slot, std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) { unsigned pending_newtx_bytes = 0; @@ -359,7 +358,7 @@ static alloc_result alloc_ul_ue(const slice_ue& u, // Iterate through allocation parameter candidates. for (const ul_harq_process* h_ul : harq_candidates) { - ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id, pusch_slot}; + ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id}; if (not is_retx) { grant.recommended_nof_bytes = pending_newtx_bytes; grant.max_nof_rbs = ul_new_tx_max_nof_rbs_per_ue_per_slot; @@ -424,10 +423,9 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, ul_ran_slice_candidate& slice_candidate) { - const slice_ue_repository& ues = slice_candidate.get_slice_ues(); - const unsigned max_rbs = slice_candidate.remaining_rbs(); - const ran_slice_id_t slice_id = slice_candidate.id(); - const slot_point pusch_slot = slice_candidate.get_slot_tx(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); + const unsigned max_rbs = slice_candidate.remaining_rbs(); + const ran_slice_id_t slice_id = slice_candidate.id(); if (ues.empty() or max_rbs == 0) { // No UEs to be scheduled or if there are no RBs to be scheduled in slice. @@ -438,11 +436,9 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. - auto sr_ue_function = - [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id, pusch_slot](const slice_ue& u) { - return alloc_ul_ue( - u, pusch_alloc, false, true, logger, slice_id, pusch_slot, ul_new_tx_max_nof_rbs_per_ue_per_slot); - }; + auto sr_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, false, true, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); + }; auto result = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); next_ul_ue_index = result.first; if (result.second == alloc_status::skip_slot) { @@ -450,8 +446,8 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, } // Second, schedule UEs with re-transmissions. - auto data_retx_ue_function = [this, &pusch_alloc, slice_id, pusch_slot](const slice_ue& u) { - return alloc_ul_ue(u, pusch_alloc, true, false, logger, slice_id, pusch_slot); + auto data_retx_ue_function = [this, &pusch_alloc, slice_id](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, true, false, logger, slice_id); }; result = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function); next_ul_ue_index = result.first; @@ -462,9 +458,8 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, // Then, schedule UEs with new transmissions. if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { auto data_tx_ue_function = - [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id, pusch_slot](const slice_ue& u) { - return alloc_ul_ue( - u, pusch_alloc, false, false, logger, slice_id, pusch_slot, ul_new_tx_max_nof_rbs_per_ue_per_slot); + [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot, slice_id](const slice_ue& u) { + return alloc_ul_ue(u, pusch_alloc, false, false, logger, slice_id, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; result = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); next_ul_ue_index = result.first; diff --git a/lib/scheduler/policy/ue_allocator.h b/lib/scheduler/policy/ue_allocator.h index 072f4e8941..77de875655 100644 --- a/lib/scheduler/policy/ue_allocator.h +++ b/lib/scheduler/policy/ue_allocator.h @@ -35,8 +35,6 @@ struct ue_pusch_grant { const slice_ue* user; du_cell_index_t cell_index; harq_id_t h_id; - /// Slot at which PUSCH grant needs to be allocated. - slot_point pusch_slot; /// Recommended nof. bytes to schedule. This field is not present/ignored in case of HARQ retransmission. std::optional recommended_nof_bytes; /// Maximum nof. RBs to allocate to the UE. This field is not present/ignored in case of HARQ retransmission. diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index b8bff6620a..28a9730e05 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -483,7 +483,8 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra return {alloc_status::invalid_params}; } -alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice_id_t slice_id) +alloc_result +ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice_id_t slice_id, slot_point pusch_slot) { srsran_assert(ues.contains(grant.user->ue_index()), "Invalid UE candidate index={}", grant.user->ue_index()); srsran_assert(has_cell(grant.cell_index), "Invalid UE candidate cell_index={}", grant.cell_index); @@ -554,8 +555,6 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra return {alloc_status::invalid_params}; } - slot_point pusch_slot = grant.pusch_slot; - // Create PUSCH param candidate search object. ue_pusch_alloc_param_candidate_searcher candidates{ u, grant.cell_index, h_ul, pdcch_alloc.slot, slots_with_no_pusch_space, pusch_slot}; diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h index 8c53424e62..c46ceba5c1 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h @@ -40,7 +40,7 @@ class ue_cell_grid_allocator alloc_result allocate_dl_grant(const ue_pdsch_grant& grant, ran_slice_id_t slice_id); - alloc_result allocate_ul_grant(const ue_pusch_grant& grant, ran_slice_id_t slice_id); + alloc_result allocate_ul_grant(const ue_pusch_grant& grant, ran_slice_id_t slice_id, slot_point pusch_slot); private: struct cell_t { @@ -114,7 +114,8 @@ class ul_slice_ue_cell_grid_allocator : public ue_pusch_allocator alloc_result allocate_ul_grant(const ue_pusch_grant& grant) override { - const alloc_result result = pusch_alloc.allocate_ul_grant(grant, slice_candidate.id()); + const alloc_result result = + pusch_alloc.allocate_ul_grant(grant, slice_candidate.id(), slice_candidate.get_slot_tx()); if (result.status == alloc_status::success) { slice_candidate.store_grant(result.alloc_nof_rbs); } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index a74fe9dbb4..26a0f62236 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -241,12 +241,13 @@ TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_n const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH corresponding to the grant. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), grant1.max_nof_rbs); @@ -265,14 +266,15 @@ TEST_P(ue_grid_allocator_tester, does_not_allocate_pusch_with_all_remaining_rbs_ const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = u1.pending_ul_newtx_bytes()}; const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH corresponding to the grant. ASSERT_LT(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), cell_crbs.length()); @@ -324,19 +326,17 @@ TEST_P(ue_grid_allocator_tester, no_two_puschs_are_allocated_in_same_slot_for_a_ const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = pusch_slot, .recommended_nof_bytes = nof_bytes_to_schedule}; // Second PUSCH grant for the UE. const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), - .pusch_slot = pusch_slot, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { - return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success or - alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; + return alloc.allocate_ul_grant(grant1, dummy_slice_id, pusch_slot).status == alloc_status::success or + alloc.allocate_ul_grant(grant2, dummy_slice_id, pusch_slot).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); @@ -359,11 +359,10 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = pusch_slot, .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until( + [&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id, pusch_slot).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u.crnti, res_grid[0].result.ul) != nullptr; })); run_slot(); @@ -372,11 +371,11 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), - .pusch_slot = pusch_slot - 1, .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_FALSE( - run_until([&]() { return alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; })); + ASSERT_FALSE(run_until([&]() { + return alloc.allocate_ul_grant(grant2, dummy_slice_id, pusch_slot - 1).status == alloc_status::success; + })); } TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_increasing_order_of_time) @@ -509,11 +508,12 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + })); // Ensure next PUSCH to be allocated slot is after wrap around of 1024 SFNs (large gap to last allocated PUSCH slot) // and current slot value is less than last allocated PUSCH slot. e.g. next PUSCH to be allocated slot=SFN 2, slot 2 @@ -526,12 +526,14 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(1), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = nof_bytes_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; }, - nof_slot_until_pusch_is_allocated_threshold)); + ASSERT_TRUE(run_until( + [&]() { + return alloc.allocate_ul_grant(grant2, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + }, + nof_slot_until_pusch_is_allocated_threshold)); } class ue_grid_allocator_remaining_rbs_alloc_tester : public ue_grid_allocator_tester @@ -612,17 +614,15 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_ul_rbs_are_alloca const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = pusch_to_alloc_slot, .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; const ue_pusch_grant grant2{.user = &slice_ues[u2.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = pusch_to_alloc_slot, .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { - return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success and - alloc.allocate_ul_grant(grant2, dummy_slice_id).status == alloc_status::success; + return alloc.allocate_ul_grant(grant1, dummy_slice_id, pusch_to_alloc_slot).status == alloc_status::success and + alloc.allocate_ul_grant(grant2, dummy_slice_id, pusch_to_alloc_slot).status == alloc_status::success; })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr and find_ue_pusch(u2.crnti, res_grid[0].result.ul); @@ -721,12 +721,13 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), @@ -749,12 +750,13 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), @@ -825,12 +827,13 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pusch_wit const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), - .pusch_slot = get_next_ul_slot(current_slot), .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; - ASSERT_TRUE( - run_until([&]() { return alloc.allocate_ul_grant(grant1, dummy_slice_id).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1, dummy_slice_id, get_next_ul_slot(current_slot)).status == + alloc_status::success; + })); ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); // Successfully allocates PUSCH within RB limits. ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1(), pusch_vrb_limits); From 990e5e387d3b16438467df24168f43662474cd8d Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 26 Aug 2024 14:38:05 +0200 Subject: [PATCH 382/407] sched,du_mgr: store list of k1 candidates in cell configuration --- include/srsran/scheduler/scheduler_configurator.h | 3 +++ .../converters/scheduler_configuration_helpers.cpp | 5 +++++ lib/scheduler/config/cell_configuration.cpp | 1 + lib/scheduler/config/cell_configuration.h | 3 +++ tests/unittests/scheduler/test_utils/config_generators.h | 7 +++++++ 5 files changed, 19 insertions(+) diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index b459d004d9..c7f674b15d 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -92,6 +92,9 @@ struct sched_cell_configuration_request_message { /// List of nzp-CSI-RS resources common to all UEs. std::vector nzp_csi_rs_res_list; + /// List of dl-DataToUL-ACK values sent to UE in its dedicated configuration. + static_vector dl_data_to_ul_ack; + /// List of RAN slices to support in the scheduler. std::vector rrm_policy_members; diff --git a/lib/du_manager/converters/scheduler_configuration_helpers.cpp b/lib/du_manager/converters/scheduler_configuration_helpers.cpp index f7adff134c..0d593c1c61 100644 --- a/lib/du_manager/converters/scheduler_configuration_helpers.cpp +++ b/lib/du_manager/converters/scheduler_configuration_helpers.cpp @@ -70,6 +70,11 @@ srsran::srs_du::make_sched_cell_config_req(du_cell_index_t cell_index, sched_req.nzp_csi_rs_res_list = du_cfg.ue_ded_serv_cell_cfg.csi_meas_cfg->nzp_csi_rs_res_list; } + if (du_cfg.ue_ded_serv_cell_cfg.ul_config.has_value() and + du_cfg.ue_ded_serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.has_value()) { + sched_req.dl_data_to_ul_ack = du_cfg.ue_ded_serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg->dl_data_to_ul_ack; + } + sched_req.rrm_policy_members = du_cfg.rrm_policy_members; return sched_req; diff --git a/lib/scheduler/config/cell_configuration.cpp b/lib/scheduler/config/cell_configuration.cpp index 59abcda1de..e5a6d687cb 100644 --- a/lib/scheduler/config/cell_configuration.cpp +++ b/lib/scheduler/config/cell_configuration.cpp @@ -36,6 +36,7 @@ cell_configuration::cell_configuration(const scheduler_expert_config& pucch_guardbands(msg.pucch_guardbands), zp_csi_rs_list(msg.zp_csi_rs_list), nzp_csi_rs_list(msg.nzp_csi_rs_res_list), + dl_data_to_ul_ack(msg.dl_data_to_ul_ack), rrm_policy_members(msg.rrm_policy_members), // SSB derived params. ssb_case(band_helper::get_ssb_pattern(msg.dl_carrier.band, msg.ssb_config.scs)), diff --git a/lib/scheduler/config/cell_configuration.h b/lib/scheduler/config/cell_configuration.h index c96b1544cf..aabc61789b 100644 --- a/lib/scheduler/config/cell_configuration.h +++ b/lib/scheduler/config/cell_configuration.h @@ -55,6 +55,9 @@ class cell_configuration /// List of nzp-CSI-RS resources. std::vector nzp_csi_rs_list; + /// List of dl-DataToUL-ACK values sent to UE in its dedicated configuration. + static_vector dl_data_to_ul_ack; + /// List of RRM Policy members configured for this cell. std::vector rrm_policy_members; diff --git a/tests/unittests/scheduler/test_utils/config_generators.h b/tests/unittests/scheduler/test_utils/config_generators.h index c2e7a2b53d..4bf139d54c 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.h +++ b/tests/unittests/scheduler/test_utils/config_generators.h @@ -68,6 +68,13 @@ make_default_sched_cell_configuration_request(const config_helpers::cell_config_ sched_req.nzp_csi_rs_res_list = csi_meas.nzp_csi_rs_res_list; } + if (sched_req.tdd_ul_dl_cfg_common.has_value()) { + sched_req.dl_data_to_ul_ack = + config_helpers::generate_k1_candidates(*sched_req.tdd_ul_dl_cfg_common, params.min_k1); + } else { + sched_req.dl_data_to_ul_ack = {params.min_k1}; + } + return sched_req; } From 1c032a30547ac97b54213ccdf682b380508ca713 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 26 Aug 2024 14:52:55 +0200 Subject: [PATCH 383/407] sched: use minimum k1 from the list of k1 candidates in cell configuration to compute PUSCH Time Domain resource index --- .../support/pusch/pusch_td_resource_indices.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp b/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp index 7b814aed2f..394e5b0eed 100644 --- a/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp +++ b/lib/scheduler/support/pusch/pusch_td_resource_indices.cpp @@ -22,12 +22,6 @@ compute_pusch_td_resource_indices(span pusch_td_res_index_list; - if (pusch_time_domain_list.empty()) { - return pusch_td_res_index_list; - } - // [Implementation-defined] Default PUSCH time domain resource index to use if no valid PUSCH time domain resource is - // found. - const unsigned default_pusch_td_res_index = 0; std::optional nof_full_ul_slots = std::nullopt; std::optional nof_full_dl_slots = std::nullopt; @@ -59,10 +53,6 @@ compute_pusch_td_resource_indices(span pusch_time_domain_list = cell_cfg.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().pusch_td_alloc_list; if (ss_info != nullptr) { From 3cb092546255340921b655498f194c424a5a1bbd Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 27 Aug 2024 17:05:51 +0200 Subject: [PATCH 384/407] sched: fix condition to re-add the slice candidate to queue --- lib/scheduler/slicing/slice_scheduler.cpp | 3 ++- tests/unittests/scheduler/slicing/slice_scheduler_test.cpp | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index bd300d3f7b..debcb842cd 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -234,7 +234,8 @@ slice_scheduler::get_next_candidate() } const slice_rrm_policy_config& cfg = chosen_slice.inst.cfg; - if (cfg.min_prb > 0 and cfg.min_prb != cfg.max_prb and rb_lims.stop() >= cfg.min_prb) { + if (cfg.min_prb > 0 and cfg.min_prb != cfg.max_prb and rb_lims.stop() >= cfg.min_prb and + rb_lims.stop() != cfg.max_prb) { // For the special case when minRB ratio>0, the first candidate for this slice was bounded between {RBLimsMin, // RBLimsMax}. We re-add the slice as a candidate, this time, with RB bounds {RBLimsMax, maxRB}. priority_type prio = chosen_slice.get_prio(IsDownlink, slot_count, slot_tx); diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 953b64b238..26125e79da 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -262,6 +262,7 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test constexpr static ran_slice_id_t default_srb_slice_id{0}; constexpr static ran_slice_id_t default_drb_slice_id{1}; constexpr static ran_slice_id_t drb1_slice_id{2}; + constexpr static ran_slice_id_t drb2_slice_id{3}; rb_ratio_slice_scheduler_test() : slice_scheduler_test({{{plmn_identity::test_value(), s_nssai_t{1}}, MIN_SLICE_RB, MAX_SLICE_RB}, @@ -355,7 +356,6 @@ TEST_F(rb_ratio_slice_scheduler_test, // 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); - next_dl_slice->store_grant(MAX_SLICE_RB - MIN_SLICE_RB); // No more slices to schedule. next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -375,7 +375,6 @@ TEST_F(rb_ratio_slice_scheduler_test, next_dl_slice = slice_sched.get_next_dl_candidate(); next_dl_slice->store_grant(MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); - next_dl_slice->store_grant(MAX_SLICE_RB - MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); @@ -391,7 +390,6 @@ TEST_F(rb_ratio_slice_scheduler_test, 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->store_grant(MAX_SLICE_RB - MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); } @@ -399,8 +397,6 @@ TEST_F(rb_ratio_slice_scheduler_test, TEST_F(rb_ratio_slice_scheduler_test, when_slices_are_saturated_then_slices_should_have_equal_opportunity_to_reach_max_rbs) { - constexpr static ran_slice_id_t drb2_slice_id{3}; - std::initializer_list lc_cfgs = { config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB0), config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB1), From 635be41267c884a0bcb17c6cbbc2767bc5db0a2a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 10 May 2024 16:49:10 +0100 Subject: [PATCH 385/407] sched: implementation of a HARQ management system for a cell, which is more computationally efficient --- lib/scheduler/ue_scheduling/CMakeLists.txt | 1 + .../ue_scheduling/cell_harq_manager.cpp | 503 ++++++++++++++++++ .../ue_scheduling/cell_harq_manager.h | 324 +++++++++++ 3 files changed, 828 insertions(+) create mode 100644 lib/scheduler/ue_scheduling/cell_harq_manager.cpp create mode 100644 lib/scheduler/ue_scheduling/cell_harq_manager.h diff --git a/lib/scheduler/ue_scheduling/CMakeLists.txt b/lib/scheduler/ue_scheduling/CMakeLists.txt index e4363997a6..ad638d1ccb 100644 --- a/lib/scheduler/ue_scheduling/CMakeLists.txt +++ b/lib/scheduler/ue_scheduling/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES harq_process.cpp + cell_harq_manager.cpp dl_logical_channel_manager.cpp ul_logical_channel_manager.cpp ta_manager.cpp diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp new file mode 100644 index 0000000000..5f04046b82 --- /dev/null +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -0,0 +1,503 @@ +/* + * + * 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 "cell_harq_manager.h" + +using namespace srsran; +using namespace harq_utils; + +template +cell_harq_repository::cell_harq_repository(unsigned max_ues, + unsigned max_ack_wait_timeout, + harq_timeout_notifier& timeout_notifier_, + srslog::basic_logger& logger_) : + max_ack_wait_in_slots(max_ack_wait_timeout), timeout_notifier(timeout_notifier_), logger(logger_) +{ + harqs.resize(MAX_NOF_HARQS * max_ues); + free_harqs.resize(MAX_NOF_HARQS * max_ues); + for (unsigned i = 0; i != free_harqs.size(); ++i) { + free_harqs[i] = free_harqs.size() - i - 1; + } + + // Reserve space in advance for UEs. + ues.resize(max_ues); + for (unsigned i = 0; i != max_ues; i++) { + ues[i].free_harq_ids.reserve(MAX_NOF_HARQS); + ues[i].harqs.resize(MAX_NOF_HARQS, INVALID_HARQ_REF_INDEX); + } +} + +template +void cell_harq_repository::slot_indication(slot_point sl_tx) +{ + // Handle HARQs that timed out. + auto& harqs_timing_out = harq_timeout_wheel[sl_tx.to_uint() % harq_timeout_wheel.size()]; + for (harq_type& h : harqs_timing_out) { + handle_harq_ack_timeout(h, sl_tx); + } +} + +template +void cell_harq_repository::handle_harq_ack_timeout(harq_type& h, slot_point sl_tx) +{ + srsran_sanity_check(h.status == harq_state_t::waiting_ack, "HARQ process in wrong state"); + + if (max_ack_wait_in_slots != 1) { + // Only in non-NTN case, we log a warning. + if (h.ack_on_timeout) { + // Case: Not all HARQ-ACKs were received, but at least one positive ACK was received. + logger.debug("ue={} h_id={}: Setting {} HARQ to \"ACKed\" state. Cause: HARQ-ACK wait timeout ({} slots) was " + "reached with still missing PUCCH HARQ-ACKs. However, one positive ACK was received.", + h.ue_idx, + h.h_id, + IsDl ? "DL" : "UL", + h.slot_ack_timeout - h.slot_ack); + } else { + // At least one of the expected ACKs went missing and we haven't received any positive ACK. + logger.warning( + "ue={} h_id={}: Discarding {} HARQ. Cause: HARQ-ACK wait timeout ({} slots) was reached, but there are still " + "missing HARQ-ACKs and none of the received ones are positive.", + h.ue_idx, + h.h_id, + IsDl ? "DL" : "UL", + h.slot_ack_timeout - h.slot_ack); + } + + // Report timeout with NACK. + timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, h.ack_on_timeout); + } + + // Deallocate HARQ. + dealloc_harq(h); +} + +template +unsigned cell_harq_repository::get_harq_ref_idx(const harq_type& h) const +{ + return &h - harqs.data(); +} + +template +typename cell_harq_repository::harq_type* cell_harq_repository::alloc_harq(du_ue_index_t ue_idx, + slot_point sl_tx, + slot_point sl_ack, + unsigned max_nof_harq_retxs) +{ + ue_harq_entity_impl& ue_harq_entity = ues[ue_idx]; + if (free_harqs.empty() or ue_harq_entity.free_harq_ids.empty()) { + return nullptr; + } + + // Allocation of free HARQ-id for the UE. + const harq_id_t h_id = ue_harq_entity.free_harq_ids.back(); + ue_harq_entity.free_harq_ids.pop_back(); + + // Allocation of DL HARQ process for the UE. + unsigned harq_ref_idx = free_harqs.back(); + free_harqs.pop_back(); + ue_harq_entity.harqs[h_id] = harq_ref_idx; + harq_type& h = harqs[harq_ref_idx]; + + // Set allocated HARQ common params. + h.ue_idx = ue_idx; + h.h_id = h_id; + h.status = harq_state_t::waiting_ack; + h.slot_tx = sl_tx; + h.slot_ack = sl_ack; + h.nof_retxs = 0; + h.ndi = !h.ndi; + h.max_nof_harq_retxs = max_nof_harq_retxs; + h.ack_on_timeout = false; + h.retxs_cancelled = false; + + // Add HARQ to the timeout list. + h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; + harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); + + return &h; +} + +template +void cell_harq_repository::dealloc_harq(harq_type& h) +{ + if (h.status == harq_state_t::empty) { + // No-op + return; + } + ue_harq_entity_impl& ue_harq_entity = ues[h.ue_idx]; + + // Mark HARQ-Id as available. + ue_harq_entity.harqs[h.h_id] = INVALID_HARQ_REF_INDEX; + ue_harq_entity.free_harq_ids.push_back(h.h_id); + + // Push HARQ resource back to cell free list. + free_harqs.push_back(get_harq_ref_idx(h)); + + if (h.status == harq_state_t::waiting_ack) { + // Remove the HARQ from the timeout list. + harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].pop(&h); + } else { + // Remove the HARQ from the pending Retx list. + harq_pending_retx_list.pop(&h); + } + + // Update HARQ process state. + h.status = harq_state_t::empty; +} + +template +void cell_harq_repository::handle_ack(harq_type& h, bool ack) +{ + if (not ack and h.nof_retxs >= h.max_nof_harq_retxs) { + if (h.retxs_cancelled) { + logger.info( + "ue={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Retxs for this HARQ process were cancelled", + h.ue_idx, + h.h_id, + IsDl ? "DL" : "UL", + h.prev_tx_params.tbs_bytes); + } else { + logger.info( + "ue={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Maximum number of reTxs {} exceeded", + h.ue_idx, + h.h_id, + IsDl ? "DL" : "UL", + h.prev_tx_params.tbs_bytes, + h.max_nof_harq_retxs); + } + } + + if (ack or h.nof_retxs >= h.max_nof_harq_retxs) { + // If the HARQ process is ACKed or the maximum number of retransmissions has been reached, we can deallocate the + // HARQ process. + dealloc_harq(h); + } else { + set_pending_retx(h); + } +} + +template +void cell_harq_repository::set_pending_retx(harq_type& h) +{ + srsran_sanity_check(h.status != harq_state_t::empty, "HARQ process in wrong state"); + if (h.status == harq_state_t::pending_retx) { + // No-op + return; + } + + // Remove the HARQ from the timeout list. + harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].pop(&h); + + // Add HARQ to pending Retx list. + harq_pending_retx_list.push_front(&h); + + // Update HARQ process state. + h.status = harq_state_t::pending_retx; +} + +template +void cell_harq_repository::reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs) +{ + ues[ue_idx].free_harq_ids.resize(nof_harqs); + for (unsigned count = 0; count != nof_harqs; count++) { + harq_id_t h_id = to_harq_id(nof_harqs - count - 1); + ues[ue_idx].free_harq_ids[count] = h_id; + } +} + +template +void cell_harq_repository::destroy_ue_harqs(du_ue_index_t ue_idx) +{ + // Return back to the pool all HARQ processes allocated by the UE. + for (unsigned h_idx : ues[ue_idx].harqs) { + if (h_idx != INVALID_HARQ_REF_INDEX) { + dealloc_harq(harqs[h_idx]); + } + } + ues[ue_idx].free_harq_ids.clear(); +} + +template +void cell_harq_repository::cancel_retxs(harq_type& h) +{ + if (h.status == harq_state_t::empty) { + return; + } + h.max_nof_harq_retxs = h.nof_retxs; + h.retxs_cancelled = true; +} + +template +unsigned cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const +{ + for (unsigned h_ref_idx : ues[ue_idx].harqs) { + if (h_ref_idx != INVALID_HARQ_REF_INDEX) { + const harq_type& h = harqs[h_ref_idx]; + if (h.status == harq_state_t::pending_retx) { + return h_ref_idx; + } + } + } + return INVALID_HARQ_REF_INDEX; +} + +template struct harq_utils::cell_harq_repository; +template struct harq_utils::cell_harq_repository; + +// Cell HARQ manager. + +cell_harq_manager::cell_harq_manager(unsigned max_ues, + unsigned max_ack_wait_timeout, + std::unique_ptr notifier) : + timeout_notifier(std::move(notifier)), + logger(srslog::fetch_basic_logger("SCHED")), + dl(max_ues, max_ack_wait_timeout, *timeout_notifier, logger), + ul(max_ues, max_ack_wait_timeout, *timeout_notifier, logger) +{ +} + +void cell_harq_manager::slot_indication(slot_point sl_tx) +{ + last_sl_tx = sl_tx; + dl.slot_indication(sl_tx); + ul.slot_indication(sl_tx); +} + +bool cell_harq_manager::contains(du_ue_index_t ue_idx) const +{ + return dl.ues[ue_idx].free_harq_ids.size() != 0; +} + +unique_ue_harq_entity +cell_harq_manager::add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs) +{ + srsran_assert(nof_dl_harq_procs > 0, "Invalid number of HARQs"); + srsran_assert(nof_ul_harq_procs > 0, "Invalid number of HARQs"); + srsran_assert(not contains(ue_idx), "Creating UE with duplicate ue_index"); + dl.reserve_ue_harqs(ue_idx, nof_dl_harq_procs); + ul.reserve_ue_harqs(ue_idx, nof_ul_harq_procs); + return {this, ue_idx, crnti}; +} + +void cell_harq_manager::destroy_ue(du_ue_index_t ue_idx) +{ + dl.destroy_ue_harqs(ue_idx); + ul.destroy_ue_harqs(ue_idx); +} + +harq_utils::dl_harq_process_impl* cell_harq_manager::new_dl_tx(du_ue_index_t ue_idx, + slot_point pdsch_slot, + unsigned k1, + unsigned max_harq_nof_retxs, + uint8_t harq_bit_idx) +{ + dl_harq_process_impl* h = dl.alloc_harq(ue_idx, pdsch_slot, pdsch_slot + k1, max_harq_nof_retxs); + if (h == nullptr) { + return nullptr; + } + + // Save DL-specific parameters. + h->prev_tx_params = {}; + h->harq_bit_idx = harq_bit_idx; + h->pucch_ack_to_receive = 0; + h->chosen_ack = mac_harq_ack_report_status::dtx; + h->last_pucch_snr = std::nullopt; + + return h; +} + +harq_utils::ul_harq_process_impl* +cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsigned max_harq_nof_retxs) +{ + ul_harq_process_impl* h = ul.alloc_harq(ue_idx, pusch_slot, pusch_slot, max_harq_nof_retxs); + if (h == nullptr) { + return nullptr; + } + + // Save UL-specific parameters. + h->prev_tx_params = {}; + + return h; +} + +dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::dl_harq_process_impl& h, + mac_harq_ack_report_status ack, + std::optional pucch_snr) +{ + using status_update = dl_harq_process_impl::status_update; + + if (h.status != harq_state_t::waiting_ack) { + // If the HARQ process is not expecting an HARQ-ACK, it means that it has already been ACKed/NACKed. + logger.warning("ue={} h_id={}: ACK arrived for inactive DL HARQ", h.ue_idx, h.h_id); + return status_update::error; + } + + if (ack != mac_harq_ack_report_status::dtx and + (not h.last_pucch_snr.has_value() or (pucch_snr.has_value() and h.last_pucch_snr.value() < pucch_snr.value()))) { + // Case: If there was no previous HARQ-ACK decoded or the previous HARQ-ACK had lower SNR, this HARQ-ACK is chosen. + h.chosen_ack = ack; + h.last_pucch_snr = pucch_snr; + } + + if (h.pucch_ack_to_receive <= 1) { + // Case: This is the last HARQ-ACK that is expected for this HARQ process. + + // Update HARQ state + bool final_ack = h.chosen_ack == mac_harq_ack_report_status::ack; + dl.handle_ack(h, final_ack); + + return final_ack ? status_update::acked : status_update::nacked; + } + + // Case: This is not the last PUCCH HARQ-ACK that is expected for this HARQ process. + h.pucch_ack_to_receive--; + h.ack_on_timeout = h.chosen_ack == mac_harq_ack_report_status::ack; + // We reduce the HARQ process timeout to receive the next HARQ-ACK. This is done because the two HARQ-ACKs should + // arrive almost simultaneously, and in case the second goes missing, we don't want to block the HARQ for too long. + dl.harq_timeout_wheel[h.slot_ack_timeout.to_uint() % dl.harq_timeout_wheel.size()].pop(&h); + h.slot_ack_timeout = last_sl_tx + SHORT_ACK_TIMEOUT_DTX; + dl.harq_timeout_wheel[h.slot_ack_timeout.to_uint() % dl.harq_timeout_wheel.size()].push_front(&h); + + return status_update::no_update; +} + +int cell_harq_manager::ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack) +{ + if (h.status != harq_state_t::waiting_ack) { + // HARQ is not expecting CRC info. + logger.warning("ue={} h_id={}: CRC arrived for UL HARQ not expecting it", h.ue_idx, h.h_id); + return -1; + } + + ul.handle_ack(h, ack); + + return ack ? (int)h.prev_tx_params.tbs_bytes : 0; +} + +dl_harq_process_view::status_update dl_harq_process_view::dl_ack_info(mac_harq_ack_report_status ack, + std::optional pucch_snr) +{ + return cell_harq_mng->dl_ack_info(cell_harq_mng->dl.harqs[harq_ref_idx], ack, pucch_snr); +} + +int ul_harq_process_view::ul_crc_info(bool ack) +{ + return cell_harq_mng->ul_crc_info(cell_harq_mng->ul.harqs[harq_ref_idx], ack); +} + +// UE HARQ entity. + +unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept : + cell_harq_mgr(other.cell_harq_mgr), ue_index(other.ue_index) +{ + other.cell_harq_mgr = nullptr; + other.ue_index = INVALID_DU_UE_INDEX; +} + +unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&& other) noexcept +{ + cell_harq_mgr->destroy_ue(ue_index); + cell_harq_mgr = other.cell_harq_mgr; + ue_index = other.ue_index; + other.cell_harq_mgr = nullptr; + other.ue_index = INVALID_DU_UE_INDEX; + return *this; +} + +unique_ue_harq_entity::~unique_ue_harq_entity() +{ + if (cell_harq_mgr != nullptr) { + cell_harq_mgr->destroy_ue(ue_index); + } +} + +std::optional +unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx) +{ + dl_harq_process_impl* h = cell_harq_mgr->new_dl_tx(ue_index, sl_tx, k1, max_harq_nof_retxs, harq_bit_idx); + if (h == nullptr) { + return std::nullopt; + } + return dl_harq_process_view(*cell_harq_mgr, cell_harq_mgr->dl.get_harq_ref_idx(*h)); +} + +std::optional unique_ue_harq_entity::alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs) +{ + ul_harq_process_impl* h = cell_harq_mgr->new_ul_tx(ue_index, sl_tx, max_harq_nof_retxs); + if (h == nullptr) { + return std::nullopt; + } + return ul_harq_process_view(*cell_harq_mgr, cell_harq_mgr->ul.get_harq_ref_idx(*h)); +} + +std::optional unique_ue_harq_entity::find_pending_dl_retx() +{ + unsigned h_ref_idx = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); + if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + return std::nullopt; + } + return dl_harq_process_view(*cell_harq_mgr, h_ref_idx); +} + +std::optional unique_ue_harq_entity::find_pending_ul_retx() +{ + unsigned h_ref_idx = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); + if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + return std::nullopt; + } + return ul_harq_process_view(*cell_harq_mgr, h_ref_idx); +} + +std::optional unique_ue_harq_entity::find_dl_harq_waiting_ack() +{ + unsigned h_ref_idx = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); + if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + return std::nullopt; + } + return dl_harq_process_view(*cell_harq_mgr, h_ref_idx); +} + +std::optional unique_ue_harq_entity::find_ul_harq_waiting_ack() +{ + unsigned h_ref_idx = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); + if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + return std::nullopt; + } + return ul_harq_process_view(*cell_harq_mgr, h_ref_idx); +} + +std::optional unique_ue_harq_entity::find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx) +{ + const std::vector& dl_harqs = cell_harq_mgr->dl.ues[ue_index].harqs; + for (unsigned h_ref_idx : dl_harqs) { + if (h_ref_idx != INVALID_HARQ_REF_INDEX) { + const dl_harq_process_impl& h = cell_harq_mgr->dl.harqs[h_ref_idx]; + if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_ack == uci_slot and + h.harq_bit_idx == harq_bit_idx) { + return dl_harq_process_view(*cell_harq_mgr, h_ref_idx); + } + } + } + return std::nullopt; +} + +std::optional unique_ue_harq_entity::find_ul_harq(slot_point pusch_slot) +{ + const std::vector& ul_harqs = cell_harq_mgr->ul.ues[ue_index].harqs; + for (unsigned h_ref_idx : ul_harqs) { + if (h_ref_idx != INVALID_HARQ_REF_INDEX) { + const ul_harq_process_impl& h = cell_harq_mgr->ul.harqs[h_ref_idx]; + if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_tx == pusch_slot) { + return ul_harq_process_view(*cell_harq_mgr, h_ref_idx); + } + } + } + return std::nullopt; +} diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h new file mode 100644 index 0000000000..505b4b9b04 --- /dev/null +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -0,0 +1,324 @@ +/* + * + * 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/intrusive_list.h" +#include "srsran/adt/optional.h" +#include "srsran/ran/csi_report/csi_report_data.h" +#include "srsran/ran/du_types.h" +#include "srsran/ran/pdsch/pdsch_mcs.h" +#include "srsran/ran/pusch/pusch_mcs.h" +#include "srsran/ran/slot_point.h" +#include "srsran/scheduler/harq_id.h" +#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/srslog/srslog.h" +#include + +namespace srsran { + +class unique_ue_harq_entity; + +/// \brief Notifier of HARQ process timeouts. +class harq_timeout_notifier +{ +public: + virtual ~harq_timeout_notifier() = default; + + /// \brief Notifies a HARQ timeout. + virtual void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) = 0; +}; + +namespace harq_utils { + +const static unsigned INVALID_HARQ_REF_INDEX = std::numeric_limits::max(); + +/// Possible states of a HARQ process. +enum class harq_state_t { empty, pending_retx, waiting_ack }; + +/// Parameters that are common to DL and UL HARQ processes. +struct base_harq_process : public intrusive_double_linked_list_element<> { + du_ue_index_t ue_idx; + harq_id_t h_id; + harq_state_t status = harq_state_t::empty; + slot_point slot_tx; + slot_point slot_ack; + slot_point slot_ack_timeout; + /// New Data Indicator. Its value should flip for every new Tx. + bool ndi = false; + /// Number of retransmissions that took place for the current Transport Block. + unsigned nof_retxs = 0; + /// Maximum number of retransmission before Transport Block is reset. + unsigned max_nof_harq_retxs = 0; + /// Whether to set the HARQ as ACKed or NACKed when the timeout expires. + bool ack_on_timeout = false; + /// Whether retransmissions for this HARQ process have been cancelled. + bool retxs_cancelled = false; +}; + +/// Parameters of a DL HARQ process. +struct dl_harq_process_impl : public base_harq_process { + /// \brief Update to the HARQ process state after a HARQ-ACK is received. + enum class status_update { acked, nacked, no_update, error }; + + /// \brief Parameters relative to the last used PDSCH PDU that get stored in the HARQ process for future reuse. + struct alloc_params { + dci_dl_rnti_config_type dci_cfg_type; + vrb_alloc rbs; + unsigned nof_symbols; + unsigned nof_layers{1}; + bool is_fallback{false}; + cqi_value cqi; + pdsch_mcs_table mcs_table; + sch_mcs_index mcs; + unsigned tbs_bytes; + /// \brief MCS originally suggested by the OLLA. It might differ from the actual MCS used. + std::optional olla_mcs; + }; + + /// Parameters used for the last Tx of this HARQ process. + alloc_params prev_tx_params; + /// HARQ-bit index corresponding to this HARQ process in the UCI PDU indication. + uint8_t harq_bit_idx = 0; + /// Keeps the count of how many PUCCH grants are allocate for this harq_process. + unsigned pucch_ack_to_receive{0}; + /// Chosen ACK status for this HARQ process transmission, given one or more HARQ-ACK bits received. + mac_harq_ack_report_status chosen_ack = mac_harq_ack_report_status::dtx; + /// Stores the highest recorded PUCCH SNR for this HARQ process. + std::optional last_pucch_snr; +}; + +/// Parameters of a UL HARQ process. +struct ul_harq_process_impl : public base_harq_process { + /// \brief Parameters relative to the last allocated PUSCH PDU for this HARQ process. + struct alloc_params { + dci_ul_rnti_config_type dci_cfg_type; + vrb_alloc rbs; + pusch_mcs_table mcs_table; + sch_mcs_index mcs; + unsigned tbs_bytes; + unsigned nof_symbols; + std::optional olla_mcs; + }; + + /// Parameters used for the last Tx of this HARQ process. + alloc_params prev_tx_params; +}; + +struct ue_harq_entity_impl { + std::vector harqs; + std::vector free_harq_ids; +}; + +template +struct cell_harq_repository { + using harq_type = std::conditional_t; + + cell_harq_repository(unsigned max_ues, + unsigned max_ack_wait_in_slots, + harq_timeout_notifier& timeout_notifier_, + srslog::basic_logger& logger_); + + /// Maximum value of time interval, in slots, before the HARQ process assumes that the ACK/CRC went missing. + const unsigned max_ack_wait_in_slots; + harq_timeout_notifier& timeout_notifier; + srslog::basic_logger& logger; + + std::vector harqs; + std::vector free_harqs; + std::vector ues; + intrusive_double_linked_list harq_pending_retx_list; + std::vector> harq_timeout_wheel; + + unsigned get_harq_ref_idx(const harq_type& h) const; + + void slot_indication(slot_point sl_tx); + void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); + harq_type* alloc_harq(du_ue_index_t ue_idx, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); + void dealloc_harq(harq_type& h); + void handle_ack(harq_type& h, bool ack); + void set_pending_retx(harq_type& h); + void reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs); + void destroy_ue_harqs(du_ue_index_t ue_idx); + void cancel_retxs(harq_type& h); + unsigned find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; +}; + +} // namespace harq_utils + +class cell_harq_manager +{ +public: + cell_harq_manager(unsigned max_ues, unsigned max_ack_wait_timeout, std::unique_ptr notifier); + + /// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK + void slot_indication(slot_point sl_tx); + + /// Create new UE HARQ entity. + /// \param rnti RNTI of the UE + /// \param nof_dl_harq_procs Number of DL HARQ processes that the UE can support. This value is derived based on + /// the UE capabilities, and passed to the UE via RRC signalling. See TS38.331, "nrofHARQ-ProcessesForPDSCH". + /// Values: {2, 4, 6, 10, 12, 16}. + /// \param nof_ul_harq_procs Number of UL HARQ processes that gNB can support. This value is implementation-defined + /// and can up to 16 (there are up to 4 bits for HARQ-Id signalling). + unique_ue_harq_entity + add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs); + + /// Checks whether an UE with the provided ue index exists. + bool contains(du_ue_index_t ue_idx) const; + +private: + friend class unique_ue_harq_entity; + friend class dl_harq_process_view; + friend class ul_harq_process_view; + + /// \brief Timeout value to use when the HARQ has been ACKed/NACKed, but it is expecting another PUCCH before being + /// cleared (implementation-defined). + constexpr static unsigned SHORT_ACK_TIMEOUT_DTX = 8U; + + const static unsigned INVALID_HARQ = std::numeric_limits::max(); + + void destroy_ue(du_ue_index_t ue_idx); + + /// \brief Called on every DL new Tx to allocate an UL HARQ process. + harq_utils::dl_harq_process_impl* new_dl_tx(du_ue_index_t ue_idx, + slot_point pdsch_slot, + unsigned k1, + unsigned max_harq_nof_retxs, + uint8_t harq_bit_idx); + + /// \brief Called on every UL new Tx to allocate an UL HARQ process. + harq_utils::ul_harq_process_impl* new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsigned max_harq_nof_retxs); + + /// Updates a DL HARQ process given the received HARQ-ACK info. + harq_utils::dl_harq_process_impl::status_update + dl_ack_info(harq_utils::dl_harq_process_impl& h, mac_harq_ack_report_status ack, std::optional pucch_snr); + + /// Updates a UL HARQ process given the received CRC indication. + /// \return Transport Block size of the HARQ whose state was updated. + int ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack); + + std::unique_ptr timeout_notifier; + srslog::basic_logger& logger; + + slot_point last_sl_tx; + + harq_utils::cell_harq_repository dl; + harq_utils::cell_harq_repository ul; +}; + +class dl_harq_process_view +{ +public: + using status_update = harq_utils::dl_harq_process_impl::status_update; + using grant_params = harq_utils::dl_harq_process_impl::alloc_params; + + dl_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : + cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) + { + } + + /// \brief Update the state of the DL HARQ process waiting for an HARQ-ACK. + /// \param[in] ack HARQ-ACK status received. + /// \param[in] pucch_snr SNR of the PUCCH that carried the HARQ-ACK. + /// \return Status update after processing the ACK info. + status_update dl_ack_info(mac_harq_ack_report_status ack, std::optional pucch_snr); + + const grant_params& get_grant_params() const { return cell_harq_mng->dl.harqs[harq_ref_idx].prev_tx_params; } + +private: + cell_harq_manager* cell_harq_mng = nullptr; + unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; +}; + +class ul_harq_process_view +{ +public: + ul_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : + cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) + { + } + + /// Update UL HARQ state given the received CRC indication. + /// \return Transport Block size of the HARQ whose state was updated. + int ul_crc_info(bool ack); + +private: + cell_harq_manager* cell_harq_mng = nullptr; + unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; +}; + +class unique_ue_harq_entity +{ +public: + unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_) : + cell_harq_mgr(mgr), ue_index(ue_idx), crnti(crnti_) + { + } + ~unique_ue_harq_entity(); + unique_ue_harq_entity(const unique_ue_harq_entity&) = delete; + unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept; + unique_ue_harq_entity& operator=(const unique_ue_harq_entity&) = delete; + unique_ue_harq_entity& operator=(unique_ue_harq_entity&& other) noexcept; + + unsigned nof_dl_harqs() const { return get_dl_ue().harqs.size(); } + unsigned nof_ul_harqs() const { return get_ul_ue().harqs.size(); } + + bool has_empty_dl_harqs() const { return not get_dl_ue().free_harq_ids.empty(); } + bool has_empty_ul_harqs() const { return not get_ul_ue().free_harq_ids.empty(); } + + std::optional dl_harq(harq_id_t h_id) + { + if (cell_harq_mgr->dl.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { + return dl_harq_process_view{*cell_harq_mgr, cell_harq_mgr->dl.ues[ue_index].harqs[h_id]}; + } + return std::nullopt; + } + std::optional ul_harq(harq_id_t h_id) + { + if (cell_harq_mgr->ul.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { + return ul_harq_process_view{*cell_harq_mgr, cell_harq_mgr->ul.ues[ue_index].harqs[h_id]}; + } + return std::nullopt; + } + + std::optional + alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx); + std::optional alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs); + + std::optional find_pending_dl_retx(); + std::optional find_pending_ul_retx(); + + std::optional find_dl_harq_waiting_ack(); + std::optional find_ul_harq_waiting_ack(); + + /// Fetch active DL HARQ process based on HARQ-ACK UCI slot and HARQ bit index. + /// \param[in] uci_slot Slot when the UCI is to be received. + /// \param[in] harq_bit_idx Bit index of the HARQ-ACK in the UCI indication. + /// \return Active DL HARQ process with matching UCI slot and HARQ bit index, if found. + std::optional find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx); + + /// Fetch active UL HARQ process based on slot when its PUSCH was transmitted. + /// \param[in] pusch_slot Slot when the PUSCH was transmitted. + /// \return Active UL HARQ process with matching PUSCH slot, if found. + std::optional find_ul_harq(slot_point pusch_slot); + +private: + harq_utils::ue_harq_entity_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } + const harq_utils::ue_harq_entity_impl& get_dl_ue() const { return cell_harq_mgr->dl.ues[ue_index]; } + harq_utils::ue_harq_entity_impl& get_ul_ue() { return cell_harq_mgr->ul.ues[ue_index]; } + const harq_utils::ue_harq_entity_impl& get_ul_ue() const { return cell_harq_mgr->ul.ues[ue_index]; } + + cell_harq_manager* cell_harq_mgr = nullptr; + du_ue_index_t ue_index = INVALID_DU_UE_INDEX; + rnti_t crnti; +}; + +} // namespace srsran \ No newline at end of file From 964ca28a1d5e939e399378e6d43febae2e5337a4 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Aug 2024 15:23:12 +0200 Subject: [PATCH 386/407] sched: wrote basic unit test for harq manager --- .../ue_scheduling/cell_harq_manager.cpp | 21 ++++-- .../ue_scheduling/cell_harq_manager.h | 62 +++++++++++++++-- .../scheduler/ue_scheduling/CMakeLists.txt | 1 + .../ue_scheduling/harq_manager_test.cpp | 69 +++++++++++++++++++ 4 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 5f04046b82..73bb16536c 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -32,6 +32,9 @@ cell_harq_repository::cell_harq_repository(unsigned max_ues, ues[i].free_harq_ids.reserve(MAX_NOF_HARQS); ues[i].harqs.resize(MAX_NOF_HARQS, INVALID_HARQ_REF_INDEX); } + + const unsigned RING_SIZE = 40; // TODO: use function to define this value. + harq_timeout_wheel.resize(RING_SIZE); } template @@ -240,7 +243,7 @@ unsigned cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, for (unsigned h_ref_idx : ues[ue_idx].harqs) { if (h_ref_idx != INVALID_HARQ_REF_INDEX) { const harq_type& h = harqs[h_ref_idx]; - if (h.status == harq_state_t::pending_retx) { + if (h.status == state) { return h_ref_idx; } } @@ -254,8 +257,8 @@ template struct harq_utils::cell_harq_repository; // Cell HARQ manager. cell_harq_manager::cell_harq_manager(unsigned max_ues, - unsigned max_ack_wait_timeout, - std::unique_ptr notifier) : + std::unique_ptr notifier, + unsigned max_ack_wait_timeout) : timeout_notifier(std::move(notifier)), logger(srslog::fetch_basic_logger("SCHED")), dl(max_ues, max_ack_wait_timeout, *timeout_notifier, logger), @@ -403,7 +406,9 @@ unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noex unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&& other) noexcept { - cell_harq_mgr->destroy_ue(ue_index); + if (cell_harq_mgr != nullptr) { + cell_harq_mgr->destroy_ue(ue_index); + } cell_harq_mgr = other.cell_harq_mgr; ue_index = other.ue_index; other.cell_harq_mgr = nullptr; @@ -418,6 +423,14 @@ unique_ue_harq_entity::~unique_ue_harq_entity() } } +void unique_ue_harq_entity::reset() +{ + if (cell_harq_mgr != nullptr) { + cell_harq_mgr->destroy_ue(ue_index); + cell_harq_mgr = nullptr; + } +} + std::optional unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx) { diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index 505b4b9b04..6a7ac99902 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -36,6 +36,14 @@ class harq_timeout_notifier virtual void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) = 0; }; +class noop_harq_timeout_notifier : public harq_timeout_notifier +{ +public: + void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override + { /* do nothing */ + } +}; + namespace harq_utils { const static unsigned INVALID_HARQ_REF_INDEX = std::numeric_limits::max(); @@ -156,7 +164,13 @@ struct cell_harq_repository { class cell_harq_manager { public: - cell_harq_manager(unsigned max_ues, unsigned max_ack_wait_timeout, std::unique_ptr notifier); + /// \brief Default timeout in slots after which the HARQ process assumes that the CRC/ACK went missing + /// (implementation-defined). + constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; + + cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, + std::unique_ptr notifier = std::make_unique(), + unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS); /// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK void slot_indication(slot_point sl_tx); @@ -168,8 +182,10 @@ class cell_harq_manager /// Values: {2, 4, 6, 10, 12, 16}. /// \param nof_ul_harq_procs Number of UL HARQ processes that gNB can support. This value is implementation-defined /// and can up to 16 (there are up to 4 bits for HARQ-Id signalling). - unique_ue_harq_entity - add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs); + unique_ue_harq_entity add_ue(du_ue_index_t ue_idx, + rnti_t crnti, + unsigned nof_dl_harq_procs = MAX_NOF_HARQS, + unsigned nof_ul_harq_procs = MAX_NOF_HARQS); /// Checks whether an UE with the provided ue index exists. bool contains(du_ue_index_t ue_idx) const; @@ -223,6 +239,17 @@ class dl_harq_process_view dl_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) { + srsran_sanity_check(cell_harq_mng->dl.harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty, + "Empty HARQ process created"); + } + + bool is_waiting_ack() const + { + return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack; + } + bool has_pending_retx() const + { + return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx; } /// \brief Update the state of the DL HARQ process waiting for an HARQ-ACK. @@ -233,6 +260,12 @@ class dl_harq_process_view const grant_params& get_grant_params() const { return cell_harq_mng->dl.harqs[harq_ref_idx].prev_tx_params; } + bool operator==(const dl_harq_process_view& other) const + { + return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx; + } + bool operator!=(const dl_harq_process_view& other) const { return !(*this == other); } + private: cell_harq_manager* cell_harq_mng = nullptr; unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; @@ -244,12 +277,29 @@ class ul_harq_process_view ul_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) { + srsran_sanity_check(cell_harq_mng->ul.harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty, + "Empty HARQ process created"); + } + + bool is_waiting_ack() const + { + return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack; + } + bool has_pending_retx() const + { + return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx; } /// Update UL HARQ state given the received CRC indication. /// \return Transport Block size of the HARQ whose state was updated. int ul_crc_info(bool ack); + bool operator==(const ul_harq_process_view& other) const + { + return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx; + } + bool operator!=(const ul_harq_process_view& other) const { return !(*this == other); } + private: cell_harq_manager* cell_harq_mng = nullptr; unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; @@ -258,9 +308,11 @@ class ul_harq_process_view class unique_ue_harq_entity { public: + unique_ue_harq_entity() = default; unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_) : cell_harq_mgr(mgr), ue_index(ue_idx), crnti(crnti_) { + (void)crnti; } ~unique_ue_harq_entity(); unique_ue_harq_entity(const unique_ue_harq_entity&) = delete; @@ -274,6 +326,8 @@ class unique_ue_harq_entity bool has_empty_dl_harqs() const { return not get_dl_ue().free_harq_ids.empty(); } bool has_empty_ul_harqs() const { return not get_ul_ue().free_harq_ids.empty(); } + void reset(); + std::optional dl_harq(harq_id_t h_id) { if (cell_harq_mgr->dl.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { @@ -318,7 +372,7 @@ class unique_ue_harq_entity cell_harq_manager* cell_harq_mgr = nullptr; du_ue_index_t ue_index = INVALID_DU_UE_INDEX; - rnti_t crnti; + rnti_t crnti = rnti_t::INVALID_RNTI; }; } // namespace srsran \ No newline at end of file diff --git a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt index e81ac784da..7bd0f215f9 100644 --- a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt +++ b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable(ue_scheduler_test logical_channel_test.cpp + harq_manager_test.cpp harq_entity_test.cpp harq_process_test.cpp fallback_scheduler_test.cpp diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp new file mode 100644 index 0000000000..2d76389d58 --- /dev/null +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -0,0 +1,69 @@ +/* + * + * 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/ue_scheduling/cell_harq_manager.h" +#include "srsran/support/test_utils.h" +#include + +using namespace srsran; + +class harq_entity_test : public ::testing::Test +{ +protected: + cell_harq_manager cell_harqs{1}; + du_ue_index_t ue_index = to_du_ue_index(0); + rnti_t rnti = to_rnti(0x4601); + unsigned max_retxs = 4; + + unique_ue_harq_entity harq_ent; +}; + +TEST_F(harq_entity_test, when_ue_harq_entity_is_created_cell_harq_manager_is_updated) +{ + ASSERT_FALSE(cell_harqs.contains(ue_index)); + harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); + ASSERT_TRUE(cell_harqs.contains(ue_index)); + harq_ent.reset(); + ASSERT_FALSE(cell_harqs.contains(ue_index)); +} + +TEST_F(harq_entity_test, when_harq_entity_is_created_all_harqs_are_empty) +{ + harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); + ASSERT_EQ(harq_ent.nof_dl_harqs(), 16); + ASSERT_EQ(harq_ent.nof_ul_harqs(), 16); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); + ASSERT_TRUE(harq_ent.has_empty_dl_harqs()); + ASSERT_TRUE(harq_ent.has_empty_ul_harqs()); + for (unsigned i = 0; i != 16; ++i) { + ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(i)).has_value()); + ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(i)).has_value()); + } +} + +TEST_F(harq_entity_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) +{ + harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); + slot_point sl_tx{0, 0}; + unsigned k1 = 4; + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_dl.value().is_waiting_ack()); + ASSERT_FALSE(h_dl.value().has_pending_retx()); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + ASSERT_TRUE(h_ul.has_value()); + ASSERT_TRUE(h_ul.value().is_waiting_ack()); + ASSERT_FALSE(h_ul.value().has_pending_retx()); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul); +} From 6ed8a6bcbd7f54a65ed3814d078025af7ffec594 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Aug 2024 17:43:43 +0200 Subject: [PATCH 387/407] sched: extend unit tests for new harq_manager class --- .../ue_scheduling/cell_harq_manager.cpp | 80 +++++++- .../ue_scheduling/cell_harq_manager.h | 32 ++-- .../ue_scheduling/harq_manager_test.cpp | 181 ++++++++++++++++-- 3 files changed, 262 insertions(+), 31 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 73bb16536c..cf55ebb1b8 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -13,6 +13,18 @@ using namespace srsran; using namespace harq_utils; +namespace { + +class noop_harq_timeout_notifier : public harq_timeout_notifier +{ +public: + void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override + { /* do nothing */ + } +}; + +} // namespace + template cell_harq_repository::cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_timeout, @@ -30,10 +42,11 @@ cell_harq_repository::cell_harq_repository(unsigned max_ues, ues.resize(max_ues); for (unsigned i = 0; i != max_ues; i++) { ues[i].free_harq_ids.reserve(MAX_NOF_HARQS); - ues[i].harqs.resize(MAX_NOF_HARQS, INVALID_HARQ_REF_INDEX); + ues[i].harqs.reserve(MAX_NOF_HARQS); } - const unsigned RING_SIZE = 40; // TODO: use function to define this value. + const unsigned RING_SIZE = 320; // TODO: use function to define this value. It must account the timeout arg and k + // values harq_timeout_wheel.resize(RING_SIZE); } @@ -42,8 +55,8 @@ void cell_harq_repository::slot_indication(slot_point sl_tx) { // Handle HARQs that timed out. auto& harqs_timing_out = harq_timeout_wheel[sl_tx.to_uint() % harq_timeout_wheel.size()]; - for (harq_type& h : harqs_timing_out) { - handle_harq_ack_timeout(h, sl_tx); + while (not harqs_timing_out.empty()) { + handle_harq_ack_timeout(harqs_timing_out.front(), sl_tx); } } @@ -205,13 +218,36 @@ void cell_harq_repository::set_pending_retx(harq_type& h) h.status = harq_state_t::pending_retx; } +template +void cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack) +{ + srsran_assert(h.status == harq_state_t::pending_retx, "Attempt of retx in an HARQ that has no pending retx"); + + // Remove HARQ from pending Retx list. + harq_pending_retx_list.pop(&h); + + h.status = harq_state_t::waiting_ack; + h.slot_tx = sl_tx; + h.slot_ack = sl_ack; + h.ndi = !h.ndi; + h.ack_on_timeout = false; + h.retxs_cancelled = false; + h.nof_retxs++; + + // Add HARQ to the timeout list. + h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; + harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); +} + template void cell_harq_repository::reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs) { + ues[ue_idx].harqs.resize(nof_harqs); ues[ue_idx].free_harq_ids.resize(nof_harqs); for (unsigned count = 0; count != nof_harqs; count++) { harq_id_t h_id = to_harq_id(nof_harqs - count - 1); ues[ue_idx].free_harq_ids[count] = h_id; + ues[ue_idx].harqs[count] = INVALID_HARQ_REF_INDEX; } } @@ -259,7 +295,7 @@ template struct harq_utils::cell_harq_repository; cell_harq_manager::cell_harq_manager(unsigned max_ues, std::unique_ptr notifier, unsigned max_ack_wait_timeout) : - timeout_notifier(std::move(notifier)), + timeout_notifier(notifier != nullptr ? std::move(notifier) : std::make_unique()), logger(srslog::fetch_basic_logger("SCHED")), dl(max_ues, max_ack_wait_timeout, *timeout_notifier, logger), ul(max_ues, max_ack_wait_timeout, *timeout_notifier, logger) @@ -275,14 +311,15 @@ void cell_harq_manager::slot_indication(slot_point sl_tx) bool cell_harq_manager::contains(du_ue_index_t ue_idx) const { - return dl.ues[ue_idx].free_harq_ids.size() != 0; + return ue_idx < dl.ues.size() and dl.ues[ue_idx].free_harq_ids.size() != 0; } unique_ue_harq_entity cell_harq_manager::add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs) { - srsran_assert(nof_dl_harq_procs > 0, "Invalid number of HARQs"); - srsran_assert(nof_ul_harq_procs > 0, "Invalid number of HARQs"); + srsran_sanity_check(nof_dl_harq_procs > 0, "Invalid number of HARQs"); + srsran_sanity_check(nof_ul_harq_procs > 0, "Invalid number of HARQs"); + srsran_sanity_check(ue_idx < dl.ues.size(), "Invalid ue_index"); srsran_assert(not contains(ue_idx), "Creating UE with duplicate ue_index"); dl.reserve_ue_harqs(ue_idx, nof_dl_harq_procs); ul.reserve_ue_harqs(ue_idx, nof_ul_harq_procs); @@ -330,6 +367,23 @@ cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsign return h; } +void cell_harq_manager::new_dl_retx(harq_utils::dl_harq_process_impl& h, + slot_point pdsch_slot, + unsigned k1, + uint8_t harq_bit_idx) +{ + dl.handle_new_retx(h, pdsch_slot, pdsch_slot + k1); + h.harq_bit_idx = harq_bit_idx; + h.pucch_ack_to_receive = 0; + h.chosen_ack = mac_harq_ack_report_status::dtx; + h.last_pucch_snr = std::nullopt; +} + +void cell_harq_manager::new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot) +{ + ul.handle_new_retx(h, pusch_slot, pusch_slot); +} + dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::dl_harq_process_impl& h, mac_harq_ack_report_status ack, std::optional pucch_snr) @@ -384,12 +438,22 @@ int cell_harq_manager::ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack return ack ? (int)h.prev_tx_params.tbs_bytes : 0; } +void dl_harq_process_view::new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) +{ + cell_harq_mng->new_dl_retx(cell_harq_mng->dl.harqs[harq_ref_idx], pdsch_slot, k1, harq_bit_idx); +} + dl_harq_process_view::status_update dl_harq_process_view::dl_ack_info(mac_harq_ack_report_status ack, std::optional pucch_snr) { return cell_harq_mng->dl_ack_info(cell_harq_mng->dl.harqs[harq_ref_idx], ack, pucch_snr); } +void ul_harq_process_view::new_retx(slot_point pusch_slot) +{ + cell_harq_mng->new_ul_retx(cell_harq_mng->ul.harqs[harq_ref_idx], pusch_slot); +} + int ul_harq_process_view::ul_crc_info(bool ack) { return cell_harq_mng->ul_crc_info(cell_harq_mng->ul.harqs[harq_ref_idx], ack); diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index 6a7ac99902..a15a56c11a 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -36,14 +36,6 @@ class harq_timeout_notifier virtual void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) = 0; }; -class noop_harq_timeout_notifier : public harq_timeout_notifier -{ -public: - void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override - { /* do nothing */ - } -}; - namespace harq_utils { const static unsigned INVALID_HARQ_REF_INDEX = std::numeric_limits::max(); @@ -153,6 +145,7 @@ struct cell_harq_repository { void dealloc_harq(harq_type& h); void handle_ack(harq_type& h, bool ack); void set_pending_retx(harq_type& h); + void handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack); void reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs); void destroy_ue_harqs(du_ue_index_t ue_idx); void cancel_retxs(harq_type& h); @@ -168,8 +161,8 @@ class cell_harq_manager /// (implementation-defined). constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; - cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, - std::unique_ptr notifier = std::make_unique(), + cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, + std::unique_ptr notifier = nullptr, unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS); /// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK @@ -203,7 +196,7 @@ class cell_harq_manager void destroy_ue(du_ue_index_t ue_idx); - /// \brief Called on every DL new Tx to allocate an UL HARQ process. + /// \brief Called on every DL new Tx to allocate an DL HARQ process. harq_utils::dl_harq_process_impl* new_dl_tx(du_ue_index_t ue_idx, slot_point pdsch_slot, unsigned k1, @@ -213,6 +206,12 @@ class cell_harq_manager /// \brief Called on every UL new Tx to allocate an UL HARQ process. harq_utils::ul_harq_process_impl* new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsigned max_harq_nof_retxs); + /// \brief Called on a new retx of a DL HARQ process. + void new_dl_retx(harq_utils::dl_harq_process_impl& h, slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); + + /// \brief Called on a new retx of a UL HARQ process. + void new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot); + /// Updates a DL HARQ process given the received HARQ-ACK info. harq_utils::dl_harq_process_impl::status_update dl_ack_info(harq_utils::dl_harq_process_impl& h, mac_harq_ack_report_status ack, std::optional pucch_snr); @@ -243,6 +242,8 @@ class dl_harq_process_view "Empty HARQ process created"); } + harq_id_t id() const { return cell_harq_mng->dl.harqs[harq_ref_idx].h_id; } + bool is_waiting_ack() const { return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack; @@ -252,6 +253,8 @@ class dl_harq_process_view return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx; } + void new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); + /// \brief Update the state of the DL HARQ process waiting for an HARQ-ACK. /// \param[in] ack HARQ-ACK status received. /// \param[in] pucch_snr SNR of the PUCCH that carried the HARQ-ACK. @@ -281,6 +284,8 @@ class ul_harq_process_view "Empty HARQ process created"); } + harq_id_t id() const { return cell_harq_mng->ul.harqs[harq_ref_idx].h_id; } + bool is_waiting_ack() const { return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack; @@ -290,6 +295,8 @@ class ul_harq_process_view return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx; } + void new_retx(slot_point pusch_slot); + /// Update UL HARQ state given the received CRC indication. /// \return Transport Block size of the HARQ whose state was updated. int ul_crc_info(bool ack); @@ -320,12 +327,15 @@ class unique_ue_harq_entity unique_ue_harq_entity& operator=(const unique_ue_harq_entity&) = delete; unique_ue_harq_entity& operator=(unique_ue_harq_entity&& other) noexcept; + /// Gets the maximum number of HARQ processes a UE can use, which depends on its configuration. unsigned nof_dl_harqs() const { return get_dl_ue().harqs.size(); } unsigned nof_ul_harqs() const { return get_ul_ue().harqs.size(); } + /// Checks whether there are free HARQ processes. bool has_empty_dl_harqs() const { return not get_dl_ue().free_harq_ids.empty(); } bool has_empty_ul_harqs() const { return not get_ul_ue().free_harq_ids.empty(); } + /// Deallocate UE HARQ entity. void reset(); std::optional dl_harq(harq_id_t h_id) diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 2d76389d58..3950563dd0 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -14,29 +14,29 @@ using namespace srsran; -class harq_entity_test : public ::testing::Test +/// Test for a single UE HARQ entity. +class single_ue_harq_entity_test : public ::testing::Test { protected: - cell_harq_manager cell_harqs{1}; + const unsigned max_ack_wait_timeout = 16; + cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; du_ue_index_t ue_index = to_du_ue_index(0); rnti_t rnti = to_rnti(0x4601); unsigned max_retxs = 4; - - unique_ue_harq_entity harq_ent; }; -TEST_F(harq_entity_test, when_ue_harq_entity_is_created_cell_harq_manager_is_updated) +TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_created_cell_harq_manager_is_updated) { ASSERT_FALSE(cell_harqs.contains(ue_index)); - harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); ASSERT_TRUE(cell_harqs.contains(ue_index)); harq_ent.reset(); ASSERT_FALSE(cell_harqs.contains(ue_index)); } -TEST_F(harq_entity_test, when_harq_entity_is_created_all_harqs_are_empty) +TEST_F(single_ue_harq_entity_test, when_harq_entity_is_created_all_harqs_are_empty) { - harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); ASSERT_EQ(harq_ent.nof_dl_harqs(), 16); ASSERT_EQ(harq_ent.nof_ul_harqs(), 16); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); @@ -51,19 +51,176 @@ TEST_F(harq_entity_test, when_harq_entity_is_created_all_harqs_are_empty) } } -TEST_F(harq_entity_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) +TEST_F(single_ue_harq_entity_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) { - harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); slot_point sl_tx{0, 0}; unsigned k1 = 4; auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); ASSERT_TRUE(h_dl.value().is_waiting_ack()); + ASSERT_TRUE(h_ul.value().is_waiting_ack()); ASSERT_FALSE(h_dl.value().has_pending_retx()); + ASSERT_FALSE(h_ul.value().has_pending_retx()); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); +} + +TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cannot_find_empty_harq) +{ + unsigned nof_harqs = 4; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + ASSERT_EQ(harq_ent.nof_dl_harqs(), nof_harqs); + ASSERT_EQ(harq_ent.nof_ul_harqs(), nof_harqs); + + slot_point sl_tx{0, 0}; + unsigned k1 = 4; + for (unsigned i = 0; i != nof_harqs; ++i) { + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_dl.value().is_waiting_ack()); + ASSERT_TRUE(h_ul.has_value()); + ASSERT_TRUE(h_ul.value().is_waiting_ack()); + } + + ASSERT_NE(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_NE(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); + ASSERT_FALSE(harq_ent.has_empty_dl_harqs()); + ASSERT_FALSE(harq_ent.has_empty_ul_harqs()); + + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + ASSERT_FALSE(h_dl.has_value()); + ASSERT_FALSE(h_ul.has_value()); +} + +TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_resources_are_available_again) +{ + unsigned nof_harqs = 16; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + slot_point sl_tx{0, 0}; + unsigned k1 = 4; + for (unsigned i = 0; i != nof_harqs; ++i) { + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + } + + harq_ent.reset(); + harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + for (unsigned i = 0; i != nof_harqs; ++i) { + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + } +} + +TEST_F(single_ue_harq_entity_test, positive_ack_sets_harq_to_empty) +{ + unsigned nof_harqs = 16; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + slot_point sl_tx{0, 0}; + unsigned k1 = 4, k2 = 6; + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx + k2, max_retxs); + ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); - ASSERT_TRUE(h_ul.value().is_waiting_ack()); + + ASSERT_EQ(harq_ent.find_dl_harq(sl_tx + k1, 0), h_dl); + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::ack, 5), dl_harq_process_view::status_update::acked); + ASSERT_FALSE(h_dl.value().has_pending_retx()); + ASSERT_EQ(harq_ent.find_ul_harq(sl_tx + k2), h_ul); + ASSERT_GE(h_ul.value().ul_crc_info(true), 0); ASSERT_FALSE(h_ul.value().has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul); +} + +TEST_F(single_ue_harq_entity_test, negative_ack_sets_harq_to_pending_retx) +{ + unsigned nof_harqs = 16; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + slot_point sl_tx{0, 0}; + unsigned k1 = 4, k2 = 6; + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx + k2, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + + ASSERT_EQ(harq_ent.find_dl_harq(sl_tx + k1, 0), h_dl); + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_TRUE(h_dl.value().has_pending_retx()); + ASSERT_EQ(harq_ent.find_ul_harq(sl_tx + k2), h_ul); + ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); + ASSERT_TRUE(h_ul.value().has_pending_retx()); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), h_dl.value()); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), h_ul.value()); +} + +TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_becomes_empty) +{ + unsigned nof_harqs = 16; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + slot_point sl_tx{0, 0}; + unsigned k1 = 4, k2 = 6; + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(sl_tx + k2, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + for (unsigned i = 0; i != max_retxs; ++i) { + ASSERT_EQ(harq_ent.find_dl_harq(sl_tx + k1, 0), h_dl); + ASSERT_EQ(harq_ent.find_ul_harq(sl_tx + k2), h_ul); + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), + dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); + ASSERT_FALSE(h_dl.value().is_waiting_ack()); + ASSERT_FALSE(h_ul.value().is_waiting_ack()); + ASSERT_TRUE(h_dl.value().has_pending_retx()); + ASSERT_TRUE(h_ul.value().has_pending_retx()); + + ++sl_tx; + h_dl.value().new_retx(sl_tx, k1, 0); + h_ul.value().new_retx(sl_tx + k2); + } + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); + ASSERT_FALSE(h_dl.value().has_pending_retx()); + ASSERT_FALSE(h_ul.value().has_pending_retx()); + ASSERT_FALSE(h_dl.value().is_waiting_ack()); + ASSERT_FALSE(h_ul.value().is_waiting_ack()); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); +} + +TEST_F(single_ue_harq_entity_test, after_max_ack_wait_timeout_dl_harqs_are_available_for_newtx) +{ + const unsigned nof_harqs = 8; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + slot_point sl_tx{0, 0}; + unsigned ack_delay = 4; + + for (unsigned i = 0; i != nof_harqs; ++i) { + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, ack_delay, max_retxs, 0); + ASSERT_TRUE(h_dl.has_value()); + } + for (unsigned i = 0; i != this->max_ack_wait_timeout + ack_delay; ++i) { + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_NE(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_FALSE(harq_ent.has_empty_dl_harqs()); + cell_harqs.slot_indication(++sl_tx); + } + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_TRUE(harq_ent.has_empty_dl_harqs()); + for (unsigned i = 0; i != nof_harqs; ++i) { + auto h_dl = harq_ent.alloc_dl_harq(sl_tx, ack_delay, max_retxs, 0); + ASSERT_TRUE(h_dl.has_value()); + } } From 8f2030d126080b3e5ae323aa98d789e0ef2610c3 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 26 Aug 2024 14:35:55 +0200 Subject: [PATCH 388/407] sched: extend harq_manager_test to cover multi-PUCCH per slot case --- .../ue_scheduling/cell_harq_manager.cpp | 5 + .../ue_scheduling/cell_harq_manager.h | 9 +- .../ue_scheduling/harq_manager_test.cpp | 358 ++++++++++++++++-- 3 files changed, 328 insertions(+), 44 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index cf55ebb1b8..6a0d0ad4d3 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -449,6 +449,11 @@ dl_harq_process_view::status_update dl_harq_process_view::dl_ack_info(mac_harq_a return cell_harq_mng->dl_ack_info(cell_harq_mng->dl.harqs[harq_ref_idx], ack, pucch_snr); } +void dl_harq_process_view::increment_pucch_counter() +{ + ++cell_harq_mng->dl.harqs[harq_ref_idx].pucch_ack_to_receive; +} + void ul_harq_process_view::new_retx(slot_point pusch_slot) { cell_harq_mng->new_ul_retx(cell_harq_mng->ul.harqs[harq_ref_idx], pusch_slot); diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index a15a56c11a..a6f9be4420 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -160,6 +160,9 @@ class cell_harq_manager /// \brief Default timeout in slots after which the HARQ process assumes that the CRC/ACK went missing /// (implementation-defined). constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; + /// \brief Timeout value to use when the HARQ has been ACKed/NACKed, but it is expecting another PUCCH before being + /// cleared (implementation-defined). + constexpr static unsigned SHORT_ACK_TIMEOUT_DTX = 8U; cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, std::unique_ptr notifier = nullptr, @@ -188,10 +191,6 @@ class cell_harq_manager friend class dl_harq_process_view; friend class ul_harq_process_view; - /// \brief Timeout value to use when the HARQ has been ACKed/NACKed, but it is expecting another PUCCH before being - /// cleared (implementation-defined). - constexpr static unsigned SHORT_ACK_TIMEOUT_DTX = 8U; - const static unsigned INVALID_HARQ = std::numeric_limits::max(); void destroy_ue(du_ue_index_t ue_idx); @@ -261,6 +260,8 @@ class dl_harq_process_view /// \return Status update after processing the ACK info. status_update dl_ack_info(mac_harq_ack_report_status ack, std::optional pucch_snr); + void increment_pucch_counter(); + const grant_params& get_grant_params() const { return cell_harq_mng->dl.harqs[harq_ref_idx].prev_tx_params; } bool operator==(const dl_harq_process_view& other) const diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 3950563dd0..04a2769413 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -18,11 +18,15 @@ using namespace srsran; class single_ue_harq_entity_test : public ::testing::Test { protected: + void run_slot() { cell_harqs.slot_indication(++next_slot); } + const unsigned max_ack_wait_timeout = 16; cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; du_ue_index_t ue_index = to_du_ue_index(0); rnti_t rnti = to_rnti(0x4601); unsigned max_retxs = 4; + + slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; }; TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_created_cell_harq_manager_is_updated) @@ -54,10 +58,9 @@ TEST_F(single_ue_harq_entity_test, when_harq_entity_is_created_all_harqs_are_emp TEST_F(single_ue_harq_entity_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) { unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); - slot_point sl_tx{0, 0}; - unsigned k1 = 4; - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + unsigned k1 = 4; + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); ASSERT_TRUE(h_dl.value().is_waiting_ack()); @@ -77,11 +80,10 @@ TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cann ASSERT_EQ(harq_ent.nof_dl_harqs(), nof_harqs); ASSERT_EQ(harq_ent.nof_ul_harqs(), nof_harqs); - slot_point sl_tx{0, 0}; - unsigned k1 = 4; + unsigned k1 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_dl.value().is_waiting_ack()); ASSERT_TRUE(h_ul.has_value()); @@ -95,8 +97,8 @@ TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cann ASSERT_FALSE(harq_ent.has_empty_dl_harqs()); ASSERT_FALSE(harq_ent.has_empty_ul_harqs()); - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); ASSERT_FALSE(h_dl.has_value()); ASSERT_FALSE(h_ul.has_value()); } @@ -105,11 +107,10 @@ TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_ { unsigned nof_harqs = 16; unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - slot_point sl_tx{0, 0}; - unsigned k1 = 4; + unsigned k1 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); } @@ -117,8 +118,8 @@ TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_ harq_ent.reset(); harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); } @@ -128,17 +129,16 @@ TEST_F(single_ue_harq_entity_test, positive_ack_sets_harq_to_empty) { unsigned nof_harqs = 16; unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - slot_point sl_tx{0, 0}; unsigned k1 = 4, k2 = 6; - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); - ASSERT_EQ(harq_ent.find_dl_harq(sl_tx + k1, 0), h_dl); + ASSERT_EQ(harq_ent.find_dl_harq(next_slot + k1, 0), h_dl); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::ack, 5), dl_harq_process_view::status_update::acked); ASSERT_FALSE(h_dl.value().has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq(sl_tx + k2), h_ul); + ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); ASSERT_GE(h_ul.value().ul_crc_info(true), 0); ASSERT_FALSE(h_ul.value().has_pending_retx()); } @@ -147,17 +147,16 @@ TEST_F(single_ue_harq_entity_test, negative_ack_sets_harq_to_pending_retx) { unsigned nof_harqs = 16; unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - slot_point sl_tx{0, 0}; unsigned k1 = 4, k2 = 6; - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); - ASSERT_EQ(harq_ent.find_dl_harq(sl_tx + k1, 0), h_dl); + ASSERT_EQ(harq_ent.find_dl_harq(next_slot + k1, 0), h_dl); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_TRUE(h_dl.value().has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq(sl_tx + k2), h_ul); + ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); ASSERT_TRUE(h_ul.value().has_pending_retx()); ASSERT_EQ(harq_ent.find_pending_dl_retx(), h_dl.value()); @@ -168,15 +167,14 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_becomes_empt { unsigned nof_harqs = 16; unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - slot_point sl_tx{0, 0}; unsigned k1 = 4, k2 = 6; - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(sl_tx + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); for (unsigned i = 0; i != max_retxs; ++i) { - ASSERT_EQ(harq_ent.find_dl_harq(sl_tx + k1, 0), h_dl); - ASSERT_EQ(harq_ent.find_ul_harq(sl_tx + k2), h_ul); + ASSERT_EQ(harq_ent.find_dl_harq(next_slot + k1, 0), h_dl); + ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); @@ -185,9 +183,9 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_becomes_empt ASSERT_TRUE(h_dl.value().has_pending_retx()); ASSERT_TRUE(h_ul.value().has_pending_retx()); - ++sl_tx; - h_dl.value().new_retx(sl_tx, k1, 0); - h_ul.value().new_retx(sl_tx + k2); + run_slot(); + h_dl.value().new_retx(next_slot, k1, 0); + h_ul.value().new_retx(next_slot + k2); } ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); @@ -203,24 +201,304 @@ TEST_F(single_ue_harq_entity_test, after_max_ack_wait_timeout_dl_harqs_are_avail { const unsigned nof_harqs = 8; unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - slot_point sl_tx{0, 0}; - unsigned ack_delay = 4; + unsigned k1 = 4, k2 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, ack_delay, max_retxs, 0); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); } - for (unsigned i = 0; i != this->max_ack_wait_timeout + ack_delay; ++i) { + for (unsigned i = 0; i != this->max_ack_wait_timeout + k1; ++i) { ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); ASSERT_NE(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_NE(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); ASSERT_FALSE(harq_ent.has_empty_dl_harqs()); - cell_harqs.slot_indication(++sl_tx); + ASSERT_FALSE(harq_ent.has_empty_ul_harqs()); + run_slot(); } + run_slot(); ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); ASSERT_TRUE(harq_ent.has_empty_dl_harqs()); + ASSERT_TRUE(harq_ent.has_empty_ul_harqs()); for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(sl_tx, ack_delay, max_retxs, 0); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + } +} + +class single_ue_dl_harq_ack_test : public single_ue_harq_entity_test +{ +protected: + const unsigned nof_harqs = 8; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); +}; + +TEST_F(single_ue_dl_harq_ack_test, when_dtx_received_after_ack_then_dtx_is_ignored) +{ + const unsigned k1 = 4, harq_bit_idx = 0; + + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, nof_harqs, harq_bit_idx); + h_dl->increment_pucch_counter(); + h_dl->increment_pucch_counter(); + slot_point pucch_slot = next_slot + k1; + + while (next_slot != pucch_slot) { + run_slot(); + } + + // ACK received. + auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); + ASSERT_EQ(h_dl, h_dl_ack); + ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), + dl_harq_process_view::status_update::no_update); + + // DTX received one slot late. + run_slot(); + h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); + ASSERT_EQ(h_dl, h_dl_ack); + ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::dtx, std::nullopt), + dl_harq_process_view::status_update::acked); +} + +// Note: When two F1 PUCCHs are decoded (one with SR and the other without), there is a small chance that none of them +// are DTX. +TEST_F(single_ue_dl_harq_ack_test, when_ack_received_after_nack_then_process_becomes_empty) +{ + const unsigned k1 = 4, harq_bit_idx = 0; + + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, nof_harqs, harq_bit_idx); + h_dl->increment_pucch_counter(); + h_dl->increment_pucch_counter(); + slot_point pucch_slot = next_slot + k1; + while (next_slot != pucch_slot) { + run_slot(); + } + + // NACK received. + auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); + ASSERT_EQ(h_dl_ack, h_dl); + ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::nack, 1.0F), + dl_harq_process_view::status_update::no_update); + + // ACK received. + h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); + ASSERT_EQ(h_dl_ack, h_dl); + ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::ack, 2.0F), dl_harq_process_view::status_update::acked); + + // HARQ should be empty. + ASSERT_FALSE(h_dl->is_waiting_ack() or h_dl->has_pending_retx()); +} + +namespace { + +enum harq_state_outcome { ACKed, NACKed, DTX_timeout }; + +struct test_2_harq_bits_params { + // Vector size represents the number of decoded PUCCHs forwarded to the scheduler. + std::vector> ack; + std::array outcome; +}; + +/// \brief With this test suite, we intend to test the scenario where two HARQ bits arrive in a single PUCCH PDU to the +/// scheduler. +class single_ue_harq_entity_2_bits_tester : public ::testing::TestWithParam +{ +protected: + single_ue_harq_entity_2_bits_tester() + { + logger.set_level(srslog::basic_levels::debug); + srslog::init(); + + // Allocate 2 HARQs with same PUCCH slot. + // > First HARQ, DAI=0. + run_slot(); + auto h_dl1 = harq_ent.alloc_dl_harq(next_slot, 5, max_harq_retxs, 0); + h_dl1->increment_pucch_counter(); + h_dls.push_back(h_dl1->id()); + // > Second HARQ, DAI=1. + run_slot(); + auto h_dl2 = harq_ent.alloc_dl_harq(next_slot, 4, max_harq_retxs, 1); + h_dl2->increment_pucch_counter(); + h_dls.push_back(h_dl2->id()); + if (GetParam().ack.size() > 1) { + h_dl1->increment_pucch_counter(); + h_dl2->increment_pucch_counter(); + } + + pucch_slot = next_slot + 4; + + while (next_slot <= pucch_slot + pucch_process_delay) { + run_slot(); + } + } + + ~single_ue_harq_entity_2_bits_tester() override { srslog::flush(); } + + void run_slot() + { + logger.set_context(next_slot.sfn(), next_slot.slot_index()); + cell_harqs.slot_indication(next_slot); + ++next_slot; + } + + const unsigned nof_harqs = 16, max_harq_retxs = 4, pucch_process_delay = 4; + const unsigned max_ack_wait_timeout = 16; + du_ue_index_t ue_index = to_du_ue_index(0); + rnti_t rnti = to_rnti(0x4601); + srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); + cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + + slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; + slot_point pucch_slot; + + std::vector h_dls; +}; + +} // namespace + +TEST_P(single_ue_harq_entity_2_bits_tester, handle_pucchs) +{ + auto params = GetParam(); + + // First PUCCH, 2 HARQ bits, different indexes. + auto h_dl1 = harq_ent.find_dl_harq(pucch_slot, 0); + auto h_dl2 = harq_ent.find_dl_harq(pucch_slot, 1); + h_dl1->dl_ack_info((mac_harq_ack_report_status)params.ack[0][0], std::nullopt); + h_dl2->dl_ack_info((mac_harq_ack_report_status)params.ack[0][1], std::nullopt); + + // Second PUCCH, 2 HARQ bits, different indexes. + if (params.ack.size() > 1) { + h_dl1 = harq_ent.find_dl_harq(pucch_slot, 0); + h_dl2 = harq_ent.find_dl_harq(pucch_slot, 1); + h_dl1->dl_ack_info((mac_harq_ack_report_status)params.ack[1][0], std::nullopt); + h_dl2->dl_ack_info((mac_harq_ack_report_status)params.ack[1][1], std::nullopt); + } + + bool check_timeout = false; + for (unsigned i = 0; i != params.outcome.size(); ++i) { + if (params.outcome[i] == ACKed) { + ASSERT_FALSE(harq_ent.dl_harq(h_dls[i]).has_value()); + } else { + ASSERT_TRUE(harq_ent.dl_harq(h_dls[i]).value().has_pending_retx()); + } + + if (params.outcome[i] == DTX_timeout) { + // DTX_timeout + check_timeout = true; + } + } + + // Check if HARQs timeout in case of HARQ-ACK set to DTX. + if (check_timeout) { + for (unsigned i = 0; i != cell_harq_manager::SHORT_ACK_TIMEOUT_DTX; ++i) { + run_slot(); + } + for (unsigned i = 0; i != params.outcome.size(); ++i) { + if (params.outcome[i] == DTX_timeout) { + ASSERT_TRUE(harq_ent.dl_harq(h_dls[i]).value().has_pending_retx()); + } + } + } +} + +INSTANTIATE_TEST_SUITE_P( + harq_manager_test, + single_ue_harq_entity_2_bits_tester, + testing::Values(test_2_harq_bits_params{.ack = {{1, 1}}, .outcome = {ACKed, ACKed}}, + test_2_harq_bits_params{.ack = {{0, 0}}, .outcome = {NACKed, NACKed}}, + test_2_harq_bits_params{.ack = {{2, 2}}, .outcome = {DTX_timeout, DTX_timeout}}, + test_2_harq_bits_params{.ack = {{2, 1}}, .outcome = {DTX_timeout, ACKed}}, + test_2_harq_bits_params{.ack = {{1, 1}, {2, 2}}, .outcome = {ACKed, ACKed}}, + test_2_harq_bits_params{.ack = {{0, 0}, {2, 2}}, .outcome = {NACKed, NACKed}}, + test_2_harq_bits_params{.ack = {{2, 2}, {2, 1}}, .outcome = {NACKed, ACKed}}, + test_2_harq_bits_params{.ack = {{2, 2}, {2, 2}}, .outcome = {NACKed, NACKed}})); + +class single_ue_harq_entity_harq_5bit_tester : public ::testing::Test +{ +protected: + single_ue_harq_entity_harq_5bit_tester() + { + logger.set_level(srslog::basic_levels::debug); + srslog::init(); + } + + void run_slot() + { + logger.set_context(next_slot.sfn(), next_slot.slot_index()); + cell_harqs.slot_indication(next_slot); + ++next_slot; + } + + const unsigned nof_harqs = 8, max_harq_retxs = 4, pucch_process_delay = 4; + const unsigned max_ack_wait_timeout = 16; + du_ue_index_t ue_index = to_du_ue_index(0); + rnti_t rnti = to_rnti(0x4601); + srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); + + cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + + slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; +}; + +TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_acks_then_all_5_active_harqs_are_updated) +{ + const unsigned active_harqs = 5, k1 = 4; + + std::vector h_dls; + for (unsigned i = 0; i != active_harqs; ++i) { + h_dls.push_back(harq_ent.alloc_dl_harq(next_slot, k1, max_harq_retxs, i)->id()); + } + slot_point pucch_slot = next_slot + k1; + + while (next_slot != pucch_slot) { + run_slot(); + } + + // ACK received. + for (unsigned i = 0; i != active_harqs; ++i) { + auto h_dl = this->harq_ent.find_dl_harq(pucch_slot, i); + ASSERT_EQ(h_dl->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), + dl_harq_process_view::status_update::acked); + } + + for (unsigned i = 0; i != h_dls.size(); ++i) { + auto h_dl = this->harq_ent.dl_harq(h_dls[i]); + ASSERT_FALSE(h_dl.has_value()); + } +} + +TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_nacks_then_all_5_active_harqs_are_updated) +{ + const unsigned active_harqs = 5, k1 = 4; + + std::vector h_dls(active_harqs); + for (unsigned i = 0; i != active_harqs; ++i) { + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_harq_retxs, i); + h_dls.push_back(h_dl->id()); + } + slot_point pucch_slot = next_slot + k1; + + while (next_slot != pucch_slot) { + run_slot(); + } + + // NACK received. + for (unsigned i = 0; i != active_harqs; ++i) { + auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, i); + ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_view::status_update::nacked); + } + + for (unsigned i = 0; i != h_dls.size(); ++i) { + ASSERT_TRUE(this->harq_ent.dl_harq(h_dls[i]).value().has_pending_retx()); } } From 22abff4aaec1bea491db2d0c073878095b15c876 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 26 Aug 2024 18:36:41 +0200 Subject: [PATCH 389/407] sched: extend harq_manager_test to cover all scenarios previously tested in harq_process_test --- .../ue_scheduling/cell_harq_manager.cpp | 91 ++- .../ue_scheduling/cell_harq_manager.h | 127 ++-- .../scheduler/ue_scheduling/CMakeLists.txt | 2 - .../ue_scheduling/harq_entity_test.cpp | 341 --------- .../ue_scheduling/harq_manager_test.cpp | 660 ++++++++++++++---- .../ue_scheduling/harq_process_test.cpp | 291 -------- 6 files changed, 677 insertions(+), 835 deletions(-) delete mode 100644 tests/unittests/scheduler/ue_scheduling/harq_entity_test.cpp diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 6a0d0ad4d3..b73a350bf0 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -9,6 +9,7 @@ */ #include "cell_harq_manager.h" +#include "srsran/scheduler/scheduler_slot_handler.h" using namespace srsran; using namespace harq_utils; @@ -219,9 +220,12 @@ void cell_harq_repository::set_pending_retx(harq_type& h) } template -void cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack) +bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack) { - srsran_assert(h.status == harq_state_t::pending_retx, "Attempt of retx in an HARQ that has no pending retx"); + if (h.status != harq_state_t::pending_retx) { + logger.warning("ue={} h_id={}: Attempt of retx in a HARQ process that has no pending retx", h.ue_idx, h.h_id); + return false; + } // Remove HARQ from pending Retx list. harq_pending_retx_list.pop(&h); @@ -237,6 +241,7 @@ void cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, // Add HARQ to the timeout list. h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); + return true; } template @@ -367,21 +372,24 @@ cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsign return h; } -void cell_harq_manager::new_dl_retx(harq_utils::dl_harq_process_impl& h, +bool cell_harq_manager::new_dl_retx(harq_utils::dl_harq_process_impl& h, slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) { - dl.handle_new_retx(h, pdsch_slot, pdsch_slot + k1); + if (not dl.handle_new_retx(h, pdsch_slot, pdsch_slot + k1)) { + return false; + } h.harq_bit_idx = harq_bit_idx; h.pucch_ack_to_receive = 0; h.chosen_ack = mac_harq_ack_report_status::dtx; h.last_pucch_snr = std::nullopt; + return true; } -void cell_harq_manager::new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot) +bool cell_harq_manager::new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot) { - ul.handle_new_retx(h, pusch_slot, pusch_slot); + return ul.handle_new_retx(h, pusch_slot, pusch_slot); } dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::dl_harq_process_impl& h, @@ -438,25 +446,59 @@ int cell_harq_manager::ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack return ack ? (int)h.prev_tx_params.tbs_bytes : 0; } -void dl_harq_process_view::new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) +bool dl_harq_process_view::new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) { - cell_harq_mng->new_dl_retx(cell_harq_mng->dl.harqs[harq_ref_idx], pdsch_slot, k1, harq_bit_idx); + return cell_harq_mng->new_dl_retx(fetch_impl(), pdsch_slot, k1, harq_bit_idx); } dl_harq_process_view::status_update dl_harq_process_view::dl_ack_info(mac_harq_ack_report_status ack, std::optional pucch_snr) { - return cell_harq_mng->dl_ack_info(cell_harq_mng->dl.harqs[harq_ref_idx], ack, pucch_snr); + return cell_harq_mng->dl_ack_info(fetch_impl(), ack, pucch_snr); } void dl_harq_process_view::increment_pucch_counter() { - ++cell_harq_mng->dl.harqs[harq_ref_idx].pucch_ack_to_receive; + ++fetch_impl().pucch_ack_to_receive; } -void ul_harq_process_view::new_retx(slot_point pusch_slot) +void dl_harq_process_view::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) { - cell_harq_mng->new_ul_retx(cell_harq_mng->ul.harqs[harq_ref_idx], pusch_slot); + srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); + dl_harq_process_impl& impl = fetch_impl(); + srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, + "Setting allocation parameters for DL HARQ process id={} in invalid state", + id()); + + const pdsch_codeword& cw = pdsch.codewords[0]; + dl_harq_process_impl::alloc_params& prev_params = impl.prev_tx_params; + + if (impl.nof_retxs == 0) { + prev_params.tbs_bytes = cw.tb_size_bytes; + prev_params.dci_cfg_type = ctx.dci_cfg_type; + prev_params.olla_mcs = ctx.olla_mcs; + prev_params.slice_id = ctx.slice_id; + } else { + srsran_assert(ctx.dci_cfg_type == prev_params.dci_cfg_type, + "DCI format and RNTI type cannot change during DL HARQ retxs"); + srsran_assert(prev_params.tbs_bytes == cw.tb_size_bytes, + "TBS cannot change during DL HARQ retxs ({}!={}). Previous MCS={}, RBs={}. New MCS={}, RBs={}", + prev_params.tbs_bytes, + cw.tb_size_bytes, + prev_params.mcs, + prev_params.rbs, + cw.mcs_index, + pdsch.rbs); + } + prev_params.mcs_table = cw.mcs_table; + prev_params.mcs = cw.mcs_index; + prev_params.rbs = pdsch.rbs; + prev_params.nof_symbols = pdsch.symbols.length(); +} + +bool ul_harq_process_view::new_retx(slot_point pusch_slot) +{ + return cell_harq_mng->new_ul_retx(cell_harq_mng->ul.harqs[harq_ref_idx], pusch_slot); } int ul_harq_process_view::ul_crc_info(bool ack) @@ -464,6 +506,31 @@ int ul_harq_process_view::ul_crc_info(bool ack) return cell_harq_mng->ul_crc_info(cell_harq_mng->ul.harqs[harq_ref_idx], ack); } +void ul_harq_process_view::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) +{ + ul_harq_process_impl& impl = fetch_impl(); + srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, + "Setting allocation parameters for DL HARQ process id={} in invalid state", + id()); + + ul_harq_process_impl::alloc_params& prev_tx_params = impl.prev_tx_params; + + if (impl.nof_retxs == 0) { + prev_tx_params.dci_cfg_type = ctx.dci_cfg_type; + prev_tx_params.olla_mcs = ctx.olla_mcs; + prev_tx_params.tbs_bytes = pusch.tb_size_bytes; + prev_tx_params.slice_id = ctx.slice_id; + } else { + srsran_assert(ctx.dci_cfg_type == prev_tx_params.dci_cfg_type, + "DCI format and RNTI type cannot change during HARQ retxs"); + srsran_assert(prev_tx_params.tbs_bytes == pusch.tb_size_bytes, "TBS cannot change during HARQ retxs"); + } + prev_tx_params.mcs_table = pusch.mcs_table; + prev_tx_params.mcs = pusch.mcs_index; + prev_tx_params.rbs = pusch.rbs; + prev_tx_params.nof_symbols = pusch.symbols.length(); +} + // UE HARQ entity. unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept : diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index a6f9be4420..7b55efe3b6 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -10,6 +10,7 @@ #pragma once +#include "../slicing/ran_slice_id.h" #include "srsran/adt/intrusive_list.h" #include "srsran/adt/optional.h" #include "srsran/ran/csi_report/csi_report_data.h" @@ -24,6 +25,9 @@ namespace srsran { +struct pdsch_information; +struct pusch_information; + class unique_ue_harq_entity; /// \brief Notifier of HARQ process timeouts. @@ -79,6 +83,8 @@ struct dl_harq_process_impl : public base_harq_process { pdsch_mcs_table mcs_table; sch_mcs_index mcs; unsigned tbs_bytes; + /// RAN slice identifier. + std::optional slice_id; /// \brief MCS originally suggested by the OLLA. It might differ from the actual MCS used. std::optional olla_mcs; }; @@ -99,13 +105,14 @@ struct dl_harq_process_impl : public base_harq_process { struct ul_harq_process_impl : public base_harq_process { /// \brief Parameters relative to the last allocated PUSCH PDU for this HARQ process. struct alloc_params { - dci_ul_rnti_config_type dci_cfg_type; - vrb_alloc rbs; - pusch_mcs_table mcs_table; - sch_mcs_index mcs; - unsigned tbs_bytes; - unsigned nof_symbols; - std::optional olla_mcs; + dci_ul_rnti_config_type dci_cfg_type; + vrb_alloc rbs; + pusch_mcs_table mcs_table; + sch_mcs_index mcs; + unsigned tbs_bytes; + unsigned nof_symbols; + std::optional slice_id; + std::optional olla_mcs; }; /// Parameters used for the last Tx of this HARQ process. @@ -139,21 +146,41 @@ struct cell_harq_repository { unsigned get_harq_ref_idx(const harq_type& h) const; - void slot_indication(slot_point sl_tx); - void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); - harq_type* alloc_harq(du_ue_index_t ue_idx, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); - void dealloc_harq(harq_type& h); - void handle_ack(harq_type& h, bool ack); - void set_pending_retx(harq_type& h); - void handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack); - void reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs); - void destroy_ue_harqs(du_ue_index_t ue_idx); - void cancel_retxs(harq_type& h); - unsigned find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; + void slot_indication(slot_point sl_tx); + void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); + harq_type* alloc_harq(du_ue_index_t ue_idx, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); + void dealloc_harq(harq_type& h); + void handle_ack(harq_type& h, bool ack); + void set_pending_retx(harq_type& h); + [[nodiscard]] bool handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack); + void reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs); + void destroy_ue_harqs(du_ue_index_t ue_idx); + void cancel_retxs(harq_type& h); + unsigned find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; }; } // namespace harq_utils +/// \brief Context of the scheduler during the current PDSCH allocation. +struct dl_harq_sched_context { + /// DCI format used to signal the PDSCH allocation. + dci_dl_rnti_config_type dci_cfg_type; + /// MCS suggested by the OLLA. + std::optional olla_mcs; + /// RAN slice identifier of the slice to which PDSCH belongs to. + std::optional slice_id; +}; + +/// \brief Context of the scheduler during the current PUSCH allocation. +struct ul_harq_sched_context { + /// DCI format used to signal the PUSCH allocation. + dci_ul_rnti_config_type dci_cfg_type; + /// MCS suggested by the OLLA. + std::optional olla_mcs; + /// RAN slice identifier of the slice to which PUSCH belongs to. + std::optional slice_id; +}; + class cell_harq_manager { public: @@ -206,10 +233,11 @@ class cell_harq_manager harq_utils::ul_harq_process_impl* new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsigned max_harq_nof_retxs); /// \brief Called on a new retx of a DL HARQ process. - void new_dl_retx(harq_utils::dl_harq_process_impl& h, slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); + [[nodiscard]] bool + new_dl_retx(harq_utils::dl_harq_process_impl& h, slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); /// \brief Called on a new retx of a UL HARQ process. - void new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot); + [[nodiscard]] bool new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot); /// Updates a DL HARQ process given the received HARQ-ACK info. harq_utils::dl_harq_process_impl::status_update @@ -241,18 +269,15 @@ class dl_harq_process_view "Empty HARQ process created"); } - harq_id_t id() const { return cell_harq_mng->dl.harqs[harq_ref_idx].h_id; } - - bool is_waiting_ack() const + harq_id_t id() const { return fetch_impl().h_id; } + bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } + bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } + bool empty() const { - return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack; - } - bool has_pending_retx() const - { - return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx; + return harq_ref_idx == cell_harq_manager::INVALID_HARQ or fetch_impl().status == harq_utils::harq_state_t::empty; } - void new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); + [[nodiscard]] bool new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); /// \brief Update the state of the DL HARQ process waiting for an HARQ-ACK. /// \param[in] ack HARQ-ACK status received. @@ -262,7 +287,17 @@ class dl_harq_process_view void increment_pucch_counter(); - const grant_params& get_grant_params() const { return cell_harq_mng->dl.harqs[harq_ref_idx].prev_tx_params; } + /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that + /// they can be later fetched and optionally reused. + void save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch); + + slot_point pdsch_slot() const { return fetch_impl().slot_tx; } + slot_point uci_slot() const { return fetch_impl().slot_ack; } + unsigned max_nof_retxs() const { return fetch_impl().max_nof_harq_retxs; } + unsigned nof_retxs() const { return fetch_impl().nof_retxs; } + bool ndi() const { return fetch_impl().ndi; } + + const grant_params& get_grant_params() const { return fetch_impl().prev_tx_params; } bool operator==(const dl_harq_process_view& other) const { @@ -271,6 +306,9 @@ class dl_harq_process_view bool operator!=(const dl_harq_process_view& other) const { return !(*this == other); } private: + harq_utils::dl_harq_process_impl& fetch_impl() { return cell_harq_mng->dl.harqs[harq_ref_idx]; } + const harq_utils::dl_harq_process_impl& fetch_impl() const { return cell_harq_mng->dl.harqs[harq_ref_idx]; } + cell_harq_manager* cell_harq_mng = nullptr; unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; }; @@ -281,27 +319,29 @@ class ul_harq_process_view ul_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) { - srsran_sanity_check(cell_harq_mng->ul.harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty, - "Empty HARQ process created"); + srsran_sanity_check(fetch_impl().status != harq_utils::harq_state_t::empty, "Empty HARQ process created"); } - harq_id_t id() const { return cell_harq_mng->ul.harqs[harq_ref_idx].h_id; } + harq_id_t id() const { return fetch_impl().h_id; } - bool is_waiting_ack() const - { - return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack; - } - bool has_pending_retx() const - { - return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx; - } + bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } + bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } - void new_retx(slot_point pusch_slot); + [[nodiscard]] bool new_retx(slot_point pusch_slot); /// Update UL HARQ state given the received CRC indication. /// \return Transport Block size of the HARQ whose state was updated. int ul_crc_info(bool ack); + /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that + /// they can be later fetched and optionally reused. + void save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pdsch); + + slot_point pusch_slot() const { return fetch_impl().slot_tx; } + unsigned max_nof_retxs() const { return fetch_impl().max_nof_harq_retxs; } + unsigned nof_retxs() const { return fetch_impl().nof_retxs; } + bool ndi() const { return fetch_impl().ndi; } + bool operator==(const ul_harq_process_view& other) const { return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx; @@ -309,6 +349,9 @@ class ul_harq_process_view bool operator!=(const ul_harq_process_view& other) const { return !(*this == other); } private: + harq_utils::ul_harq_process_impl& fetch_impl() { return cell_harq_mng->ul.harqs[harq_ref_idx]; } + const harq_utils::ul_harq_process_impl& fetch_impl() const { return cell_harq_mng->ul.harqs[harq_ref_idx]; } + cell_harq_manager* cell_harq_mng = nullptr; unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; }; diff --git a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt index 7bd0f215f9..3c91bf54a6 100644 --- a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt +++ b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt @@ -9,7 +9,6 @@ add_executable(ue_scheduler_test logical_channel_test.cpp harq_manager_test.cpp - harq_entity_test.cpp harq_process_test.cpp fallback_scheduler_test.cpp ue_cell_test.cpp @@ -28,5 +27,4 @@ target_link_libraries(ue_scheduler_test sched_config gtest gtest_main) -gtest_discover_tests(ue_scheduler_test) add_test(ue_scheduler_test ue_scheduler_test) diff --git a/tests/unittests/scheduler/ue_scheduling/harq_entity_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_entity_test.cpp deleted file mode 100644 index ec1d8f7e3b..0000000000 --- a/tests/unittests/scheduler/ue_scheduling/harq_entity_test.cpp +++ /dev/null @@ -1,341 +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 "lib/scheduler/ue_scheduling/harq_process.h" -#include "srsran/support/test_utils.h" -#include - -using namespace srsran; - -TEST(harq_entity, when_harq_entity_is_created_all_harqs_are_empty) -{ - harq_entity harq_ent(to_rnti(0x4601), 16, 16, {}, 4); - - ASSERT_EQ(harq_ent.nof_dl_harqs(), 16); - ASSERT_EQ(harq_ent.nof_ul_harqs(), 16); - ASSERT_NE(harq_ent.find_empty_dl_harq(), nullptr); - ASSERT_TRUE(harq_ent.find_empty_dl_harq()->empty()); - ASSERT_NE(harq_ent.find_empty_ul_harq(), nullptr); - ASSERT_TRUE(harq_ent.find_empty_ul_harq()->empty()); - ASSERT_EQ(harq_ent.find_pending_dl_retx(), nullptr); - ASSERT_EQ(harq_ent.find_pending_ul_retx(), nullptr); -} - -TEST(harq_entity, when_all_harqs_are_allocated_harq_entity_cannot_find_empty_harq) -{ - unsigned nof_harqs = 8; - harq_entity harq_ent(to_rnti(0x4601), nof_harqs, nof_harqs, {}, 4); - slot_point sl_tx{0, 0}; - unsigned ack_delay = 4; - - for (unsigned i = 0; i != nof_harqs; ++i) { - harq_ent.find_empty_dl_harq()->new_tx(sl_tx, ack_delay, 4, 0, 15, 1); - harq_ent.find_empty_ul_harq()->new_tx(sl_tx, 4); - } - ASSERT_EQ(harq_ent.find_empty_dl_harq(), nullptr); - ASSERT_EQ(harq_ent.find_empty_ul_harq(), nullptr); -} - -TEST(harq_entity, after_max_ack_wait_timeout_dl_harqs_are_available_for_newtx) -{ - unsigned nof_harqs = 8, max_ack_wait_slots = 4; - harq_entity harq_ent(to_rnti(0x4601), nof_harqs, nof_harqs, {}, 0, max_ack_wait_slots); - slot_point sl_tx{0, 0}; - unsigned ack_delay = 4; - - for (unsigned i = 0; i != nof_harqs; ++i) { - harq_ent.find_empty_dl_harq()->new_tx(sl_tx, ack_delay, 4, 0, 15, 1); - } - for (unsigned i = 0; i != max_ack_wait_slots + ack_delay; ++i) { - ASSERT_EQ(harq_ent.find_empty_dl_harq(), nullptr); - ASSERT_EQ(harq_ent.find_pending_dl_retx(), nullptr); - harq_ent.slot_indication(++sl_tx); - } - ASSERT_EQ(harq_ent.find_pending_dl_retx(), nullptr); - ASSERT_NE(harq_ent.find_empty_dl_harq(), nullptr); -} - -class harq_entity_harq_1bit_tester : public ::testing::Test -{ -protected: - harq_entity_harq_1bit_tester() - { - logger.set_level(srslog::basic_levels::debug); - srslog::init(); - } - - void run_slot() - { - logger.set_context(next_slot.sfn(), next_slot.slot_index()); - harq_ent.slot_indication(next_slot); - ++next_slot; - } - - const unsigned nof_harqs = 8, max_harq_retxs = 4, pucch_process_delay = 4; - harq_entity harq_ent{to_rnti(0x4601), nof_harqs, nof_harqs, {}}; - - srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); - - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; - - dl_harq_process& h_dl{*harq_ent.find_empty_dl_harq()}; -}; - -TEST_F(harq_entity_harq_1bit_tester, when_dtx_received_after_ack_then_dtx_is_ignored) -{ - const unsigned k1 = 4, dai = 0; - - this->h_dl.new_tx(next_slot, k1, max_harq_retxs, dai, 15, 1); - this->h_dl.increment_pucch_counter(); - this->h_dl.increment_pucch_counter(); - slot_point pucch_slot = next_slot + k1; - - while (next_slot != pucch_slot) { - run_slot(); - } - - // ACK received. - auto result = this->harq_ent.dl_ack_info(pucch_slot, mac_harq_ack_report_status::ack, dai, std::nullopt); - ASSERT_TRUE(result.has_value()); - ASSERT_EQ(result->h_id, this->h_dl.id); - ASSERT_EQ(result->update, dl_harq_process::status_update::no_update); - - // DTX received one slot late. - run_slot(); - result = this->harq_ent.dl_ack_info(pucch_slot, mac_harq_ack_report_status::dtx, dai, std::nullopt); - ASSERT_TRUE(result.has_value()); - ASSERT_EQ(result->h_id, this->h_dl.id); - ASSERT_EQ(result->update, dl_harq_process::status_update::acked); -} - -// Note: When two F1 PUCCHs are decoded (one with SR and the other without), there is a small chance that none of them -// are DTX. -TEST_F(harq_entity_harq_1bit_tester, when_ack_received_after_nack_then_process_becomes_empty) -{ - const unsigned k1 = 4, dai = 0; - - this->h_dl.new_tx(next_slot, k1, max_harq_retxs, dai, 15, 1); - this->h_dl.increment_pucch_counter(); - this->h_dl.increment_pucch_counter(); - slot_point pucch_slot = next_slot + k1; - - while (next_slot != pucch_slot) { - run_slot(); - } - - // NACK received. - auto result = this->harq_ent.dl_ack_info(pucch_slot, mac_harq_ack_report_status::nack, dai, 1.0F); - ASSERT_TRUE(result.has_value()); - ASSERT_EQ(result->h_id, this->h_dl.id); - ASSERT_EQ(result->update, dl_harq_process::status_update::no_update); - - // ACK received. - result = this->harq_ent.dl_ack_info(pucch_slot, srsran::mac_harq_ack_report_status::ack, dai, 2.0F); - ASSERT_TRUE(result.has_value()); - ASSERT_EQ(result->h_id, this->h_dl.id); - ASSERT_EQ(result->update, dl_harq_process::status_update::acked); - - // HARQ should be empty. - ASSERT_TRUE(this->h_dl.empty()); -} - -enum harq_state_outcome { ACKed, NACKed, DTX_timeout }; - -struct test_2_harq_bits_params { - // Vector size represents the number of decoded PUCCHs forwarded to the scheduler. - std::vector> ack; - std::array outcome; -}; - -/// \brief With this test suite, we intend to test the scenario where two HARQ bits arrive in a single PUCCH PDU to the -/// scheduler. -class harq_entity_2_harq_bits_tester : public ::testing::TestWithParam -{ -protected: - harq_entity_2_harq_bits_tester() - { - logger.set_level(srslog::basic_levels::debug); - srslog::init(); - - // Allocate 2 HARQs with same PUCCH slot. - // > First HARQ, DAI=0. - run_slot(); - h_dls.push_back(harq_ent.find_empty_dl_harq()); - h_dls[0]->new_tx(next_slot, 5, max_harq_retxs, 0, 15, 1); - h_dls[0]->increment_pucch_counter(); - // > Second HARQ, DAI=1. - run_slot(); - h_dls.push_back(harq_ent.find_empty_dl_harq()); - h_dls[1]->new_tx(next_slot, 4, max_harq_retxs, 1, 15, 1); - h_dls[1]->increment_pucch_counter(); - if (GetParam().ack.size() > 1) { - h_dls[0]->increment_pucch_counter(); - h_dls[1]->increment_pucch_counter(); - } - - pucch_slot = next_slot + 4; - - while (next_slot <= pucch_slot + pucch_process_delay) { - run_slot(); - } - } - - ~harq_entity_2_harq_bits_tester() { srslog::flush(); } - - void run_slot() - { - logger.set_context(next_slot.sfn(), next_slot.slot_index()); - harq_ent.slot_indication(next_slot); - ++next_slot; - } - - const unsigned nof_harqs = 8, max_harq_retxs = 4, pucch_process_delay = 4; - harq_entity harq_ent{to_rnti(0x4601), nof_harqs, nof_harqs, {}}; - srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); - - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; - slot_point pucch_slot; - - std::vector h_dls; -}; - -TEST_P(harq_entity_2_harq_bits_tester, handle_pucchs) -{ - auto params = GetParam(); - - // First PUCCH, 2 HARQ bits, different indexes. - harq_ent.dl_ack_info(pucch_slot, (mac_harq_ack_report_status)params.ack[0][0], 0, std::nullopt); - harq_ent.dl_ack_info(pucch_slot, (mac_harq_ack_report_status)params.ack[0][1], 1, std::nullopt); - - // Second PUCCH, 2 HARQ bits, different indexes. - if (params.ack.size() > 1) { - harq_ent.dl_ack_info(pucch_slot, (mac_harq_ack_report_status)params.ack[1][0], 0, std::nullopt); - harq_ent.dl_ack_info(pucch_slot, (mac_harq_ack_report_status)params.ack[1][1], 1, std::nullopt); - } - - bool check_timeout = false; - for (unsigned i = 0; i != params.outcome.size(); ++i) { - if (params.outcome[i] == ACKed) { - ASSERT_TRUE(h_dls[i]->empty()); - } else { - ASSERT_TRUE(h_dls[i]->has_pending_retx()); - } - - if (params.outcome[i] == DTX_timeout) { - // DTX_timeout - check_timeout = true; - } - } - - // Check if HARQs timeout in case of HARQ-ACK set to DTX. - if (check_timeout) { - for (unsigned i = 0; i != dl_harq_process::SHORT_ACK_TIMEOUT_DTX; ++i) { - run_slot(); - } - for (unsigned i = 0; i != params.outcome.size(); ++i) { - if (params.outcome[i] == DTX_timeout) { - ASSERT_TRUE(h_dls[i]->has_pending_retx()); - } - } - } -} - -INSTANTIATE_TEST_SUITE_P( - harq_entity_tester, - harq_entity_2_harq_bits_tester, - testing::Values(test_2_harq_bits_params{.ack = {{1, 1}}, .outcome = {ACKed, ACKed}}, - test_2_harq_bits_params{.ack = {{0, 0}}, .outcome = {NACKed, NACKed}}, - test_2_harq_bits_params{.ack = {{2, 2}}, .outcome = {DTX_timeout, DTX_timeout}}, - test_2_harq_bits_params{.ack = {{2, 1}}, .outcome = {DTX_timeout, ACKed}}, - test_2_harq_bits_params{.ack = {{1, 1}, {2, 2}}, .outcome = {ACKed, ACKed}}, - test_2_harq_bits_params{.ack = {{0, 0}, {2, 2}}, .outcome = {NACKed, NACKed}}, - test_2_harq_bits_params{.ack = {{2, 2}, {2, 1}}, .outcome = {NACKed, ACKed}}, - test_2_harq_bits_params{.ack = {{2, 2}, {2, 2}}, .outcome = {NACKed, NACKed}})); - -class harq_entity_harq_5bit_tester : public ::testing::Test -{ -protected: - harq_entity_harq_5bit_tester() - { - logger.set_level(srslog::basic_levels::debug); - srslog::init(); - } - - void run_slot() - { - logger.set_context(next_slot.sfn(), next_slot.slot_index()); - harq_ent.slot_indication(next_slot); - ++next_slot; - } - - const unsigned nof_harqs = 8, max_harq_retxs = 4, pucch_process_delay = 4; - harq_entity harq_ent{to_rnti(0x4601), nof_harqs, nof_harqs, {}}; - - srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); - - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; -}; - -TEST_F(harq_entity_harq_5bit_tester, when_5_harq_bits_are_acks_then_all_5_active_harqs_are_updated) -{ - const unsigned active_harqs = 5, k1 = 4; - - std::vector h_dls(active_harqs); - for (unsigned i = 0; i != active_harqs; ++i) { - h_dls[i] = harq_ent.find_empty_dl_harq(); - h_dls[i]->new_tx(next_slot, k1, max_harq_retxs, i, 15, 1); - } - slot_point pucch_slot = next_slot + k1; - - while (next_slot != pucch_slot) { - run_slot(); - } - - // ACK received. - for (unsigned i = 0; i != active_harqs; ++i) { - auto result = this->harq_ent.dl_ack_info(pucch_slot, srsran::mac_harq_ack_report_status::ack, i, std::nullopt); - ASSERT_TRUE(result.has_value()); - ASSERT_NE(result->h_id, INVALID_HARQ_ID); - ASSERT_EQ(result->update, dl_harq_process::status_update::acked); - } - - for (unsigned i = 0; i != h_dls.size(); ++i) { - ASSERT_TRUE(h_dls[i]->empty()); - } -} - -TEST_F(harq_entity_harq_5bit_tester, when_5_harq_bits_are_nacks_then_all_5_active_harqs_are_updated) -{ - const unsigned active_harqs = 5, k1 = 4; - - std::vector h_dls(active_harqs); - for (unsigned i = 0; i != active_harqs; ++i) { - h_dls[i] = harq_ent.find_empty_dl_harq(); - h_dls[i]->new_tx(next_slot, k1, max_harq_retxs, i, 15, 1); - } - slot_point pucch_slot = next_slot + k1; - - while (next_slot != pucch_slot) { - run_slot(); - } - - // NACK received. - for (unsigned i = 0; i != active_harqs; ++i) { - auto result = this->harq_ent.dl_ack_info(pucch_slot, srsran::mac_harq_ack_report_status::nack, i, std::nullopt); - ASSERT_TRUE(result.has_value()); - ASSERT_NE(result->h_id, INVALID_HARQ_ID); - ASSERT_EQ(result->update, dl_harq_process::status_update::nacked); - } - - for (unsigned i = 0; i != h_dls.size(); ++i) { - ASSERT_FALSE(h_dls[i]->empty()); - ASSERT_TRUE(h_dls[i]->has_pending_retx()); - } -} diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 04a2769413..437904b83c 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -9,78 +9,529 @@ */ #include "lib/scheduler/ue_scheduling/cell_harq_manager.h" +#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/test_utils.h" #include using namespace srsran; -/// Test for a single UE HARQ entity. -class single_ue_harq_entity_test : public ::testing::Test +namespace { + +// Generate random PUCCH SNR value. +float random_snr() +{ + return static_cast(std::uniform_real_distribution{-20.0F, 30.0F}(test_rgen::get())); +} + +mac_harq_ack_report_status get_random_harq_ack() +{ + return static_cast(test_rgen::uniform_int(0, 2)); +} + +pdsch_information make_dummy_pdsch_info() +{ + pdsch_information pdsch; + pdsch.codewords.resize(1); + pdsch.codewords[0].mcs_table = srsran::pdsch_mcs_table::qam64; + pdsch.codewords[0].mcs_index = 10; + pdsch.codewords[0].tb_size_bytes = 10000; + pdsch.rbs = vrb_interval{5, 10}; + return pdsch; +} + +pusch_information make_dummy_pusch_info() +{ + pusch_information pusch; + pusch.mcs_table = pusch_mcs_table::qam64; + pusch.mcs_index = 10; + pusch.tb_size_bytes = 10000; + pusch.rbs = vrb_interval{5, 10}; + return pusch; +} + +// Dummy HARQ timeout recorder +class dummy_harq_timeout_handler +{ +public: + du_ue_index_t last_ue_index = INVALID_DU_UE_INDEX; + bool last_dir_is_dl = false; + bool last_was_ack = false; + + void handle_harq_timeout(du_ue_index_t ue_index, bool is_dl, bool ack) + { + last_ue_index = ue_index; + last_dir_is_dl = is_dl; + last_was_ack = ack; + } + + std::unique_ptr make_notifier() + { + class dummy_notifier : public harq_timeout_notifier + { + public: + dummy_notifier(dummy_harq_timeout_handler& parent_) : parent(parent_) {} + + void on_harq_timeout(du_ue_index_t ue_index, bool is_dl, bool ack) override + { + parent.handle_harq_timeout(ue_index, is_dl, ack); + } + + private: + dummy_harq_timeout_handler& parent; + }; + + return std::make_unique(*this); + } +}; + +// Base test class that instantiates a cell HARQ manager. +class base_harq_manager_test { protected: - void run_slot() { cell_harqs.slot_indication(++next_slot); } + base_harq_manager_test(unsigned nof_ues) : cell_harqs(nof_ues, timeout_handler.make_notifier(), max_ack_wait_timeout) + { + } + + const unsigned max_ack_wait_timeout = 16; + dummy_harq_timeout_handler timeout_handler; - const unsigned max_ack_wait_timeout = 16; - cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; - du_ue_index_t ue_index = to_du_ue_index(0); - rnti_t rnti = to_rnti(0x4601); - unsigned max_retxs = 4; + cell_harq_manager cell_harqs; slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; }; -TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_created_cell_harq_manager_is_updated) +class base_single_harq_entity_test : public base_harq_manager_test { - ASSERT_FALSE(cell_harqs.contains(ue_index)); - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); - ASSERT_TRUE(cell_harqs.contains(ue_index)); - harq_ent.reset(); - ASSERT_FALSE(cell_harqs.contains(ue_index)); +protected: + base_single_harq_entity_test() : base_harq_manager_test(1) {} + + void run_slot() + { + ++next_slot; + srslog::fetch_basic_logger("SCHED").set_context(next_slot.sfn(), next_slot.slot_index()); + cell_harqs.slot_indication(next_slot); + } + + const du_ue_index_t ue_index = to_du_ue_index(0); + const rnti_t rnti = to_rnti(0x4601); + const unsigned nof_harqs = 8; + unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); + + unsigned max_retxs = 4; + unsigned k1 = 4; + unsigned k2 = 6; +}; + +} // namespace + +// Test for multiple UEs managed by a single HARQ manager instance. +class multi_ue_harq_manager_test : public base_harq_manager_test, public ::testing::Test +{ +protected: + multi_ue_harq_manager_test() : base_harq_manager_test(max_ues) {} + + constexpr static unsigned max_ues = 4; + const unsigned nof_harqs = 8; +}; + +// Test for a single UE HARQ entity. +class single_ue_harq_entity_test : public base_single_harq_entity_test, public ::testing::Test +{}; + +// Test suite for a single HARQ process. +class single_harq_process_test : public base_single_harq_entity_test, public ::testing::Test +{ +protected: + single_harq_process_test() + { + pdsch_info = make_dummy_pdsch_info(); + dl_harq_sched_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; + h_dl.save_grant_params(harq_ctxt, pdsch_info); + pusch_info = make_dummy_pusch_info(); + ul_harq_sched_context ul_harq_ctxt{dci_ul_rnti_config_type::c_rnti_f0_0}; + h_ul.save_grant_params(ul_harq_ctxt, pusch_info); + } + + pdsch_information pdsch_info; + pusch_information pusch_info; + dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value()}; + ul_harq_process_view h_ul{harq_ent.alloc_ul_harq(next_slot + k2, max_retxs).value()}; +}; + +class dl_harq_process_multi_pucch_test : public base_single_harq_entity_test, public ::testing::Test +{ +protected: + dl_harq_process_multi_pucch_test() + { + // Expect two PUCCHs. + h_dl.increment_pucch_counter(); + h_dl.increment_pucch_counter(); + } + + dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value()}; +}; + +// Parameters of test with 2 PUCCHs - dl_harq_process_two_pucch_param_test +struct two_ack_test_params { + std::array ack; + std::array snr; + bool outcome; +}; + +void PrintTo(const two_ack_test_params& params, ::std::ostream* os) +{ + *os << fmt::format("{{ack={} snr={:.2}}} + {{ack={} snr={:.2}}} -> outcome={}", + params.ack[0], + params.snr[0], + params.ack[1], + params.snr[1], + params.outcome ? "ACK" : "NACK"); +} + +class dl_harq_process_two_pucch_param_test : public base_single_harq_entity_test, + public ::testing::TestWithParam +{ +protected: + dl_harq_process_two_pucch_param_test() + { + // Expect two PUCCHs. + h_dl.increment_pucch_counter(); + h_dl.increment_pucch_counter(); + } + + dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value()}; +}; + +// HARQ process tests + +TEST_F(single_harq_process_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) +{ + ASSERT_TRUE(h_dl.is_waiting_ack()); + ASSERT_TRUE(h_ul.is_waiting_ack()); + ASSERT_FALSE(h_dl.has_pending_retx()); + ASSERT_FALSE(h_ul.has_pending_retx()); +} + +TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_params_have_correct_values) +{ + ASSERT_EQ(h_dl.pdsch_slot(), next_slot); + ASSERT_EQ(h_dl.uci_slot(), next_slot + k1); + ASSERT_EQ(h_dl.max_nof_retxs(), max_retxs); + ASSERT_EQ(h_dl.nof_retxs(), 0); + ASSERT_EQ(h_ul.pusch_slot(), next_slot + k2); + ASSERT_EQ(h_ul.max_nof_retxs(), max_retxs); + ASSERT_EQ(h_ul.nof_retxs(), 0); +} + +TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_grant_params_have_correct_values) +{ + ASSERT_EQ(h_dl.get_grant_params().mcs, pdsch_info.codewords[0].mcs_index); + ASSERT_EQ(h_dl.get_grant_params().mcs_table, pdsch_info.codewords[0].mcs_table); + ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); + ASSERT_EQ(h_dl.get_grant_params().rbs.type1(), pdsch_info.rbs.type1()); + ASSERT_EQ(h_dl.get_grant_params().dci_cfg_type, dci_dl_rnti_config_type::c_rnti_f1_0); +} + +TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) +{ + float pucch_snr = 5; + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_FALSE(h_dl.is_waiting_ack()); + ASSERT_FALSE(h_dl.has_pending_retx()); + ASSERT_EQ(h_ul.ul_crc_info(true), pusch_info.tb_size_bytes); + ASSERT_FALSE(h_ul.is_waiting_ack()); + ASSERT_FALSE(h_ul.has_pending_retx()); +} + +TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) +{ + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_FALSE(h_dl.is_waiting_ack()); + ASSERT_TRUE(h_dl.has_pending_retx()); + ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); + ASSERT_EQ(h_ul.ul_crc_info(false), 0); + ASSERT_FALSE(h_ul.is_waiting_ack()); + ASSERT_TRUE(h_ul.has_pending_retx()); +} + +TEST_F(single_harq_process_test, ack_of_empty_harq_is_failure) +{ + float pucch_snr = 5; + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_GE(h_ul.ul_crc_info(true), 0); + + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::error); + ASSERT_LT(h_ul.ul_crc_info(true), 0); +} + +TEST_F(single_harq_process_test, retx_of_empty_harq_is_failure) +{ + float pucch_snr = 5; + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_GE(h_ul.ul_crc_info(true), 0); + + ASSERT_FALSE(h_dl.new_retx(next_slot, k1, 0)); + ASSERT_FALSE(h_ul.new_retx(next_slot + k2)); +} + +TEST_F(single_harq_process_test, retx_of_harq_waiting_ack_is_failure) +{ + ASSERT_FALSE(h_dl.new_retx(next_slot, k1, 0)); + ASSERT_FALSE(h_ul.new_retx(next_slot + k2)); +} + +TEST_F(single_harq_process_test, when_max_retxs_reached_then_harq_becomes_empty) +{ + bool old_dl_ndi = h_dl.ndi(); + bool old_ul_ndi = h_ul.ndi(); + for (unsigned i = 0; i != max_retxs; ++i) { + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_ul.ul_crc_info(false), 0); + ASSERT_FALSE(h_dl.is_waiting_ack()); + ASSERT_FALSE(h_ul.is_waiting_ack()); + ASSERT_TRUE(h_dl.has_pending_retx()); + ASSERT_TRUE(h_ul.has_pending_retx()); + + run_slot(); + ASSERT_TRUE(h_dl.new_retx(next_slot, k1, 0)); + ASSERT_TRUE(h_ul.new_retx(next_slot + k2)); + ASSERT_EQ(h_dl.nof_retxs(), i + 1); + ASSERT_EQ(h_ul.nof_retxs(), i + 1); + ASSERT_NE(old_dl_ndi, h_dl.ndi()); + ASSERT_NE(old_ul_ndi, h_ul.ndi()); + old_dl_ndi = h_dl.ndi(); + old_ul_ndi = h_dl.ndi(); + } + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_ul.ul_crc_info(false), 0); + ASSERT_FALSE(h_dl.has_pending_retx()); + ASSERT_FALSE(h_ul.has_pending_retx()); + ASSERT_FALSE(h_dl.is_waiting_ack()); + ASSERT_FALSE(h_ul.is_waiting_ack()); +} + +TEST_F(single_harq_process_test, when_newtx_after_ack_then_ndi_flips) +{ + float pucch_snr = 5; + bool dl_ndi = h_dl.ndi(), ul_ndi = h_ul.ndi(); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_GE(h_ul.ul_crc_info(true), 0); + + h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value(); + h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs).value(); + ASSERT_EQ(h_dl.nof_retxs(), 0); + ASSERT_EQ(h_ul.nof_retxs(), 0); + ASSERT_NE(dl_ndi, h_dl.ndi()); + ASSERT_NE(ul_ndi, h_ul.ndi()); +} + +TEST_F(single_harq_process_test, when_ack_wait_timeout_reached_then_harq_is_available_for_newtx) +{ + harq_id_t h_dl_id = h_dl.id(), h_ul_id = h_ul.id(); + bool dl_ndi = h_dl.ndi(), ul_ndi = h_ul.ndi(); + for (unsigned i = 0; i != this->max_ack_wait_timeout + k1; ++i) { + ASSERT_TRUE(h_dl.is_waiting_ack() and not h_dl.has_pending_retx()); + ASSERT_TRUE(h_ul.is_waiting_ack() and not h_ul.has_pending_retx()); + run_slot(); + } + // Note: k1 < k2, so there is an intermediate state where h_dl timed out but h_ul didn't. + ASSERT_TRUE(not h_dl.is_waiting_ack() and not h_dl.has_pending_retx()); + ASSERT_FALSE(harq_ent.dl_harq(h_dl_id).has_value()); + for (unsigned i = 0; i != (k2 - k1); ++i) { + ASSERT_TRUE(h_ul.is_waiting_ack() and not h_ul.has_pending_retx()); + run_slot(); + } + ASSERT_TRUE(not h_ul.is_waiting_ack() and not h_ul.has_pending_retx()); + ASSERT_FALSE(harq_ent.ul_harq(h_ul_id).has_value()); + + h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs - 1, 0).value(); + h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs - 1).value(); + ASSERT_TRUE(h_dl.is_waiting_ack() and not h_dl.has_pending_retx()); + ASSERT_TRUE(h_ul.is_waiting_ack() and not h_ul.has_pending_retx()); + ASSERT_EQ(h_dl.nof_retxs(), 0); + ASSERT_EQ(h_dl.max_nof_retxs(), max_retxs - 1); + ASSERT_EQ(h_ul.nof_retxs(), 0); + ASSERT_EQ(h_ul.max_nof_retxs(), max_retxs - 1); + if (h_dl.id() == h_dl_id) { + ASSERT_NE(dl_ndi, h_dl.ndi()); + } + if (h_ul.id() == h_ul_id) { + ASSERT_NE(ul_ndi, h_ul.ndi()); + } +} + +// DL HARQ process with multi PUCCH test + +TEST_F(dl_harq_process_multi_pucch_test, when_dtx_received_after_ack_then_dtx_is_ignored) +{ + slot_point pucch_slot = next_slot + k1; + while (next_slot != pucch_slot) { + run_slot(); + } + + // ACK received. + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), + dl_harq_process_view::status_update::no_update); + + // DTX received one slot late. + run_slot(); + ASSERT_TRUE(h_dl.is_waiting_ack()); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::dtx, std::nullopt), + dl_harq_process_view::status_update::acked); } +// Note: When two F1 PUCCHs are decoded (one with SR and the other without), there is a small chance that none of them +// are DTX. +TEST_F(dl_harq_process_multi_pucch_test, when_stronger_ack_received_after_nack_then_process_becomes_empty) +{ + slot_point pucch_slot = next_slot + k1; + while (next_slot != pucch_slot) { + run_slot(); + } + + // NACK received. + harq_id_t h_id = h_dl.id(); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 1.0F), dl_harq_process_view::status_update::no_update); + + // ACK received. + ASSERT_EQ(harq_ent.dl_harq(h_id), h_dl); + ASSERT_TRUE(h_dl.is_waiting_ack()); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, 2.0F), dl_harq_process_view::status_update::acked); + + // HARQ should be empty. + ASSERT_FALSE(harq_ent.dl_harq(h_id).has_value()); +} + +TEST_F(dl_harq_process_multi_pucch_test, + when_one_harq_ack_is_received_and_other_goes_missing_then_harq_timeout_is_shortened) +{ + const mac_harq_ack_report_status ack_val = get_random_harq_ack(); + const unsigned first_ack_slot = 1; + + for (unsigned i = 0; i != this->max_ack_wait_timeout + k1 + 1; ++i) { + // Notify HARQ process with DTX (ACK not decoded). + if (i == first_ack_slot) { + ASSERT_EQ(h_dl.dl_ack_info(ack_val, random_snr()), dl_harq_process_view::status_update::no_update); + } + + // Before reaching the ack_wait_slots, the HARQ should be neither empty nor have pending reTX. + if (i < cell_harq_manager::SHORT_ACK_TIMEOUT_DTX + first_ack_slot) { + ASSERT_FALSE(h_dl.has_pending_retx()); + ASSERT_TRUE(h_dl.is_waiting_ack()); + ASSERT_EQ(timeout_handler.last_ue_index, INVALID_DU_UE_INDEX); + } + // Once the shortened_ack_wait_slots has passed, expect HARQ to be reset. + else { + ASSERT_TRUE(h_dl.empty()); + ASSERT_EQ(timeout_handler.last_ue_index, to_du_ue_index(0)); + ASSERT_TRUE(timeout_handler.last_dir_is_dl); + if (ack_val == srsran::mac_harq_ack_report_status::ack) { + ASSERT_TRUE(timeout_handler.last_was_ack); + } else { + // In case of NACK/DTX, the HARQ should report the timeout. + ASSERT_FALSE(timeout_handler.last_was_ack); + } + break; + } + run_slot(); + } +} + +TEST_P(dl_harq_process_two_pucch_param_test, two_harq_acks_received) +{ + auto params = GetParam(); + unsigned first_ack_slot = 1, second_ack_slot = 2; + + for (unsigned i = 0; i != max_ack_wait_timeout + k1 + 1; ++i) { + if (i == first_ack_slot) { + ASSERT_EQ(h_dl.dl_ack_info(static_cast(params.ack[0]), params.snr[0]), + dl_harq_process_view::status_update::no_update); + } + if (i == second_ack_slot) { + ASSERT_EQ(h_dl.dl_ack_info(static_cast(params.ack[1]), params.snr[1]), + params.outcome ? dl_harq_process_view::status_update::acked + : dl_harq_process_view::status_update::nacked); + } + + if (i < second_ack_slot) { + // Before second HARQ-ACK, the process is waiting for an ACK. + ASSERT_TRUE(h_dl.is_waiting_ack()); + } else { + // When second HARQ-ACK arrives, the process should be set as either empty or pending reTX. + ASSERT_FALSE(h_dl.is_waiting_ack()); + if (params.outcome) { + ASSERT_TRUE(h_dl.empty()); + } else { + ASSERT_TRUE(h_dl.has_pending_retx()); + } + break; + } + run_slot(); + } + + ASSERT_EQ(timeout_handler.last_ue_index, INVALID_DU_UE_INDEX) << "Timeout should not expire"; +} + +INSTANTIATE_TEST_SUITE_P( + dl_harq_process_test, + dl_harq_process_two_pucch_param_test, + testing::Values(two_ack_test_params{.ack = {2, 1}, .snr = {random_snr(), random_snr()}, .outcome = true}, + two_ack_test_params{.ack = {1, 2}, .snr = {random_snr(), random_snr()}, .outcome = true}, + two_ack_test_params{.ack = {2, 0}, .snr = {random_snr(), random_snr()}, .outcome = false}, + two_ack_test_params{.ack = {0, 2}, .snr = {random_snr(), random_snr()}, .outcome = false}, + two_ack_test_params{.ack = {0, 1}, .snr = {10.0, 11.0}, .outcome = true}, + two_ack_test_params{.ack = {0, 1}, .snr = {10.0, 9.0}, .outcome = false}, + two_ack_test_params{.ack = {2, 2}, .snr = {random_snr(), random_snr()}, .outcome = false}, + two_ack_test_params{.ack = {0, 0}, .snr = {random_snr(), random_snr()}, .outcome = false}, + two_ack_test_params{.ack = {1, 1}, .snr = {random_snr(), random_snr()}, .outcome = true})); + +// HARQ entity tests + TEST_F(single_ue_harq_entity_test, when_harq_entity_is_created_all_harqs_are_empty) { - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); - ASSERT_EQ(harq_ent.nof_dl_harqs(), 16); - ASSERT_EQ(harq_ent.nof_ul_harqs(), 16); + ASSERT_EQ(harq_ent.nof_dl_harqs(), this->nof_harqs); + ASSERT_EQ(harq_ent.nof_ul_harqs(), this->nof_harqs); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); ASSERT_TRUE(harq_ent.has_empty_dl_harqs()); ASSERT_TRUE(harq_ent.has_empty_ul_harqs()); - for (unsigned i = 0; i != 16; ++i) { + for (unsigned i = 0; i != harq_ent.nof_dl_harqs(); ++i) { ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(i)).has_value()); ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(i)).has_value()); } } -TEST_F(single_ue_harq_entity_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) +TEST_F(single_ue_harq_entity_test, when_harq_is_allocated_then_harq_entity_finds_harq_in_waiting_ack_state) { - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16); - unsigned k1 = 4; - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); - ASSERT_TRUE(h_dl.value().is_waiting_ack()); - ASSERT_TRUE(h_ul.value().is_waiting_ack()); - ASSERT_FALSE(h_dl.value().has_pending_retx()); - ASSERT_FALSE(h_ul.value().has_pending_retx()); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl); ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul); ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); } +TEST_F(single_ue_harq_entity_test, when_harq_is_nacked_then_harq_entity_finds_harq_with_pending_retx) +{ + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), h_dl); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), h_ul); +} + TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cannot_find_empty_harq) { - unsigned nof_harqs = 4; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); ASSERT_EQ(harq_ent.nof_dl_harqs(), nof_harqs); ASSERT_EQ(harq_ent.nof_ul_harqs(), nof_harqs); - unsigned k1 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); @@ -105,9 +556,6 @@ TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cann TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_resources_are_available_again) { - unsigned nof_harqs = 16; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - unsigned k1 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); @@ -125,51 +573,10 @@ TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_ } } -TEST_F(single_ue_harq_entity_test, positive_ack_sets_harq_to_empty) +TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_entity_does_not_find_pending_retx) { - unsigned nof_harqs = 16; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - unsigned k1 = 4, k2 = 6; - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); - ASSERT_TRUE(h_dl.has_value()); - ASSERT_TRUE(h_ul.has_value()); - - ASSERT_EQ(harq_ent.find_dl_harq(next_slot + k1, 0), h_dl); - ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::ack, 5), dl_harq_process_view::status_update::acked); - ASSERT_FALSE(h_dl.value().has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); - ASSERT_GE(h_ul.value().ul_crc_info(true), 0); - ASSERT_FALSE(h_ul.value().has_pending_retx()); -} - -TEST_F(single_ue_harq_entity_test, negative_ack_sets_harq_to_pending_retx) -{ - unsigned nof_harqs = 16; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - unsigned k1 = 4, k2 = 6; - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); - ASSERT_TRUE(h_dl.has_value()); - ASSERT_TRUE(h_ul.has_value()); - - ASSERT_EQ(harq_ent.find_dl_harq(next_slot + k1, 0), h_dl); - ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); - ASSERT_TRUE(h_dl.value().has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); - ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); - ASSERT_TRUE(h_ul.value().has_pending_retx()); - ASSERT_EQ(harq_ent.find_pending_dl_retx(), h_dl.value()); - ASSERT_EQ(harq_ent.find_pending_ul_retx(), h_ul.value()); -} - -TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_becomes_empty) -{ - unsigned nof_harqs = 16; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - unsigned k1 = 4, k2 = 6; - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); for (unsigned i = 0; i != max_retxs; ++i) { @@ -178,31 +585,30 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_becomes_empt ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); - ASSERT_FALSE(h_dl.value().is_waiting_ack()); - ASSERT_FALSE(h_ul.value().is_waiting_ack()); - ASSERT_TRUE(h_dl.value().has_pending_retx()); - ASSERT_TRUE(h_ul.value().has_pending_retx()); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), h_dl); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), h_ul); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); run_slot(); - h_dl.value().new_retx(next_slot, k1, 0); - h_ul.value().new_retx(next_slot + k2); + ASSERT_TRUE(h_dl.value().new_retx(next_slot, k1, 0)); + ASSERT_TRUE(h_ul.value().new_retx(next_slot + k2)); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul); + ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); + ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); } ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); - ASSERT_FALSE(h_dl.value().has_pending_retx()); - ASSERT_FALSE(h_ul.value().has_pending_retx()); - ASSERT_FALSE(h_dl.value().is_waiting_ack()); - ASSERT_FALSE(h_ul.value().is_waiting_ack()); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); } TEST_F(single_ue_harq_entity_test, after_max_ack_wait_timeout_dl_harqs_are_available_for_newtx) { - const unsigned nof_harqs = 8; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - unsigned k1 = 4, k2 = 4; - + k2 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); @@ -233,6 +639,22 @@ TEST_F(single_ue_harq_entity_test, after_max_ack_wait_timeout_dl_harqs_are_avail } } +TEST_F(multi_ue_harq_manager_test, when_ue_harq_entity_is_created_or_reset_then_cell_harq_manager_is_updated) +{ + for (unsigned i = 0; i != this->max_ues; ++i) { + ASSERT_FALSE(cell_harqs.contains(to_du_ue_index(i))); + } + std::vector harq_ents; + for (unsigned i = 0; i != this->max_ues; ++i) { + harq_ents.push_back(cell_harqs.add_ue(to_du_ue_index(i), to_rnti(0x4601 + i), nof_harqs, nof_harqs)); + ASSERT_TRUE(cell_harqs.contains(to_du_ue_index(i))); + } + for (unsigned i = 0; i != this->max_ues; ++i) { + harq_ents[i].reset(); + ASSERT_FALSE(cell_harqs.contains(to_du_ue_index(i))); + } +} + class single_ue_dl_harq_ack_test : public single_ue_harq_entity_test { protected: @@ -240,62 +662,6 @@ class single_ue_dl_harq_ack_test : public single_ue_harq_entity_test unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); }; -TEST_F(single_ue_dl_harq_ack_test, when_dtx_received_after_ack_then_dtx_is_ignored) -{ - const unsigned k1 = 4, harq_bit_idx = 0; - - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, nof_harqs, harq_bit_idx); - h_dl->increment_pucch_counter(); - h_dl->increment_pucch_counter(); - slot_point pucch_slot = next_slot + k1; - - while (next_slot != pucch_slot) { - run_slot(); - } - - // ACK received. - auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); - ASSERT_EQ(h_dl, h_dl_ack); - ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), - dl_harq_process_view::status_update::no_update); - - // DTX received one slot late. - run_slot(); - h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); - ASSERT_EQ(h_dl, h_dl_ack); - ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::dtx, std::nullopt), - dl_harq_process_view::status_update::acked); -} - -// Note: When two F1 PUCCHs are decoded (one with SR and the other without), there is a small chance that none of them -// are DTX. -TEST_F(single_ue_dl_harq_ack_test, when_ack_received_after_nack_then_process_becomes_empty) -{ - const unsigned k1 = 4, harq_bit_idx = 0; - - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, nof_harqs, harq_bit_idx); - h_dl->increment_pucch_counter(); - h_dl->increment_pucch_counter(); - slot_point pucch_slot = next_slot + k1; - while (next_slot != pucch_slot) { - run_slot(); - } - - // NACK received. - auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); - ASSERT_EQ(h_dl_ack, h_dl); - ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::nack, 1.0F), - dl_harq_process_view::status_update::no_update); - - // ACK received. - h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, harq_bit_idx); - ASSERT_EQ(h_dl_ack, h_dl); - ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::ack, 2.0F), dl_harq_process_view::status_update::acked); - - // HARQ should be empty. - ASSERT_FALSE(h_dl->is_waiting_ack() or h_dl->has_pending_retx()); -} - namespace { enum harq_state_outcome { ACKed, NACKed, DTX_timeout }; diff --git a/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp index 793ed2c503..9aeb652abf 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp @@ -15,19 +15,6 @@ using namespace srsran; -class dummy_harq_timeout_handler : public harq_timeout_handler -{ -public: - du_ue_index_t last_ue_index = INVALID_DU_UE_INDEX; - bool last_dir_is_dl = false; - - void handle_harq_timeout(du_ue_index_t ue_index, bool is_dl) override - { - last_ue_index = ue_index; - last_dir_is_dl = is_dl; - } -}; - /// Tester for different combinations of max HARQ retxs, ack wait timeouts, and k1s. class dl_harq_process_tester : public ::testing::Test { @@ -62,87 +49,6 @@ TEST_F(dl_harq_process_tester, reset_of_empty_harq_is_no_op) ASSERT_FALSE(h_dl.has_pending_retx(0)); } -TEST_F(dl_harq_process_tester, newtx_set_harq_to_not_empty) -{ - slot_point sl_tx{0, 0}; - vrb_interval vrbs{5, 10}; - unsigned k1 = 4, max_harq_retxs = 5, tbs_bytes = 1000; - sch_mcs_index mcs = 10; - - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - ASSERT_FALSE(h_dl.empty()); - ASSERT_FALSE(h_dl.empty(0)); - ASSERT_TRUE(h_dl.empty(1)); - ASSERT_EQ(h_dl.slot_tx(), sl_tx); - ASSERT_EQ(h_dl.slot_ack(), sl_tx + k1); - ASSERT_EQ(h_dl.tb(0).nof_retxs, 0); - ASSERT_EQ(h_dl.tb(0).max_nof_harq_retxs, max_harq_retxs); - - pdsch_information pdsch; - pdsch.codewords.resize(1); - pdsch.codewords[0].mcs_table = srsran::pdsch_mcs_table::qam64; - pdsch.codewords[0].mcs_index = mcs; - pdsch.codewords[0].tb_size_bytes = tbs_bytes; - pdsch.rbs = vrbs; - dl_harq_sched_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; - h_dl.save_alloc_params(harq_ctxt, pdsch); - ASSERT_EQ(h_dl.last_alloc_params().dci_cfg_type, dci_dl_rnti_config_type::c_rnti_f1_0); - ASSERT_EQ(h_dl.last_alloc_params().rbs.type1(), vrbs); - ASSERT_EQ(h_dl.last_alloc_params().tb[0]->mcs, mcs); - ASSERT_EQ(h_dl.last_alloc_params().tb[0]->tbs_bytes, tbs_bytes); -} - -#ifdef ASSERTS_ENABLED -TEST_F(dl_harq_process_tester, retx_of_empty_harq_asserts) -{ - (void)(::testing::GTEST_FLAG(death_test_style) = "threadsafe"); - slot_point sl_tx{0, 0}; - ASSERT_DEATH(h_dl.new_retx(sl_tx, 4, 0), ".*") << "Retxing an empty HARQ should assert"; -} -#endif - -TEST_F(dl_harq_process_tester, ack_of_empty_harq_is_failure) -{ - ASSERT_EQ(h_dl.ack_info(0, mac_harq_ack_report_status::ack, std::nullopt), dl_harq_process::status_update::error) - << "ACK of empty HARQ should fail"; -} - -class dl_harq_process_timeout_tester : public dl_harq_process_tester -{ -protected: - dl_harq_process_timeout_tester() : dl_harq_process_tester(1) {} -}; - -TEST_F(dl_harq_process_timeout_tester, when_max_retx_exceeded_and_nack_is_received_harq_becomes_empty) -{ - unsigned k1 = 1, max_harq_retxs = 1; - slot_point sl_tx{0, 0}; - - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - h_dl.slot_indication(++sl_tx); - ASSERT_FALSE(h_dl.has_pending_retx(0)); - ASSERT_EQ(h_dl.ack_info(0, mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process::status_update::nacked); - h_dl.new_retx(sl_tx, k1, 0); - h_dl.slot_indication(++sl_tx); - ASSERT_EQ(h_dl.ack_info(0, mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process::status_update::nacked); - ASSERT_TRUE(h_dl.empty()); - ASSERT_FALSE(h_dl.has_pending_retx()); -} - -#ifdef ASSERTS_ENABLED -TEST_F(dl_harq_process_timeout_tester, when_harq_has_no_pending_retx_calling_newtx_or_retx_asserts) -{ - (void)(::testing::GTEST_FLAG(death_test_style) = "threadsafe"); - unsigned k1 = 1, max_harq_retxs = 1; - slot_point sl_tx{0, 0}; - - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - ASSERT_TRUE(not h_dl.empty(0) and not h_dl.has_pending_retx(0)); - ASSERT_DEATH(h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1), ".*"); - ASSERT_DEATH(h_dl.new_retx(sl_tx, k1, 0), ".*"); -} -#endif - /// Tester for different combinations of max HARQ retxs, ack wait timeouts, and k1s. class dl_harq_process_param_tester : public ::testing::TestWithParam> { @@ -175,205 +81,8 @@ class dl_harq_process_param_tester : public ::testing::TestWithParammax_ack_wait_slots + this->k1; ++i) { - ASSERT_FALSE(h_dl.empty()) << "It is too early for HARQ to be reset"; - ASSERT_FALSE(h_dl.has_pending_retx()) << "It is too early for HARQ to be available for retx"; - ASSERT_EQ(h_dl.tb(0).nof_retxs, 0); - slot_indication(); - } - - ASSERT_TRUE(h_dl.empty()) << "HARQ should be automatically reset once max HARQ retxs is achieved"; - - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - ASSERT_FALSE(h_dl.empty()) << "It should be possible to reuse the HARQ"; - ASSERT_NE(h_dl.tb(0).ndi, ndi) << "NDI should have been toggled"; - ASSERT_EQ(h_dl.tb(0).nof_retxs, 0) << "nof_retxs() has not been updated"; -} - -TEST_P(dl_harq_process_param_tester, harq_newtxs_flip_ndi) -{ - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - for (unsigned i = 0; i != this->max_ack_wait_slots + k1 - 1; ++i) { - ASSERT_FALSE(h_dl.empty()); - ASSERT_FALSE(h_dl.has_pending_retx()); - slot_indication(); - } - - bool prev_ndi = h_dl.tb(0).ndi; - ASSERT_EQ(h_dl.ack_info(0, mac_harq_ack_report_status::ack, std::nullopt), dl_harq_process::status_update::acked); - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - ASSERT_NE(prev_ndi, h_dl.tb(0).ndi); -} - INSTANTIATE_TEST_SUITE_P(dl_harq_param_combine, dl_harq_process_param_tester, testing::Combine(testing::Values(0, 1, 2, 4), // max_retxs testing::Values(2, 4, 6, 8), // max_ack_wait_slots testing::Values(1, 2, 4, 6))); // k1 - -class base_dl_harq_process_multi_harq_ack_test -{ -public: - base_dl_harq_process_multi_harq_ack_test() : - dl_logger(srslog::fetch_basic_logger("SCHED"), to_rnti(0x4601), to_du_cell_index(0), true), - h_dl(to_harq_id(0), dl_logger, {timeout_handler, to_du_ue_index(0)}, max_ack_wait_slots) - { - srslog::init(); - - // Allocate HARQ expecting two PUCCHs. - h_dl.new_tx(sl_tx, k1, max_harq_retxs, 0, 15, 1); - h_dl.increment_pucch_counter(); - h_dl.increment_pucch_counter(); - } - ~base_dl_harq_process_multi_harq_ack_test() { srslog::flush(); } - - void slot_indication() - { - ++sl_tx; - srslog::fetch_basic_logger("SCHED").set_context(sl_tx.sfn(), sl_tx.slot_index()); - h_dl.slot_indication(sl_tx); - } - - static mac_harq_ack_report_status get_random_harq_ack() - { - return static_cast(test_rgen::uniform_int(0, 2)); - } - - const unsigned max_harq_retxs = 1; - const unsigned max_ack_wait_slots = 12; - const unsigned shortened_ack_wait_slots{8}; - const unsigned k1 = 1; - const unsigned first_ack_slot = 1; - const unsigned second_ack_slot = 2; - - harq_logger dl_logger; - dummy_harq_timeout_handler timeout_handler; - dl_harq_process h_dl; - slot_point sl_tx{0, 0}; -}; - -static float random_snr() -{ - return static_cast(std::uniform_real_distribution{-20.0F, 30.0F}(test_rgen::get())); -} - -class dl_harq_process_multi_harq_ack_timeout_test : public base_dl_harq_process_multi_harq_ack_test, - public ::testing::Test -{}; - -TEST_F(dl_harq_process_multi_harq_ack_timeout_test, - when_one_harq_ack_is_received_and_other_goes_missing_then_harq_timeout_is_shortened) -{ - const mac_harq_ack_report_status ack_val = get_random_harq_ack(); - - for (unsigned i = 0; i != max_ack_wait_slots + k1 + 1; ++i) { - // Notify HARQ process with DTX (ACK not decoded). - if (i == first_ack_slot) { - ASSERT_EQ(h_dl.ack_info(0, ack_val, random_snr()), dl_harq_process::status_update::no_update); - } - - // Before reaching the ack_wait_slots, the HARQ should be neither empty nor have pending reTX. - if (i < shortened_ack_wait_slots + k1) { - ASSERT_FALSE(h_dl.empty()); - ASSERT_FALSE(h_dl.has_pending_retx()); - ASSERT_TRUE(h_dl.is_waiting_ack()); - ASSERT_EQ(timeout_handler.last_ue_index, INVALID_DU_UE_INDEX); - } - // Once the shortened_ack_wait_slots has passed, expect HARQ to be reset. - else { - ASSERT_TRUE(h_dl.empty()); - if (ack_val == srsran::mac_harq_ack_report_status::ack) { - ASSERT_NE(timeout_handler.last_ue_index, to_du_ue_index(0)); - } else { - // In case of NACK/DTX, the HARQ should report the timeout. - ASSERT_EQ(timeout_handler.last_ue_index, to_du_ue_index(0)); - ASSERT_TRUE(timeout_handler.last_dir_is_dl); - } - break; - } - slot_indication(); - } -} - -struct multi_ack_test_params { - std::array ack; - std::array snr; - bool outcome; -}; - -void PrintTo(const multi_ack_test_params& params, ::std::ostream* os) -{ - *os << fmt::format("{{ack={} snr={:.2}}} + {{ack={} snr={:.2}}} -> outcome={}", - params.ack[0], - params.snr[0], - params.ack[1], - params.snr[1], - params.outcome ? "ACK" : "NACK"); -} - -class dl_harq_process_multi_harq_ack_test : public base_dl_harq_process_multi_harq_ack_test, - public ::testing::TestWithParam -{}; - -TEST_P(dl_harq_process_multi_harq_ack_test, two_harq_acks_received) -{ - auto params = GetParam(); - - for (unsigned i = 0; i != max_ack_wait_slots + k1 + 1; ++i) { - if (i == first_ack_slot) { - ASSERT_EQ(h_dl.ack_info(0, static_cast(params.ack[0]), params.snr[0]), - dl_harq_process::status_update::no_update); - } - if (i == second_ack_slot) { - ASSERT_EQ(h_dl.ack_info(0, static_cast(params.ack[1]), params.snr[1]), - params.outcome ? dl_harq_process::status_update::acked : dl_harq_process::status_update::nacked); - } - - if (i < second_ack_slot) { - // Before second HARQ-ACK, the process is waiting for an ACK. - ASSERT_TRUE(h_dl.is_waiting_ack()); - } else { - // When second HARQ-ACK arrives, the process should be set as either empty or pending reTX. - ASSERT_FALSE(h_dl.is_waiting_ack()); - if (params.outcome) { - ASSERT_TRUE(h_dl.empty()); - } else { - ASSERT_TRUE(h_dl.has_pending_retx()); - } - break; - } - slot_indication(); - } - - ASSERT_EQ(timeout_handler.last_ue_index, INVALID_DU_UE_INDEX) << "Timeout should not expire"; -} - -INSTANTIATE_TEST_SUITE_P( - dl_harq_process_tester, - dl_harq_process_multi_harq_ack_test, - testing::Values(multi_ack_test_params{.ack = {2, 1}, .snr = {random_snr(), random_snr()}, .outcome = true}, - multi_ack_test_params{.ack = {1, 2}, .snr = {random_snr(), random_snr()}, .outcome = true}, - multi_ack_test_params{.ack = {2, 0}, .snr = {random_snr(), random_snr()}, .outcome = false}, - multi_ack_test_params{.ack = {0, 2}, .snr = {random_snr(), random_snr()}, .outcome = false}, - multi_ack_test_params{.ack = {0, 1}, .snr = {10.0, 11.0}, .outcome = true}, - multi_ack_test_params{.ack = {0, 1}, .snr = {10.0, 9.0}, .outcome = false}, - multi_ack_test_params{.ack = {2, 2}, .snr = {random_snr(), random_snr()}, .outcome = false}, - multi_ack_test_params{.ack = {0, 0}, .snr = {random_snr(), random_snr()}, .outcome = false}, - multi_ack_test_params{.ack = {1, 1}, .snr = {random_snr(), random_snr()}, .outcome = true})); From 01da77d45748d0cc78fcee019f2fc56bb0319c8b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 10:38:11 +0200 Subject: [PATCH 390/407] sched: log rnti in harq manager and improve tests --- .../ue_scheduling/cell_harq_manager.cpp | 58 +-- .../ue_scheduling/cell_harq_manager.h | 24 +- .../ue_scheduling/harq_manager_test.cpp | 338 ++++++++---------- 3 files changed, 203 insertions(+), 217 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index b73a350bf0..22995c5653 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -70,21 +70,21 @@ void cell_harq_repository::handle_harq_ack_timeout(harq_type& h, slot_poin // Only in non-NTN case, we log a warning. if (h.ack_on_timeout) { // Case: Not all HARQ-ACKs were received, but at least one positive ACK was received. - logger.debug("ue={} h_id={}: Setting {} HARQ to \"ACKed\" state. Cause: HARQ-ACK wait timeout ({} slots) was " + logger.debug("rnti={} h_id={}: Setting {} HARQ to \"ACKed\" state. Cause: HARQ-ACK wait timeout ({} slots) was " "reached with still missing PUCCH HARQ-ACKs. However, one positive ACK was received.", - h.ue_idx, + h.rnti, h.h_id, IsDl ? "DL" : "UL", h.slot_ack_timeout - h.slot_ack); } else { // At least one of the expected ACKs went missing and we haven't received any positive ACK. - logger.warning( - "ue={} h_id={}: Discarding {} HARQ. Cause: HARQ-ACK wait timeout ({} slots) was reached, but there are still " - "missing HARQ-ACKs and none of the received ones are positive.", - h.ue_idx, - h.h_id, - IsDl ? "DL" : "UL", - h.slot_ack_timeout - h.slot_ack); + logger.warning("rnti={} h_id={}: Discarding {} HARQ. Cause: HARQ-ACK wait timeout ({} slots) was reached, but " + "there are still " + "missing HARQ-ACKs and none of the received ones are positive.", + h.rnti, + h.h_id, + IsDl ? "DL" : "UL", + h.slot_ack_timeout - h.slot_ack); } // Report timeout with NACK. @@ -103,6 +103,7 @@ unsigned cell_harq_repository::get_harq_ref_idx(const harq_type& h) const template typename cell_harq_repository::harq_type* cell_harq_repository::alloc_harq(du_ue_index_t ue_idx, + rnti_t rnti, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs) @@ -124,6 +125,7 @@ typename cell_harq_repository::harq_type* cell_harq_repository::allo // Set allocated HARQ common params. h.ue_idx = ue_idx; + h.rnti = rnti; h.h_id = h_id; h.status = harq_state_t::waiting_ack; h.slot_tx = sl_tx; @@ -174,16 +176,16 @@ void cell_harq_repository::handle_ack(harq_type& h, bool ack) { if (not ack and h.nof_retxs >= h.max_nof_harq_retxs) { if (h.retxs_cancelled) { - logger.info( - "ue={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Retxs for this HARQ process were cancelled", - h.ue_idx, - h.h_id, - IsDl ? "DL" : "UL", - h.prev_tx_params.tbs_bytes); + logger.info("rnti={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Retxs for this HARQ process were " + "cancelled", + h.rnti, + h.h_id, + IsDl ? "DL" : "UL", + h.prev_tx_params.tbs_bytes); } else { logger.info( - "ue={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Maximum number of reTxs {} exceeded", - h.ue_idx, + "rnti={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Maximum number of reTxs {} exceeded", + h.rnti, h.h_id, IsDl ? "DL" : "UL", h.prev_tx_params.tbs_bytes, @@ -223,7 +225,7 @@ template bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack) { if (h.status != harq_state_t::pending_retx) { - logger.warning("ue={} h_id={}: Attempt of retx in a HARQ process that has no pending retx", h.ue_idx, h.h_id); + logger.warning("rnti={} h_id={}: Attempt of retx in a HARQ process that has no pending retx", h.rnti, h.h_id); return false; } @@ -338,12 +340,13 @@ void cell_harq_manager::destroy_ue(du_ue_index_t ue_idx) } harq_utils::dl_harq_process_impl* cell_harq_manager::new_dl_tx(du_ue_index_t ue_idx, + rnti_t rnti, slot_point pdsch_slot, unsigned k1, unsigned max_harq_nof_retxs, uint8_t harq_bit_idx) { - dl_harq_process_impl* h = dl.alloc_harq(ue_idx, pdsch_slot, pdsch_slot + k1, max_harq_nof_retxs); + dl_harq_process_impl* h = dl.alloc_harq(ue_idx, rnti, pdsch_slot, pdsch_slot + k1, max_harq_nof_retxs); if (h == nullptr) { return nullptr; } @@ -359,9 +362,9 @@ harq_utils::dl_harq_process_impl* cell_harq_manager::new_dl_tx(du_ue_index_t ue_ } harq_utils::ul_harq_process_impl* -cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsigned max_harq_nof_retxs) +cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs) { - ul_harq_process_impl* h = ul.alloc_harq(ue_idx, pusch_slot, pusch_slot, max_harq_nof_retxs); + ul_harq_process_impl* h = ul.alloc_harq(ue_idx, rnti, pusch_slot, pusch_slot, max_harq_nof_retxs); if (h == nullptr) { return nullptr; } @@ -400,7 +403,7 @@ dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::d if (h.status != harq_state_t::waiting_ack) { // If the HARQ process is not expecting an HARQ-ACK, it means that it has already been ACKed/NACKed. - logger.warning("ue={} h_id={}: ACK arrived for inactive DL HARQ", h.ue_idx, h.h_id); + logger.warning("rnti={} h_id={}: ACK arrived for inactive DL HARQ", h.rnti, h.h_id); return status_update::error; } @@ -437,7 +440,7 @@ int cell_harq_manager::ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack { if (h.status != harq_state_t::waiting_ack) { // HARQ is not expecting CRC info. - logger.warning("ue={} h_id={}: CRC arrived for UL HARQ not expecting it", h.ue_idx, h.h_id); + logger.warning("rnti={} h_id={}: CRC arrived for UL HARQ not expecting it", h.rnti, h.h_id); return -1; } @@ -533,6 +536,11 @@ void ul_harq_process_view::save_grant_params(const ul_harq_sched_context& ctx, c // UE HARQ entity. +unique_ue_harq_entity::unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_) : + cell_harq_mgr(mgr), ue_index(ue_idx), crnti(crnti_) +{ +} + unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept : cell_harq_mgr(other.cell_harq_mgr), ue_index(other.ue_index) { @@ -570,7 +578,7 @@ void unique_ue_harq_entity::reset() std::optional unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx) { - dl_harq_process_impl* h = cell_harq_mgr->new_dl_tx(ue_index, sl_tx, k1, max_harq_nof_retxs, harq_bit_idx); + dl_harq_process_impl* h = cell_harq_mgr->new_dl_tx(ue_index, crnti, sl_tx, k1, max_harq_nof_retxs, harq_bit_idx); if (h == nullptr) { return std::nullopt; } @@ -579,7 +587,7 @@ unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max std::optional unique_ue_harq_entity::alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs) { - ul_harq_process_impl* h = cell_harq_mgr->new_ul_tx(ue_index, sl_tx, max_harq_nof_retxs); + ul_harq_process_impl* h = cell_harq_mgr->new_ul_tx(ue_index, crnti, sl_tx, max_harq_nof_retxs); if (h == nullptr) { return std::nullopt; } diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index 7b55efe3b6..8d5365420d 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -50,6 +50,7 @@ enum class harq_state_t { empty, pending_retx, waiting_ack }; /// Parameters that are common to DL and UL HARQ processes. struct base_harq_process : public intrusive_double_linked_list_element<> { du_ue_index_t ue_idx; + rnti_t rnti; harq_id_t h_id; harq_state_t status = harq_state_t::empty; slot_point slot_tx; @@ -146,12 +147,13 @@ struct cell_harq_repository { unsigned get_harq_ref_idx(const harq_type& h) const; - void slot_indication(slot_point sl_tx); - void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); - harq_type* alloc_harq(du_ue_index_t ue_idx, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); - void dealloc_harq(harq_type& h); - void handle_ack(harq_type& h, bool ack); - void set_pending_retx(harq_type& h); + void slot_indication(slot_point sl_tx); + void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); + harq_type* + alloc_harq(du_ue_index_t ue_idx, rnti_t rnti, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); + void dealloc_harq(harq_type& h); + void handle_ack(harq_type& h, bool ack); + void set_pending_retx(harq_type& h); [[nodiscard]] bool handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack); void reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs); void destroy_ue_harqs(du_ue_index_t ue_idx); @@ -224,13 +226,15 @@ class cell_harq_manager /// \brief Called on every DL new Tx to allocate an DL HARQ process. harq_utils::dl_harq_process_impl* new_dl_tx(du_ue_index_t ue_idx, + rnti_t rnti, slot_point pdsch_slot, unsigned k1, unsigned max_harq_nof_retxs, uint8_t harq_bit_idx); /// \brief Called on every UL new Tx to allocate an UL HARQ process. - harq_utils::ul_harq_process_impl* new_ul_tx(du_ue_index_t ue_idx, slot_point pusch_slot, unsigned max_harq_nof_retxs); + harq_utils::ul_harq_process_impl* + new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs); /// \brief Called on a new retx of a DL HARQ process. [[nodiscard]] bool @@ -360,11 +364,7 @@ class unique_ue_harq_entity { public: unique_ue_harq_entity() = default; - unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_) : - cell_harq_mgr(mgr), ue_index(ue_idx), crnti(crnti_) - { - (void)crnti; - } + unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_); ~unique_ue_harq_entity(); unique_ue_harq_entity(const unique_ue_harq_entity&) = delete; unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept; diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 437904b83c..ac61561227 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -90,14 +90,27 @@ class base_harq_manager_test protected: base_harq_manager_test(unsigned nof_ues) : cell_harqs(nof_ues, timeout_handler.make_notifier(), max_ack_wait_timeout) { + logger.set_level(srslog::basic_levels::warning); + srslog::init(); + + srslog::fetch_basic_logger("SCHED").set_context(current_slot.sfn(), current_slot.slot_index()); + cell_harqs.slot_indication(current_slot); + } + + void run_slot() + { + ++current_slot; + srslog::fetch_basic_logger("SCHED").set_context(current_slot.sfn(), current_slot.slot_index()); + cell_harqs.slot_indication(current_slot); } const unsigned max_ack_wait_timeout = 16; dummy_harq_timeout_handler timeout_handler; + srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); cell_harq_manager cell_harqs; - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; + slot_point current_slot{0, test_rgen::uniform_int(0, 10239)}; }; class base_single_harq_entity_test : public base_harq_manager_test @@ -105,13 +118,6 @@ class base_single_harq_entity_test : public base_harq_manager_test protected: base_single_harq_entity_test() : base_harq_manager_test(1) {} - void run_slot() - { - ++next_slot; - srslog::fetch_basic_logger("SCHED").set_context(next_slot.sfn(), next_slot.slot_index()); - cell_harqs.slot_indication(next_slot); - } - const du_ue_index_t ue_index = to_du_ue_index(0); const rnti_t rnti = to_rnti(0x4601); const unsigned nof_harqs = 8; @@ -122,8 +128,6 @@ class base_single_harq_entity_test : public base_harq_manager_test unsigned k2 = 6; }; -} // namespace - // Test for multiple UEs managed by a single HARQ manager instance. class multi_ue_harq_manager_test : public base_harq_manager_test, public ::testing::Test { @@ -154,8 +158,8 @@ class single_harq_process_test : public base_single_harq_entity_test, public ::t pdsch_information pdsch_info; pusch_information pusch_info; - dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value()}; - ul_harq_process_view h_ul{harq_ent.alloc_ul_harq(next_slot + k2, max_retxs).value()}; + dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; + ul_harq_process_view h_ul{harq_ent.alloc_ul_harq(current_slot + k2, max_retxs).value()}; }; class dl_harq_process_multi_pucch_test : public base_single_harq_entity_test, public ::testing::Test @@ -168,7 +172,7 @@ class dl_harq_process_multi_pucch_test : public base_single_harq_entity_test, pu h_dl.increment_pucch_counter(); } - dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value()}; + dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; }; // Parameters of test with 2 PUCCHs - dl_harq_process_two_pucch_param_test @@ -199,9 +203,58 @@ class dl_harq_process_two_pucch_param_test : public base_single_harq_entity_test h_dl.increment_pucch_counter(); } - dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value()}; + dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; +}; + +enum harq_state_outcome { ACKed, NACKed, DTX_timeout }; + +struct test_2_harq_bits_params { + // Vector size represents the number of decoded PUCCHs forwarded to the scheduler. + std::vector> ack; + std::array outcome; +}; + +// In this test suite, we test the scenario where two HARQ bits arrive in a single PUCCH PDU to the scheduler. +class single_ue_harq_entity_2_bits_tester : public base_single_harq_entity_test, + public ::testing::TestWithParam +{ +protected: + single_ue_harq_entity_2_bits_tester() + { + // Allocate 2 HARQs with same PUCCH slot. + // > First HARQ, DAI=0. + run_slot(); + auto h_dl1 = harq_ent.alloc_dl_harq(current_slot, this->k1 + 1, this->max_retxs, 0); + h_dl1->increment_pucch_counter(); + h_dls.push_back(h_dl1->id()); + // > Second HARQ, DAI=1. + run_slot(); + auto h_dl2 = harq_ent.alloc_dl_harq(current_slot, this->k1, this->max_retxs, 1); + h_dl2->increment_pucch_counter(); + h_dls.push_back(h_dl2->id()); + if (GetParam().ack.size() > 1) { + h_dl1->increment_pucch_counter(); + h_dl2->increment_pucch_counter(); + } + + pucch_slot = current_slot + this->k1; + + while (current_slot <= pucch_slot + pucch_process_delay) { + run_slot(); + } + } + + const unsigned pucch_process_delay = 4; + slot_point pucch_slot; + std::vector h_dls; }; +// In this test suite, we test the scenario where 5 HARQ bits arrive in a single PUCCH PDU to the scheduler. +class single_ue_harq_entity_harq_5bit_tester : public base_single_harq_entity_test, public ::testing::Test +{}; + +} // namespace + // HARQ process tests TEST_F(single_harq_process_test, when_harq_is_allocated_then_it_enters_waiting_ack_state) @@ -214,11 +267,11 @@ TEST_F(single_harq_process_test, when_harq_is_allocated_then_it_enters_waiting_a TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_params_have_correct_values) { - ASSERT_EQ(h_dl.pdsch_slot(), next_slot); - ASSERT_EQ(h_dl.uci_slot(), next_slot + k1); + ASSERT_EQ(h_dl.pdsch_slot(), current_slot); + ASSERT_EQ(h_dl.uci_slot(), current_slot + k1); ASSERT_EQ(h_dl.max_nof_retxs(), max_retxs); ASSERT_EQ(h_dl.nof_retxs(), 0); - ASSERT_EQ(h_ul.pusch_slot(), next_slot + k2); + ASSERT_EQ(h_ul.pusch_slot(), current_slot + k2); ASSERT_EQ(h_ul.max_nof_retxs(), max_retxs); ASSERT_EQ(h_ul.nof_retxs(), 0); } @@ -248,7 +301,7 @@ TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_FALSE(h_dl.is_waiting_ack()); ASSERT_TRUE(h_dl.has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); + ASSERT_EQ(harq_ent.find_ul_harq(current_slot + k2), h_ul); ASSERT_EQ(h_ul.ul_crc_info(false), 0); ASSERT_FALSE(h_ul.is_waiting_ack()); ASSERT_TRUE(h_ul.has_pending_retx()); @@ -270,14 +323,14 @@ TEST_F(single_harq_process_test, retx_of_empty_harq_is_failure) ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); ASSERT_GE(h_ul.ul_crc_info(true), 0); - ASSERT_FALSE(h_dl.new_retx(next_slot, k1, 0)); - ASSERT_FALSE(h_ul.new_retx(next_slot + k2)); + ASSERT_FALSE(h_dl.new_retx(current_slot, k1, 0)); + ASSERT_FALSE(h_ul.new_retx(current_slot + k2)); } TEST_F(single_harq_process_test, retx_of_harq_waiting_ack_is_failure) { - ASSERT_FALSE(h_dl.new_retx(next_slot, k1, 0)); - ASSERT_FALSE(h_ul.new_retx(next_slot + k2)); + ASSERT_FALSE(h_dl.new_retx(current_slot, k1, 0)); + ASSERT_FALSE(h_ul.new_retx(current_slot + k2)); } TEST_F(single_harq_process_test, when_max_retxs_reached_then_harq_becomes_empty) @@ -293,8 +346,8 @@ TEST_F(single_harq_process_test, when_max_retxs_reached_then_harq_becomes_empty) ASSERT_TRUE(h_ul.has_pending_retx()); run_slot(); - ASSERT_TRUE(h_dl.new_retx(next_slot, k1, 0)); - ASSERT_TRUE(h_ul.new_retx(next_slot + k2)); + ASSERT_TRUE(h_dl.new_retx(current_slot, k1, 0)); + ASSERT_TRUE(h_ul.new_retx(current_slot + k2)); ASSERT_EQ(h_dl.nof_retxs(), i + 1); ASSERT_EQ(h_ul.nof_retxs(), i + 1); ASSERT_NE(old_dl_ndi, h_dl.ndi()); @@ -317,8 +370,8 @@ TEST_F(single_harq_process_test, when_newtx_after_ack_then_ndi_flips) ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); ASSERT_GE(h_ul.ul_crc_info(true), 0); - h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0).value(); - h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs).value(); + h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value(); + h_ul = harq_ent.alloc_ul_harq(current_slot + k2, max_retxs).value(); ASSERT_EQ(h_dl.nof_retxs(), 0); ASSERT_EQ(h_ul.nof_retxs(), 0); ASSERT_NE(dl_ndi, h_dl.ndi()); @@ -344,8 +397,8 @@ TEST_F(single_harq_process_test, when_ack_wait_timeout_reached_then_harq_is_avai ASSERT_TRUE(not h_ul.is_waiting_ack() and not h_ul.has_pending_retx()); ASSERT_FALSE(harq_ent.ul_harq(h_ul_id).has_value()); - h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs - 1, 0).value(); - h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs - 1).value(); + h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs - 1, 0).value(); + h_ul = harq_ent.alloc_ul_harq(current_slot + k2, max_retxs - 1).value(); ASSERT_TRUE(h_dl.is_waiting_ack() and not h_dl.has_pending_retx()); ASSERT_TRUE(h_ul.is_waiting_ack() and not h_ul.has_pending_retx()); ASSERT_EQ(h_dl.nof_retxs(), 0); @@ -364,8 +417,8 @@ TEST_F(single_harq_process_test, when_ack_wait_timeout_reached_then_harq_is_avai TEST_F(dl_harq_process_multi_pucch_test, when_dtx_received_after_ack_then_dtx_is_ignored) { - slot_point pucch_slot = next_slot + k1; - while (next_slot != pucch_slot) { + slot_point pucch_slot = current_slot + k1; + while (current_slot != pucch_slot) { run_slot(); } @@ -384,8 +437,8 @@ TEST_F(dl_harq_process_multi_pucch_test, when_dtx_received_after_ack_then_dtx_is // are DTX. TEST_F(dl_harq_process_multi_pucch_test, when_stronger_ack_received_after_nack_then_process_becomes_empty) { - slot_point pucch_slot = next_slot + k1; - while (next_slot != pucch_slot) { + slot_point pucch_slot = current_slot + k1; + while (current_slot != pucch_slot) { run_slot(); } @@ -505,8 +558,8 @@ TEST_F(single_ue_harq_entity_test, when_harq_entity_is_created_all_harqs_are_emp TEST_F(single_ue_harq_entity_test, when_harq_is_allocated_then_harq_entity_finds_harq_in_waiting_ack_state) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl); @@ -517,8 +570,8 @@ TEST_F(single_ue_harq_entity_test, when_harq_is_allocated_then_harq_entity_finds TEST_F(single_ue_harq_entity_test, when_harq_is_nacked_then_harq_entity_finds_harq_with_pending_retx) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); @@ -533,8 +586,8 @@ TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cann ASSERT_EQ(harq_ent.nof_ul_harqs(), nof_harqs); for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_dl.value().is_waiting_ack()); ASSERT_TRUE(h_ul.has_value()); @@ -548,8 +601,8 @@ TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cann ASSERT_FALSE(harq_ent.has_empty_dl_harqs()); ASSERT_FALSE(harq_ent.has_empty_ul_harqs()); - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); ASSERT_FALSE(h_dl.has_value()); ASSERT_FALSE(h_ul.has_value()); } @@ -557,8 +610,8 @@ TEST_F(single_ue_harq_entity_test, when_all_harqs_are_allocated_harq_entity_cann TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_resources_are_available_again) { for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); } @@ -566,8 +619,8 @@ TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_ harq_ent.reset(); harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); } @@ -575,13 +628,13 @@ TEST_F(single_ue_harq_entity_test, when_ue_harq_entity_is_deallocated_then_harq_ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_entity_does_not_find_pending_retx) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); for (unsigned i = 0; i != max_retxs; ++i) { - ASSERT_EQ(harq_ent.find_dl_harq(next_slot + k1, 0), h_dl); - ASSERT_EQ(harq_ent.find_ul_harq(next_slot + k2), h_ul); + ASSERT_EQ(harq_ent.find_dl_harq(current_slot + k1, 0), h_dl); + ASSERT_EQ(harq_ent.find_ul_harq(current_slot + k2), h_ul); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); @@ -591,8 +644,8 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_entity_does_ ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); run_slot(); - ASSERT_TRUE(h_dl.value().new_retx(next_slot, k1, 0)); - ASSERT_TRUE(h_ul.value().new_retx(next_slot + k2)); + ASSERT_TRUE(h_dl.value().new_retx(current_slot, k1, 0)); + ASSERT_TRUE(h_ul.value().new_retx(current_slot + k2)); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl); ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul); ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); @@ -610,8 +663,8 @@ TEST_F(single_ue_harq_entity_test, after_max_ack_wait_timeout_dl_harqs_are_avail { k2 = 4; for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); } @@ -632,103 +685,14 @@ TEST_F(single_ue_harq_entity_test, after_max_ack_wait_timeout_dl_harqs_are_avail ASSERT_TRUE(harq_ent.has_empty_dl_harqs()); ASSERT_TRUE(harq_ent.has_empty_ul_harqs()); for (unsigned i = 0; i != nof_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_retxs, 0); - auto h_ul = harq_ent.alloc_ul_harq(next_slot + k2, max_retxs); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent.alloc_ul_harq(current_slot + k2, max_retxs); ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); } } -TEST_F(multi_ue_harq_manager_test, when_ue_harq_entity_is_created_or_reset_then_cell_harq_manager_is_updated) -{ - for (unsigned i = 0; i != this->max_ues; ++i) { - ASSERT_FALSE(cell_harqs.contains(to_du_ue_index(i))); - } - std::vector harq_ents; - for (unsigned i = 0; i != this->max_ues; ++i) { - harq_ents.push_back(cell_harqs.add_ue(to_du_ue_index(i), to_rnti(0x4601 + i), nof_harqs, nof_harqs)); - ASSERT_TRUE(cell_harqs.contains(to_du_ue_index(i))); - } - for (unsigned i = 0; i != this->max_ues; ++i) { - harq_ents[i].reset(); - ASSERT_FALSE(cell_harqs.contains(to_du_ue_index(i))); - } -} - -class single_ue_dl_harq_ack_test : public single_ue_harq_entity_test -{ -protected: - const unsigned nof_harqs = 8; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); -}; - -namespace { - -enum harq_state_outcome { ACKed, NACKed, DTX_timeout }; - -struct test_2_harq_bits_params { - // Vector size represents the number of decoded PUCCHs forwarded to the scheduler. - std::vector> ack; - std::array outcome; -}; - -/// \brief With this test suite, we intend to test the scenario where two HARQ bits arrive in a single PUCCH PDU to the -/// scheduler. -class single_ue_harq_entity_2_bits_tester : public ::testing::TestWithParam -{ -protected: - single_ue_harq_entity_2_bits_tester() - { - logger.set_level(srslog::basic_levels::debug); - srslog::init(); - - // Allocate 2 HARQs with same PUCCH slot. - // > First HARQ, DAI=0. - run_slot(); - auto h_dl1 = harq_ent.alloc_dl_harq(next_slot, 5, max_harq_retxs, 0); - h_dl1->increment_pucch_counter(); - h_dls.push_back(h_dl1->id()); - // > Second HARQ, DAI=1. - run_slot(); - auto h_dl2 = harq_ent.alloc_dl_harq(next_slot, 4, max_harq_retxs, 1); - h_dl2->increment_pucch_counter(); - h_dls.push_back(h_dl2->id()); - if (GetParam().ack.size() > 1) { - h_dl1->increment_pucch_counter(); - h_dl2->increment_pucch_counter(); - } - - pucch_slot = next_slot + 4; - - while (next_slot <= pucch_slot + pucch_process_delay) { - run_slot(); - } - } - - ~single_ue_harq_entity_2_bits_tester() override { srslog::flush(); } - - void run_slot() - { - logger.set_context(next_slot.sfn(), next_slot.slot_index()); - cell_harqs.slot_indication(next_slot); - ++next_slot; - } - - const unsigned nof_harqs = 16, max_harq_retxs = 4, pucch_process_delay = 4; - const unsigned max_ack_wait_timeout = 16; - du_ue_index_t ue_index = to_du_ue_index(0); - rnti_t rnti = to_rnti(0x4601); - srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); - cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; - slot_point pucch_slot; - - std::vector h_dls; -}; - -} // namespace +// DL HARQ entity test when two HARQs match in UCI slot. TEST_P(single_ue_harq_entity_2_bits_tester, handle_pucchs) { @@ -787,45 +751,17 @@ INSTANTIATE_TEST_SUITE_P( test_2_harq_bits_params{.ack = {{2, 2}, {2, 1}}, .outcome = {NACKed, ACKed}}, test_2_harq_bits_params{.ack = {{2, 2}, {2, 2}}, .outcome = {NACKed, NACKed}})); -class single_ue_harq_entity_harq_5bit_tester : public ::testing::Test -{ -protected: - single_ue_harq_entity_harq_5bit_tester() - { - logger.set_level(srslog::basic_levels::debug); - srslog::init(); - } - - void run_slot() - { - logger.set_context(next_slot.sfn(), next_slot.slot_index()); - cell_harqs.slot_indication(next_slot); - ++next_slot; - } - - const unsigned nof_harqs = 8, max_harq_retxs = 4, pucch_process_delay = 4; - const unsigned max_ack_wait_timeout = 16; - du_ue_index_t ue_index = to_du_ue_index(0); - rnti_t rnti = to_rnti(0x4601); - srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); - - cell_harq_manager cell_harqs{1, nullptr, max_ack_wait_timeout}; - unique_ue_harq_entity harq_ent = cell_harqs.add_ue(ue_index, rnti, nof_harqs, nof_harqs); - - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; -}; - TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_acks_then_all_5_active_harqs_are_updated) { - const unsigned active_harqs = 5, k1 = 4; + const unsigned active_harqs = 5; std::vector h_dls; for (unsigned i = 0; i != active_harqs; ++i) { - h_dls.push_back(harq_ent.alloc_dl_harq(next_slot, k1, max_harq_retxs, i)->id()); + h_dls.push_back(harq_ent.alloc_dl_harq(current_slot, k1, this->max_retxs, i)->id()); } - slot_point pucch_slot = next_slot + k1; + slot_point pucch_slot = current_slot + k1; - while (next_slot != pucch_slot) { + while (current_slot != pucch_slot) { run_slot(); } @@ -844,16 +780,16 @@ TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_acks_then_al TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_nacks_then_all_5_active_harqs_are_updated) { - const unsigned active_harqs = 5, k1 = 4; + const unsigned active_harqs = 5; std::vector h_dls(active_harqs); for (unsigned i = 0; i != active_harqs; ++i) { - auto h_dl = harq_ent.alloc_dl_harq(next_slot, k1, max_harq_retxs, i); + auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, this->max_retxs, i); h_dls.push_back(h_dl->id()); } - slot_point pucch_slot = next_slot + k1; + slot_point pucch_slot = current_slot + k1; - while (next_slot != pucch_slot) { + while (current_slot != pucch_slot) { run_slot(); } @@ -868,3 +804,45 @@ TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_nacks_then_a ASSERT_TRUE(this->harq_ent.dl_harq(h_dls[i]).value().has_pending_retx()); } } + +// Tests for HARQ manager with multiple UEs + +TEST_F(multi_ue_harq_manager_test, when_ue_harq_entity_is_created_or_reset_then_cell_harq_manager_is_updated) +{ + for (unsigned i = 0; i != this->max_ues; ++i) { + ASSERT_FALSE(cell_harqs.contains(to_du_ue_index(i))); + } + std::vector harq_ents; + for (unsigned i = 0; i != this->max_ues; ++i) { + harq_ents.push_back(cell_harqs.add_ue(to_du_ue_index(i), to_rnti(0x4601 + i), nof_harqs, nof_harqs)); + ASSERT_TRUE(cell_harqs.contains(to_du_ue_index(i))); + } + for (unsigned i = 0; i != this->max_ues; ++i) { + harq_ents[i].reset(); + ASSERT_FALSE(cell_harqs.contains(to_du_ue_index(i))); + } +} + +TEST_F(multi_ue_harq_manager_test, when_harq_entities_are_destroyed_then_pending_timeouts_are_not_triggered) +{ + unsigned k1 = 4, max_retxs = 4; + unique_ue_harq_entity harq_ent1 = cell_harqs.add_ue(to_du_ue_index(1), to_rnti(0x4601), nof_harqs, nof_harqs); + unique_ue_harq_entity harq_ent2 = cell_harqs.add_ue(to_du_ue_index(2), to_rnti(0x4602), nof_harqs, nof_harqs); + + ASSERT_TRUE(harq_ent1.alloc_dl_harq(current_slot, k1, max_retxs, 0).has_value()); + run_slot(); + ASSERT_TRUE(harq_ent2.alloc_dl_harq(current_slot, k1, max_retxs, 0).has_value()); + + // Delete UE1 before timeout. + for (unsigned i = 0; i != this->max_ack_wait_timeout + k1 - 2; ++i) { + run_slot(); + ASSERT_EQ(this->timeout_handler.last_ue_index, INVALID_DU_UE_INDEX); + } + + harq_ent1.reset(); + run_slot(); // UE1 timeout should not trigger. + ASSERT_EQ(this->timeout_handler.last_ue_index, INVALID_DU_UE_INDEX); + + run_slot(); + ASSERT_EQ(this->timeout_handler.last_ue_index, to_du_ue_index(2)); +} From a2d80498a6d254f87c6a7befe8689d903f513d6e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 10:49:33 +0200 Subject: [PATCH 391/407] sched: test retx cancellation --- .../ue_scheduling/cell_harq_manager.cpp | 22 ++++++++++++++----- .../ue_scheduling/cell_harq_manager.h | 8 +++++++ .../ue_scheduling/harq_manager_test.cpp | 14 ++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 22995c5653..67ae16a5dd 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -176,12 +176,12 @@ void cell_harq_repository::handle_ack(harq_type& h, bool ack) { if (not ack and h.nof_retxs >= h.max_nof_harq_retxs) { if (h.retxs_cancelled) { - logger.info("rnti={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Retxs for this HARQ process were " - "cancelled", - h.rnti, - h.h_id, - IsDl ? "DL" : "UL", - h.prev_tx_params.tbs_bytes); + logger.debug("rnti={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Retxs for this HARQ process " + "were cancelled", + h.rnti, + h.h_id, + IsDl ? "DL" : "UL", + h.prev_tx_params.tbs_bytes); } else { logger.info( "rnti={} h_id={}: Discarding {} HARQ process TB with tbs={}. Cause: Maximum number of reTxs {} exceeded", @@ -465,6 +465,11 @@ void dl_harq_process_view::increment_pucch_counter() ++fetch_impl().pucch_ack_to_receive; } +void dl_harq_process_view::cancel_retxs() +{ + cell_harq_mng->dl.cancel_retxs(fetch_impl()); +} + void dl_harq_process_view::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) { srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); @@ -509,6 +514,11 @@ int ul_harq_process_view::ul_crc_info(bool ack) return cell_harq_mng->ul_crc_info(cell_harq_mng->ul.harqs[harq_ref_idx], ack); } +void ul_harq_process_view::cancel_retxs() +{ + cell_harq_mng->ul.cancel_retxs(fetch_impl()); +} + void ul_harq_process_view::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) { ul_harq_process_impl& impl = fetch_impl(); diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index 8d5365420d..e0c4a44a30 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -291,6 +291,8 @@ class dl_harq_process_view void increment_pucch_counter(); + void cancel_retxs(); + /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that /// they can be later fetched and optionally reused. void save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch); @@ -330,6 +332,10 @@ class ul_harq_process_view bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } + bool empty() const + { + return harq_ref_idx == cell_harq_manager::INVALID_HARQ or fetch_impl().status == harq_utils::harq_state_t::empty; + } [[nodiscard]] bool new_retx(slot_point pusch_slot); @@ -337,6 +343,8 @@ class ul_harq_process_view /// \return Transport Block size of the HARQ whose state was updated. int ul_crc_info(bool ack); + void cancel_retxs(); + /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that /// they can be later fetched and optionally reused. void save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pdsch); diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index ac61561227..7bc8d6da21 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -413,6 +413,20 @@ TEST_F(single_harq_process_test, when_ack_wait_timeout_reached_then_harq_is_avai } } +TEST_F(single_harq_process_test, when_harq_retx_is_cancelled_then_harq_nack_empties_it) +{ + h_dl.cancel_retxs(); + h_ul.cancel_retxs(); + ASSERT_TRUE(h_dl.is_waiting_ack()); + ASSERT_TRUE(h_ul.is_waiting_ack()); + + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_ul.ul_crc_info(false), 0); + ASSERT_TRUE(h_dl.empty()); + ASSERT_TRUE(h_ul.empty()); +} + // DL HARQ process with multi PUCCH test TEST_F(dl_harq_process_multi_pucch_test, when_dtx_received_after_ack_then_dtx_is_ignored) From e94e493636aa9e2ee710ef13f6ffde2b385fd04f Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 11:18:19 +0200 Subject: [PATCH 392/407] sched: remove harq_process_test --- .../scheduler/ue_scheduling/CMakeLists.txt | 1 - .../ue_scheduling/harq_process_test.cpp | 88 ------------------- 2 files changed, 89 deletions(-) delete mode 100644 tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp diff --git a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt index 3c91bf54a6..ae0719fbd7 100644 --- a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt +++ b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt @@ -9,7 +9,6 @@ add_executable(ue_scheduler_test logical_channel_test.cpp harq_manager_test.cpp - harq_process_test.cpp fallback_scheduler_test.cpp ue_cell_test.cpp ue_configuration_test.cpp diff --git a/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp deleted file mode 100644 index 9aeb652abf..0000000000 --- a/tests/unittests/scheduler/ue_scheduling/harq_process_test.cpp +++ /dev/null @@ -1,88 +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 "lib/scheduler/ue_scheduling/harq_process.h" -#include "srsran/scheduler/scheduler_slot_handler.h" -#include "srsran/support/test_utils.h" -#include - -using namespace srsran; - -/// Tester for different combinations of max HARQ retxs, ack wait timeouts, and k1s. -class dl_harq_process_tester : public ::testing::Test -{ -protected: - dl_harq_process_tester(unsigned max_ack_timeout_slots = 16) : - dl_logger(srslog::fetch_basic_logger("SCHED"), to_rnti(0x4601), to_du_cell_index(0), true), - h_dl(to_harq_id(0), dl_logger, {}, max_ack_timeout_slots) - { - srslog::fetch_basic_logger("SCHED").set_level(srslog::basic_levels::debug); - - srslog::init(); - } - - harq_logger dl_logger; - dl_harq_process h_dl; -}; - -TEST_F(dl_harq_process_tester, harq_starts_empty) -{ - ASSERT_TRUE(this->h_dl.empty(0)); - ASSERT_TRUE(this->h_dl.empty()); - ASSERT_FALSE(this->h_dl.has_pending_retx()); - ASSERT_FALSE(this->h_dl.has_pending_retx(0)); -} - -TEST_F(dl_harq_process_tester, reset_of_empty_harq_is_no_op) -{ - h_dl.reset(); - ASSERT_TRUE(h_dl.empty()); - ASSERT_TRUE(h_dl.empty(0)); - ASSERT_FALSE(h_dl.has_pending_retx()); - ASSERT_FALSE(h_dl.has_pending_retx(0)); -} - -/// Tester for different combinations of max HARQ retxs, ack wait timeouts, and k1s. -class dl_harq_process_param_tester : public ::testing::TestWithParam> -{ -protected: - dl_harq_process_param_tester() : - max_harq_retxs(std::get<0>(GetParam())), - max_ack_wait_slots(std::get<1>(GetParam())), - k1(std::get<2>(GetParam())), - dl_logger(srslog::fetch_basic_logger("SCHED"), to_rnti(0x4601), to_du_cell_index(0), true), - h_dl(to_harq_id(0), dl_logger, {}, max_ack_wait_slots) - { - srslog::init(); - } - - void slot_indication() - { - ++sl_tx; - srslog::fetch_basic_logger("SCHED").set_context(sl_tx.sfn(), sl_tx.slot_index()); - h_dl.slot_indication(sl_tx); - } - - ~dl_harq_process_param_tester() { srslog::flush(); } - - const unsigned max_harq_retxs; - const unsigned max_ack_wait_slots; - const unsigned k1; - - harq_logger dl_logger; - dl_harq_process h_dl; - slot_point sl_tx{0, 0}; -}; - -INSTANTIATE_TEST_SUITE_P(dl_harq_param_combine, - dl_harq_process_param_tester, - testing::Combine(testing::Values(0, 1, 2, 4), // max_retxs - testing::Values(2, 4, 6, 8), // max_ack_wait_slots - testing::Values(1, 2, 4, 6))); // k1 From 74338a09acda1941e3aae9e0cfef4c5d9e99666d Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 12:57:16 +0200 Subject: [PATCH 393/407] sched: refactor harq_process_handle classes and fix cancellation of retxs --- .../ue_scheduling/cell_harq_manager.cpp | 130 ++++++------- .../ue_scheduling/cell_harq_manager.h | 181 +++++++++--------- .../ue_scheduling/harq_manager_test.cpp | 79 +++++--- 3 files changed, 197 insertions(+), 193 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 67ae16a5dd..446dd4cf79 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -59,6 +59,8 @@ void cell_harq_repository::slot_indication(slot_point sl_tx) while (not harqs_timing_out.empty()) { handle_harq_ack_timeout(harqs_timing_out.front(), sl_tx); } + + last_sl_ind = sl_tx; } template @@ -276,6 +278,13 @@ void cell_harq_repository::cancel_retxs(harq_type& h) if (h.status == harq_state_t::empty) { return; } + if (h.status == harq_state_t::pending_retx) { + // If a retx is pending, do not allow it to take place. + dealloc_harq(h); + return; + } + // If the HARQ is still waiting for an ACK to arrive, just mark it as max retxs have been exceeded. The ack_info + // function will automatically update the HARQ state. h.max_nof_harq_retxs = h.nof_retxs; h.retxs_cancelled = true; } @@ -375,14 +384,13 @@ cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch return h; } -bool cell_harq_manager::new_dl_retx(harq_utils::dl_harq_process_impl& h, - slot_point pdsch_slot, - unsigned k1, - uint8_t harq_bit_idx) +bool dl_harq_process_handle::new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) { - if (not dl.handle_new_retx(h, pdsch_slot, pdsch_slot + k1)) { + dl_harq_process_impl& h = fetch_impl(); + if (not harq_repo->handle_new_retx(h, pdsch_slot, pdsch_slot + k1)) { return false; } + // Reset DL-only HARQ parameters. h.harq_bit_idx = harq_bit_idx; h.pucch_ack_to_receive = 0; h.chosen_ack = mac_harq_ack_report_status::dtx; @@ -390,20 +398,13 @@ bool cell_harq_manager::new_dl_retx(harq_utils::dl_harq_process_impl& h, return true; } -bool cell_harq_manager::new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot) -{ - return ul.handle_new_retx(h, pusch_slot, pusch_slot); -} - -dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::dl_harq_process_impl& h, - mac_harq_ack_report_status ack, - std::optional pucch_snr) +dl_harq_process_handle::status_update dl_harq_process_handle::dl_ack_info(mac_harq_ack_report_status ack, + std::optional pucch_snr) { - using status_update = dl_harq_process_impl::status_update; - + dl_harq_process_impl& h = fetch_impl(); if (h.status != harq_state_t::waiting_ack) { // If the HARQ process is not expecting an HARQ-ACK, it means that it has already been ACKed/NACKed. - logger.warning("rnti={} h_id={}: ACK arrived for inactive DL HARQ", h.rnti, h.h_id); + harq_repo->logger.warning("rnti={} h_id={}: ACK arrived for inactive DL HARQ", h.rnti, h.h_id); return status_update::error; } @@ -419,7 +420,7 @@ dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::d // Update HARQ state bool final_ack = h.chosen_ack == mac_harq_ack_report_status::ack; - dl.handle_ack(h, final_ack); + harq_repo->handle_ack(h, final_ack); return final_ack ? status_update::acked : status_update::nacked; } @@ -429,48 +430,25 @@ dl_harq_process_impl::status_update cell_harq_manager::dl_ack_info(harq_utils::d h.ack_on_timeout = h.chosen_ack == mac_harq_ack_report_status::ack; // We reduce the HARQ process timeout to receive the next HARQ-ACK. This is done because the two HARQ-ACKs should // arrive almost simultaneously, and in case the second goes missing, we don't want to block the HARQ for too long. - dl.harq_timeout_wheel[h.slot_ack_timeout.to_uint() % dl.harq_timeout_wheel.size()].pop(&h); - h.slot_ack_timeout = last_sl_tx + SHORT_ACK_TIMEOUT_DTX; - dl.harq_timeout_wheel[h.slot_ack_timeout.to_uint() % dl.harq_timeout_wheel.size()].push_front(&h); + auto& wheel = harq_repo->harq_timeout_wheel; + wheel[h.slot_ack_timeout.to_uint() % wheel.size()].pop(&h); + h.slot_ack_timeout = harq_repo->last_sl_ind + SHORT_ACK_TIMEOUT_DTX; + wheel[h.slot_ack_timeout.to_uint() % wheel.size()].push_front(&h); return status_update::no_update; } -int cell_harq_manager::ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack) -{ - if (h.status != harq_state_t::waiting_ack) { - // HARQ is not expecting CRC info. - logger.warning("rnti={} h_id={}: CRC arrived for UL HARQ not expecting it", h.rnti, h.h_id); - return -1; - } - - ul.handle_ack(h, ack); - - return ack ? (int)h.prev_tx_params.tbs_bytes : 0; -} - -bool dl_harq_process_view::new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) -{ - return cell_harq_mng->new_dl_retx(fetch_impl(), pdsch_slot, k1, harq_bit_idx); -} - -dl_harq_process_view::status_update dl_harq_process_view::dl_ack_info(mac_harq_ack_report_status ack, - std::optional pucch_snr) -{ - return cell_harq_mng->dl_ack_info(fetch_impl(), ack, pucch_snr); -} - -void dl_harq_process_view::increment_pucch_counter() +void dl_harq_process_handle::increment_pucch_counter() { ++fetch_impl().pucch_ack_to_receive; } -void dl_harq_process_view::cancel_retxs() +void dl_harq_process_handle::cancel_retxs() { - cell_harq_mng->dl.cancel_retxs(fetch_impl()); + harq_repo->cancel_retxs(fetch_impl()); } -void dl_harq_process_view::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) +void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) { srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); dl_harq_process_impl& impl = fetch_impl(); @@ -504,22 +482,31 @@ void dl_harq_process_view::save_grant_params(const dl_harq_sched_context& ctx, c prev_params.nof_symbols = pdsch.symbols.length(); } -bool ul_harq_process_view::new_retx(slot_point pusch_slot) +bool ul_harq_process_handle::new_retx(slot_point pusch_slot) { - return cell_harq_mng->new_ul_retx(cell_harq_mng->ul.harqs[harq_ref_idx], pusch_slot); + return harq_repo->handle_new_retx(fetch_impl(), pusch_slot, pusch_slot); } -int ul_harq_process_view::ul_crc_info(bool ack) +int ul_harq_process_handle::ul_crc_info(bool ack) { - return cell_harq_mng->ul_crc_info(cell_harq_mng->ul.harqs[harq_ref_idx], ack); + ul_harq_process_impl& h = fetch_impl(); + if (h.status != harq_state_t::waiting_ack) { + // HARQ is not expecting CRC info. + harq_repo->logger.warning("rnti={} h_id={}: CRC arrived for UL HARQ not expecting it", h.rnti, h.h_id); + return -1; + } + + harq_repo->handle_ack(h, ack); + + return ack ? (int)h.prev_tx_params.tbs_bytes : 0; } -void ul_harq_process_view::cancel_retxs() +void ul_harq_process_handle::cancel_retxs() { - cell_harq_mng->ul.cancel_retxs(fetch_impl()); + harq_repo->cancel_retxs(fetch_impl()); } -void ul_harq_process_view::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) +void ul_harq_process_handle::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) { ul_harq_process_impl& impl = fetch_impl(); srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, @@ -585,62 +572,63 @@ void unique_ue_harq_entity::reset() } } -std::optional +std::optional unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx) { dl_harq_process_impl* h = cell_harq_mgr->new_dl_tx(ue_index, crnti, sl_tx, k1, max_harq_nof_retxs, harq_bit_idx); if (h == nullptr) { return std::nullopt; } - return dl_harq_process_view(*cell_harq_mgr, cell_harq_mgr->dl.get_harq_ref_idx(*h)); + return dl_harq_process_handle(cell_harq_mgr->dl, cell_harq_mgr->dl.get_harq_ref_idx(*h)); } -std::optional unique_ue_harq_entity::alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs) +std::optional unique_ue_harq_entity::alloc_ul_harq(slot_point sl_tx, + unsigned max_harq_nof_retxs) { ul_harq_process_impl* h = cell_harq_mgr->new_ul_tx(ue_index, crnti, sl_tx, max_harq_nof_retxs); if (h == nullptr) { return std::nullopt; } - return ul_harq_process_view(*cell_harq_mgr, cell_harq_mgr->ul.get_harq_ref_idx(*h)); + return ul_harq_process_handle(cell_harq_mgr->ul, cell_harq_mgr->ul.get_harq_ref_idx(*h)); } -std::optional unique_ue_harq_entity::find_pending_dl_retx() +std::optional unique_ue_harq_entity::find_pending_dl_retx() { unsigned h_ref_idx = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); if (h_ref_idx == INVALID_HARQ_REF_INDEX) { return std::nullopt; } - return dl_harq_process_view(*cell_harq_mgr, h_ref_idx); + return dl_harq_process_handle(cell_harq_mgr->dl, h_ref_idx); } -std::optional unique_ue_harq_entity::find_pending_ul_retx() +std::optional unique_ue_harq_entity::find_pending_ul_retx() { unsigned h_ref_idx = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); if (h_ref_idx == INVALID_HARQ_REF_INDEX) { return std::nullopt; } - return ul_harq_process_view(*cell_harq_mgr, h_ref_idx); + return ul_harq_process_handle(cell_harq_mgr->ul, h_ref_idx); } -std::optional unique_ue_harq_entity::find_dl_harq_waiting_ack() +std::optional unique_ue_harq_entity::find_dl_harq_waiting_ack() { unsigned h_ref_idx = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); if (h_ref_idx == INVALID_HARQ_REF_INDEX) { return std::nullopt; } - return dl_harq_process_view(*cell_harq_mgr, h_ref_idx); + return dl_harq_process_handle(cell_harq_mgr->dl, h_ref_idx); } -std::optional unique_ue_harq_entity::find_ul_harq_waiting_ack() +std::optional unique_ue_harq_entity::find_ul_harq_waiting_ack() { unsigned h_ref_idx = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); if (h_ref_idx == INVALID_HARQ_REF_INDEX) { return std::nullopt; } - return ul_harq_process_view(*cell_harq_mgr, h_ref_idx); + return ul_harq_process_handle(cell_harq_mgr->ul, h_ref_idx); } -std::optional unique_ue_harq_entity::find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx) +std::optional unique_ue_harq_entity::find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx) { const std::vector& dl_harqs = cell_harq_mgr->dl.ues[ue_index].harqs; for (unsigned h_ref_idx : dl_harqs) { @@ -648,21 +636,21 @@ std::optional unique_ue_harq_entity::find_dl_harq(slot_poi const dl_harq_process_impl& h = cell_harq_mgr->dl.harqs[h_ref_idx]; if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_ack == uci_slot and h.harq_bit_idx == harq_bit_idx) { - return dl_harq_process_view(*cell_harq_mgr, h_ref_idx); + return dl_harq_process_handle(cell_harq_mgr->dl, h_ref_idx); } } } return std::nullopt; } -std::optional unique_ue_harq_entity::find_ul_harq(slot_point pusch_slot) +std::optional unique_ue_harq_entity::find_ul_harq(slot_point pusch_slot) { const std::vector& ul_harqs = cell_harq_mgr->ul.ues[ue_index].harqs; for (unsigned h_ref_idx : ul_harqs) { if (h_ref_idx != INVALID_HARQ_REF_INDEX) { const ul_harq_process_impl& h = cell_harq_mgr->ul.harqs[h_ref_idx]; if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_tx == pusch_slot) { - return ul_harq_process_view(*cell_harq_mgr, h_ref_idx); + return ul_harq_process_handle(cell_harq_mgr->ul, h_ref_idx); } } } diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index e0c4a44a30..8416741a9d 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -129,6 +129,8 @@ template struct cell_harq_repository { using harq_type = std::conditional_t; + const static unsigned INVALID_HARQ = std::numeric_limits::max(); + cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_in_slots, harq_timeout_notifier& timeout_notifier_, @@ -139,6 +141,8 @@ struct cell_harq_repository { harq_timeout_notifier& timeout_notifier; srslog::basic_logger& logger; + slot_point last_sl_ind; + std::vector harqs; std::vector free_harqs; std::vector ues; @@ -161,6 +165,46 @@ struct cell_harq_repository { unsigned find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; }; +template +class base_harq_process_handle +{ +protected: + using harq_pool = cell_harq_repository; + using harq_impl_type = std::conditional_t; + +public: + base_harq_process_handle(harq_pool& pool_, unsigned harq_ref_idx_) : harq_repo(&pool_), harq_ref_idx(harq_ref_idx_) + { + srsran_sanity_check(harq_ref_idx < harq_repo->harqs.size(), "Invalid HARQ created"); + srsran_sanity_check(harq_repo->harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty, + "Empty HARQ process created"); + } + + harq_id_t id() const { return fetch_impl().h_id; } + bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } + bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } + bool empty() const + { + return harq_ref_idx == harq_pool::INVALID_HARQ or fetch_impl().status == harq_utils::harq_state_t::empty; + } + unsigned max_nof_retxs() const { return fetch_impl().max_nof_harq_retxs; } + unsigned nof_retxs() const { return fetch_impl().nof_retxs; } + bool ndi() const { return fetch_impl().ndi; } + + bool operator==(const base_harq_process_handle& other) const + { + return harq_repo == other.harq_repo and harq_ref_idx == other.harq_ref_idx; + } + bool operator!=(const base_harq_process_handle& other) const { return !(*this == other); } + +protected: + harq_impl_type& fetch_impl() { return harq_repo->harqs[harq_ref_idx]; } + const harq_impl_type& fetch_impl() const { return harq_repo->harqs[harq_ref_idx]; } + + harq_pool* harq_repo = nullptr; + unsigned harq_ref_idx = harq_pool::INVALID_HARQ; +}; + } // namespace harq_utils /// \brief Context of the scheduler during the current PDSCH allocation. @@ -189,9 +233,6 @@ class cell_harq_manager /// \brief Default timeout in slots after which the HARQ process assumes that the CRC/ACK went missing /// (implementation-defined). constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; - /// \brief Timeout value to use when the HARQ has been ACKed/NACKed, but it is expecting another PUCCH before being - /// cleared (implementation-defined). - constexpr static unsigned SHORT_ACK_TIMEOUT_DTX = 8U; cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, std::unique_ptr notifier = nullptr, @@ -217,10 +258,6 @@ class cell_harq_manager private: friend class unique_ue_harq_entity; - friend class dl_harq_process_view; - friend class ul_harq_process_view; - - const static unsigned INVALID_HARQ = std::numeric_limits::max(); void destroy_ue(du_ue_index_t ue_idx); @@ -236,21 +273,6 @@ class cell_harq_manager harq_utils::ul_harq_process_impl* new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs); - /// \brief Called on a new retx of a DL HARQ process. - [[nodiscard]] bool - new_dl_retx(harq_utils::dl_harq_process_impl& h, slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); - - /// \brief Called on a new retx of a UL HARQ process. - [[nodiscard]] bool new_ul_retx(harq_utils::ul_harq_process_impl& h, slot_point pusch_slot); - - /// Updates a DL HARQ process given the received HARQ-ACK info. - harq_utils::dl_harq_process_impl::status_update - dl_ack_info(harq_utils::dl_harq_process_impl& h, mac_harq_ack_report_status ack, std::optional pucch_snr); - - /// Updates a UL HARQ process given the received CRC indication. - /// \return Transport Block size of the HARQ whose state was updated. - int ul_crc_info(harq_utils::ul_harq_process_impl& h, bool ack); - std::unique_ptr timeout_notifier; srslog::basic_logger& logger; @@ -260,26 +282,34 @@ class cell_harq_manager harq_utils::cell_harq_repository ul; }; -class dl_harq_process_view +/// \brief Interface used to fetch and update the status of a DL HARQ process. +/// \remark This handle acts like a view to an internal HARQ process. It is not a "unique" type that controls the +/// lifetime of a HARQ. Avoid storing and using the same handle across different slots. +class dl_harq_process_handle : public harq_utils::base_harq_process_handle { + using base_type = harq_utils::base_harq_process_handle; + public: + /// \brief Timeout value to use when the HARQ has been ACKed/NACKed, but it is expecting another PUCCH before being + /// cleared (implementation-defined). + constexpr static unsigned SHORT_ACK_TIMEOUT_DTX = 8U; + using status_update = harq_utils::dl_harq_process_impl::status_update; using grant_params = harq_utils::dl_harq_process_impl::alloc_params; - dl_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : - cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) + dl_harq_process_handle(harq_utils::cell_harq_repository& harq_repo_, unsigned h_ref_idx_) : + base_type(harq_repo_, h_ref_idx_) { - srsran_sanity_check(cell_harq_mng->dl.harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty, - "Empty HARQ process created"); } - harq_id_t id() const { return fetch_impl().h_id; } - bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } - bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } - bool empty() const - { - return harq_ref_idx == cell_harq_manager::INVALID_HARQ or fetch_impl().status == harq_utils::harq_state_t::empty; - } + using base_type::empty; + using base_type::has_pending_retx; + using base_type::id; + using base_type::is_waiting_ack; + + using base_type::max_nof_retxs; + using base_type::ndi; + using base_type::nof_retxs; [[nodiscard]] bool new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); @@ -299,43 +329,28 @@ class dl_harq_process_view slot_point pdsch_slot() const { return fetch_impl().slot_tx; } slot_point uci_slot() const { return fetch_impl().slot_ack; } - unsigned max_nof_retxs() const { return fetch_impl().max_nof_harq_retxs; } - unsigned nof_retxs() const { return fetch_impl().nof_retxs; } - bool ndi() const { return fetch_impl().ndi; } const grant_params& get_grant_params() const { return fetch_impl().prev_tx_params; } - - bool operator==(const dl_harq_process_view& other) const - { - return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx; - } - bool operator!=(const dl_harq_process_view& other) const { return !(*this == other); } - -private: - harq_utils::dl_harq_process_impl& fetch_impl() { return cell_harq_mng->dl.harqs[harq_ref_idx]; } - const harq_utils::dl_harq_process_impl& fetch_impl() const { return cell_harq_mng->dl.harqs[harq_ref_idx]; } - - cell_harq_manager* cell_harq_mng = nullptr; - unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; }; -class ul_harq_process_view +/// Interface used to fetch and update the status of a UL HARQ process. +/// \remark This handle acts like a view to an internal HARQ process. It is not a "unique" type that controls the +/// lifetime of a HARQ. Avoid storing and using the same handle across different slots. +class ul_harq_process_handle : public harq_utils::base_harq_process_handle { + using base_type = harq_utils::base_harq_process_handle; + public: - ul_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) : - cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx) - { - srsran_sanity_check(fetch_impl().status != harq_utils::harq_state_t::empty, "Empty HARQ process created"); - } + ul_harq_process_handle(harq_pool& harq_repo_, unsigned h_ref_idx) : base_type(harq_repo_, h_ref_idx) {} - harq_id_t id() const { return fetch_impl().h_id; } + using base_type::empty; + using base_type::has_pending_retx; + using base_type::id; + using base_type::is_waiting_ack; - bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } - bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } - bool empty() const - { - return harq_ref_idx == cell_harq_manager::INVALID_HARQ or fetch_impl().status == harq_utils::harq_state_t::empty; - } + using base_type::max_nof_retxs; + using base_type::ndi; + using base_type::nof_retxs; [[nodiscard]] bool new_retx(slot_point pusch_slot); @@ -350,22 +365,6 @@ class ul_harq_process_view void save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pdsch); slot_point pusch_slot() const { return fetch_impl().slot_tx; } - unsigned max_nof_retxs() const { return fetch_impl().max_nof_harq_retxs; } - unsigned nof_retxs() const { return fetch_impl().nof_retxs; } - bool ndi() const { return fetch_impl().ndi; } - - bool operator==(const ul_harq_process_view& other) const - { - return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx; - } - bool operator!=(const ul_harq_process_view& other) const { return !(*this == other); } - -private: - harq_utils::ul_harq_process_impl& fetch_impl() { return cell_harq_mng->ul.harqs[harq_ref_idx]; } - const harq_utils::ul_harq_process_impl& fetch_impl() const { return cell_harq_mng->ul.harqs[harq_ref_idx]; } - - cell_harq_manager* cell_harq_mng = nullptr; - unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ; }; class unique_ue_harq_entity @@ -390,41 +389,41 @@ class unique_ue_harq_entity /// Deallocate UE HARQ entity. void reset(); - std::optional dl_harq(harq_id_t h_id) + std::optional dl_harq(harq_id_t h_id) { if (cell_harq_mgr->dl.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { - return dl_harq_process_view{*cell_harq_mgr, cell_harq_mgr->dl.ues[ue_index].harqs[h_id]}; + return dl_harq_process_handle{cell_harq_mgr->dl, cell_harq_mgr->dl.ues[ue_index].harqs[h_id]}; } return std::nullopt; } - std::optional ul_harq(harq_id_t h_id) + std::optional ul_harq(harq_id_t h_id) { if (cell_harq_mgr->ul.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { - return ul_harq_process_view{*cell_harq_mgr, cell_harq_mgr->ul.ues[ue_index].harqs[h_id]}; + return ul_harq_process_handle{cell_harq_mgr->ul, cell_harq_mgr->ul.ues[ue_index].harqs[h_id]}; } return std::nullopt; } - std::optional + std::optional alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx); - std::optional alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs); + std::optional alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs); - std::optional find_pending_dl_retx(); - std::optional find_pending_ul_retx(); + std::optional find_pending_dl_retx(); + std::optional find_pending_ul_retx(); - std::optional find_dl_harq_waiting_ack(); - std::optional find_ul_harq_waiting_ack(); + std::optional find_dl_harq_waiting_ack(); + std::optional find_ul_harq_waiting_ack(); /// Fetch active DL HARQ process based on HARQ-ACK UCI slot and HARQ bit index. /// \param[in] uci_slot Slot when the UCI is to be received. /// \param[in] harq_bit_idx Bit index of the HARQ-ACK in the UCI indication. /// \return Active DL HARQ process with matching UCI slot and HARQ bit index, if found. - std::optional find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx); + std::optional find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx); /// Fetch active UL HARQ process based on slot when its PUSCH was transmitted. /// \param[in] pusch_slot Slot when the PUSCH was transmitted. /// \return Active UL HARQ process with matching PUSCH slot, if found. - std::optional find_ul_harq(slot_point pusch_slot); + std::optional find_ul_harq(slot_point pusch_slot); private: harq_utils::ue_harq_entity_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 7bc8d6da21..f30d0a5a12 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -156,10 +156,10 @@ class single_harq_process_test : public base_single_harq_entity_test, public ::t h_ul.save_grant_params(ul_harq_ctxt, pusch_info); } - pdsch_information pdsch_info; - pusch_information pusch_info; - dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; - ul_harq_process_view h_ul{harq_ent.alloc_ul_harq(current_slot + k2, max_retxs).value()}; + pdsch_information pdsch_info; + pusch_information pusch_info; + dl_harq_process_handle h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; + ul_harq_process_handle h_ul{harq_ent.alloc_ul_harq(current_slot + k2, max_retxs).value()}; }; class dl_harq_process_multi_pucch_test : public base_single_harq_entity_test, public ::testing::Test @@ -172,7 +172,7 @@ class dl_harq_process_multi_pucch_test : public base_single_harq_entity_test, pu h_dl.increment_pucch_counter(); } - dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; + dl_harq_process_handle h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; }; // Parameters of test with 2 PUCCHs - dl_harq_process_two_pucch_param_test @@ -203,7 +203,7 @@ class dl_harq_process_two_pucch_param_test : public base_single_harq_entity_test h_dl.increment_pucch_counter(); } - dl_harq_process_view h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; + dl_harq_process_handle h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; }; enum harq_state_outcome { ACKed, NACKed, DTX_timeout }; @@ -288,7 +288,7 @@ TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_grant_params_h TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) { float pucch_snr = 5; - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_handle::status_update::acked); ASSERT_FALSE(h_dl.is_waiting_ack()); ASSERT_FALSE(h_dl.has_pending_retx()); ASSERT_EQ(h_ul.ul_crc_info(true), pusch_info.tb_size_bytes); @@ -298,7 +298,7 @@ TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) { - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_handle::status_update::nacked); ASSERT_FALSE(h_dl.is_waiting_ack()); ASSERT_TRUE(h_dl.has_pending_retx()); ASSERT_EQ(harq_ent.find_ul_harq(current_slot + k2), h_ul); @@ -310,17 +310,17 @@ TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) TEST_F(single_harq_process_test, ack_of_empty_harq_is_failure) { float pucch_snr = 5; - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_handle::status_update::acked); ASSERT_GE(h_ul.ul_crc_info(true), 0); - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::error); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_handle::status_update::error); ASSERT_LT(h_ul.ul_crc_info(true), 0); } TEST_F(single_harq_process_test, retx_of_empty_harq_is_failure) { float pucch_snr = 5; - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_handle::status_update::acked); ASSERT_GE(h_ul.ul_crc_info(true), 0); ASSERT_FALSE(h_dl.new_retx(current_slot, k1, 0)); @@ -338,7 +338,7 @@ TEST_F(single_harq_process_test, when_max_retxs_reached_then_harq_becomes_empty) bool old_dl_ndi = h_dl.ndi(); bool old_ul_ndi = h_ul.ndi(); for (unsigned i = 0; i != max_retxs; ++i) { - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.ul_crc_info(false), 0); ASSERT_FALSE(h_dl.is_waiting_ack()); ASSERT_FALSE(h_ul.is_waiting_ack()); @@ -355,7 +355,7 @@ TEST_F(single_harq_process_test, when_max_retxs_reached_then_harq_becomes_empty) old_dl_ndi = h_dl.ndi(); old_ul_ndi = h_dl.ndi(); } - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.ul_crc_info(false), 0); ASSERT_FALSE(h_dl.has_pending_retx()); ASSERT_FALSE(h_ul.has_pending_retx()); @@ -367,7 +367,7 @@ TEST_F(single_harq_process_test, when_newtx_after_ack_then_ndi_flips) { float pucch_snr = 5; bool dl_ndi = h_dl.ndi(), ul_ndi = h_ul.ndi(); - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_view::status_update::acked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, pucch_snr), dl_harq_process_handle::status_update::acked); ASSERT_GE(h_ul.ul_crc_info(true), 0); h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value(); @@ -413,7 +413,7 @@ TEST_F(single_harq_process_test, when_ack_wait_timeout_reached_then_harq_is_avai } } -TEST_F(single_harq_process_test, when_harq_retx_is_cancelled_then_harq_nack_empties_it) +TEST_F(single_harq_process_test, when_harq_retx_is_cancelled_while_harq_waits_ack_then_harq_nack_empties_it) { h_dl.cancel_retxs(); h_ul.cancel_retxs(); @@ -421,12 +421,27 @@ TEST_F(single_harq_process_test, when_harq_retx_is_cancelled_then_harq_nack_empt ASSERT_TRUE(h_ul.is_waiting_ack()); ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), - dl_harq_process_view::status_update::nacked); + dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.ul_crc_info(false), 0); ASSERT_TRUE(h_dl.empty()); ASSERT_TRUE(h_ul.empty()); } +TEST_F(single_harq_process_test, + when_harq_retx_is_cancelled_while_harq_has_pending_retx_then_harq_is_emptied_right_away) +{ + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_handle::status_update::nacked); + ASSERT_EQ(h_ul.ul_crc_info(false), 0); + ASSERT_TRUE(h_dl.has_pending_retx()); + ASSERT_TRUE(h_ul.has_pending_retx()); + + h_dl.cancel_retxs(); + h_ul.cancel_retxs(); + ASSERT_TRUE(h_dl.empty()); + ASSERT_TRUE(h_ul.empty()); +} + // DL HARQ process with multi PUCCH test TEST_F(dl_harq_process_multi_pucch_test, when_dtx_received_after_ack_then_dtx_is_ignored) @@ -438,13 +453,13 @@ TEST_F(dl_harq_process_multi_pucch_test, when_dtx_received_after_ack_then_dtx_is // ACK received. ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), - dl_harq_process_view::status_update::no_update); + dl_harq_process_handle::status_update::no_update); // DTX received one slot late. run_slot(); ASSERT_TRUE(h_dl.is_waiting_ack()); ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::dtx, std::nullopt), - dl_harq_process_view::status_update::acked); + dl_harq_process_handle::status_update::acked); } // Note: When two F1 PUCCHs are decoded (one with SR and the other without), there is a small chance that none of them @@ -458,12 +473,12 @@ TEST_F(dl_harq_process_multi_pucch_test, when_stronger_ack_received_after_nack_t // NACK received. harq_id_t h_id = h_dl.id(); - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 1.0F), dl_harq_process_view::status_update::no_update); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 1.0F), dl_harq_process_handle::status_update::no_update); // ACK received. ASSERT_EQ(harq_ent.dl_harq(h_id), h_dl); ASSERT_TRUE(h_dl.is_waiting_ack()); - ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, 2.0F), dl_harq_process_view::status_update::acked); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, 2.0F), dl_harq_process_handle::status_update::acked); // HARQ should be empty. ASSERT_FALSE(harq_ent.dl_harq(h_id).has_value()); @@ -478,11 +493,11 @@ TEST_F(dl_harq_process_multi_pucch_test, for (unsigned i = 0; i != this->max_ack_wait_timeout + k1 + 1; ++i) { // Notify HARQ process with DTX (ACK not decoded). if (i == first_ack_slot) { - ASSERT_EQ(h_dl.dl_ack_info(ack_val, random_snr()), dl_harq_process_view::status_update::no_update); + ASSERT_EQ(h_dl.dl_ack_info(ack_val, random_snr()), dl_harq_process_handle::status_update::no_update); } // Before reaching the ack_wait_slots, the HARQ should be neither empty nor have pending reTX. - if (i < cell_harq_manager::SHORT_ACK_TIMEOUT_DTX + first_ack_slot) { + if (i < dl_harq_process_handle::SHORT_ACK_TIMEOUT_DTX + first_ack_slot) { ASSERT_FALSE(h_dl.has_pending_retx()); ASSERT_TRUE(h_dl.is_waiting_ack()); ASSERT_EQ(timeout_handler.last_ue_index, INVALID_DU_UE_INDEX); @@ -512,12 +527,12 @@ TEST_P(dl_harq_process_two_pucch_param_test, two_harq_acks_received) for (unsigned i = 0; i != max_ack_wait_timeout + k1 + 1; ++i) { if (i == first_ack_slot) { ASSERT_EQ(h_dl.dl_ack_info(static_cast(params.ack[0]), params.snr[0]), - dl_harq_process_view::status_update::no_update); + dl_harq_process_handle::status_update::no_update); } if (i == second_ack_slot) { ASSERT_EQ(h_dl.dl_ack_info(static_cast(params.ack[1]), params.snr[1]), - params.outcome ? dl_harq_process_view::status_update::acked - : dl_harq_process_view::status_update::nacked); + params.outcome ? dl_harq_process_handle::status_update::acked + : dl_harq_process_handle::status_update::nacked); } if (i < second_ack_slot) { @@ -586,7 +601,8 @@ TEST_F(single_ue_harq_entity_test, when_harq_is_nacked_then_harq_entity_finds_ha { auto h_dl = harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0); auto h_ul = harq_ent.alloc_ul_harq(current_slot, max_retxs); - ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), + dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); @@ -650,7 +666,7 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_entity_does_ ASSERT_EQ(harq_ent.find_dl_harq(current_slot + k1, 0), h_dl); ASSERT_EQ(harq_ent.find_ul_harq(current_slot + k2), h_ul); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), - dl_harq_process_view::status_update::nacked); + dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); ASSERT_EQ(harq_ent.find_pending_dl_retx(), h_dl); ASSERT_EQ(harq_ent.find_pending_ul_retx(), h_ul); @@ -665,7 +681,8 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_entity_does_ ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt); ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt); } - ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_view::status_update::nacked); + ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), + dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt); ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt); @@ -742,7 +759,7 @@ TEST_P(single_ue_harq_entity_2_bits_tester, handle_pucchs) // Check if HARQs timeout in case of HARQ-ACK set to DTX. if (check_timeout) { - for (unsigned i = 0; i != cell_harq_manager::SHORT_ACK_TIMEOUT_DTX; ++i) { + for (unsigned i = 0; i != dl_harq_process_handle::SHORT_ACK_TIMEOUT_DTX; ++i) { run_slot(); } for (unsigned i = 0; i != params.outcome.size(); ++i) { @@ -783,7 +800,7 @@ TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_acks_then_al for (unsigned i = 0; i != active_harqs; ++i) { auto h_dl = this->harq_ent.find_dl_harq(pucch_slot, i); ASSERT_EQ(h_dl->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), - dl_harq_process_view::status_update::acked); + dl_harq_process_handle::status_update::acked); } for (unsigned i = 0; i != h_dls.size(); ++i) { @@ -811,7 +828,7 @@ TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_nacks_then_a for (unsigned i = 0; i != active_harqs; ++i) { auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, i); ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), - dl_harq_process_view::status_update::nacked); + dl_harq_process_handle::status_update::nacked); } for (unsigned i = 0; i != h_dls.size(); ++i) { From afbce2652db81ff6ba9cc71bd74e140125de4785 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 14:32:02 +0200 Subject: [PATCH 394/407] sched: implementation of view of pending HARQ retxs --- .../ue_scheduling/cell_harq_manager.cpp | 10 + .../ue_scheduling/cell_harq_manager.h | 182 ++++++++++++------ .../ue_scheduling/harq_manager_test.cpp | 59 ++++++ 3 files changed, 191 insertions(+), 60 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 446dd4cf79..8c3b9e35a2 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -330,6 +330,16 @@ bool cell_harq_manager::contains(du_ue_index_t ue_idx) const return ue_idx < dl.ues.size() and dl.ues[ue_idx].free_harq_ids.size() != 0; } +dl_harq_pending_retx_list cell_harq_manager::pending_dl_retxs() +{ + return dl_harq_pending_retx_list{dl}; +} + +ul_harq_pending_retx_list cell_harq_manager::pending_ul_retxs() +{ + return ul_harq_pending_retx_list{ul}; +} + unique_ue_harq_entity cell_harq_manager::add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs) { diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index 8416741a9d..bda3324d3a 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -173,6 +173,7 @@ class base_harq_process_handle using harq_impl_type = std::conditional_t; public: + base_harq_process_handle() = default; base_harq_process_handle(harq_pool& pool_, unsigned harq_ref_idx_) : harq_repo(&pool_), harq_ref_idx(harq_ref_idx_) { srsran_sanity_check(harq_ref_idx < harq_repo->harqs.size(), "Invalid HARQ created"); @@ -180,6 +181,7 @@ class base_harq_process_handle "Empty HARQ process created"); } + rnti_t rnti() const { return fetch_impl().rnti; } harq_id_t id() const { return fetch_impl().h_id; } bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } @@ -227,61 +229,6 @@ struct ul_harq_sched_context { std::optional slice_id; }; -class cell_harq_manager -{ -public: - /// \brief Default timeout in slots after which the HARQ process assumes that the CRC/ACK went missing - /// (implementation-defined). - constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; - - cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, - std::unique_ptr notifier = nullptr, - unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS); - - /// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK - void slot_indication(slot_point sl_tx); - - /// Create new UE HARQ entity. - /// \param rnti RNTI of the UE - /// \param nof_dl_harq_procs Number of DL HARQ processes that the UE can support. This value is derived based on - /// the UE capabilities, and passed to the UE via RRC signalling. See TS38.331, "nrofHARQ-ProcessesForPDSCH". - /// Values: {2, 4, 6, 10, 12, 16}. - /// \param nof_ul_harq_procs Number of UL HARQ processes that gNB can support. This value is implementation-defined - /// and can up to 16 (there are up to 4 bits for HARQ-Id signalling). - unique_ue_harq_entity add_ue(du_ue_index_t ue_idx, - rnti_t crnti, - unsigned nof_dl_harq_procs = MAX_NOF_HARQS, - unsigned nof_ul_harq_procs = MAX_NOF_HARQS); - - /// Checks whether an UE with the provided ue index exists. - bool contains(du_ue_index_t ue_idx) const; - -private: - friend class unique_ue_harq_entity; - - void destroy_ue(du_ue_index_t ue_idx); - - /// \brief Called on every DL new Tx to allocate an DL HARQ process. - harq_utils::dl_harq_process_impl* new_dl_tx(du_ue_index_t ue_idx, - rnti_t rnti, - slot_point pdsch_slot, - unsigned k1, - unsigned max_harq_nof_retxs, - uint8_t harq_bit_idx); - - /// \brief Called on every UL new Tx to allocate an UL HARQ process. - harq_utils::ul_harq_process_impl* - new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs); - - std::unique_ptr timeout_notifier; - srslog::basic_logger& logger; - - slot_point last_sl_tx; - - harq_utils::cell_harq_repository dl; - harq_utils::cell_harq_repository ul; -}; - /// \brief Interface used to fetch and update the status of a DL HARQ process. /// \remark This handle acts like a view to an internal HARQ process. It is not a "unique" type that controls the /// lifetime of a HARQ. Avoid storing and using the same handle across different slots. @@ -297,10 +244,7 @@ class dl_harq_process_handle : public harq_utils::base_harq_process_handle using status_update = harq_utils::dl_harq_process_impl::status_update; using grant_params = harq_utils::dl_harq_process_impl::alloc_params; - dl_harq_process_handle(harq_utils::cell_harq_repository& harq_repo_, unsigned h_ref_idx_) : - base_type(harq_repo_, h_ref_idx_) - { - } + using base_type::base_type; using base_type::empty; using base_type::has_pending_retx; @@ -341,7 +285,7 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handle; public: - ul_harq_process_handle(harq_pool& harq_repo_, unsigned h_ref_idx) : base_type(harq_repo_, h_ref_idx) {} + using base_type::base_type; using base_type::empty; using base_type::has_pending_retx; @@ -367,6 +311,124 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handle +class harq_pending_retx_list_impl +{ + using harq_pool = harq_utils::cell_harq_repository; + using harq_impl_type = std::conditional_t; + using handle_type = std::conditional_t; + +public: + struct iterator { + using value_type = handle_type; + using reference = handle_type; + using pointer = std::optional; + using iterator_category = std::forward_iterator_tag; + + iterator(harq_pool& pool_, typename intrusive_double_linked_list::iterator it_) : + pool(&pool_), it(it_) + { + } + + reference operator++() + { + ++it; + return value(); + } + reference operator*() { return value(); } + reference value() + { + return it != pool->harq_pending_retx_list.end() ? handle_type{*pool, get_harq_ref_idx(*it)} : handle_type{}; + } + + bool operator==(const iterator& other) const { return pool == other.pool and it == other.it; } + bool operator!=(const iterator& other) const { return !(*this == other); } + + private: + unsigned get_harq_ref_idx(const harq_impl_type& h) { return &h - pool->harqs.data(); } + + harq_pool* pool; + typename intrusive_double_linked_list::iterator it; + }; + + explicit harq_pending_retx_list_impl(harq_pool& pool_) : pool(&pool_) {} + + bool empty() const { return pool->harq_pending_retx_list.empty(); } + + iterator begin() { return iterator{*pool, pool->harq_pending_retx_list.begin()}; } + iterator end() { return iterator{*pool, pool->harq_pending_retx_list.end()}; } + +private: + harq_pool* pool; +}; + +} // namespace harq_utils + +using dl_harq_pending_retx_list = harq_utils::harq_pending_retx_list_impl; +using ul_harq_pending_retx_list = harq_utils::harq_pending_retx_list_impl; + +/// Manager of all HARQ processes in a given cell. +class cell_harq_manager +{ +public: + /// \brief Default timeout in slots after which the HARQ process assumes that the CRC/ACK went missing + /// (implementation-defined). + constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; + + cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, + std::unique_ptr notifier = nullptr, + unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS); + + /// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK + void slot_indication(slot_point sl_tx); + + /// Create new UE HARQ entity. + /// \param rnti RNTI of the UE + /// \param nof_dl_harq_procs Number of DL HARQ processes that the UE can support. This value is derived based on + /// the UE capabilities, and passed to the UE via RRC signalling. See TS38.331, "nrofHARQ-ProcessesForPDSCH". + /// Values: {2, 4, 6, 10, 12, 16}. + /// \param nof_ul_harq_procs Number of UL HARQ processes that gNB can support. This value is implementation-defined + /// and can up to 16 (there are up to 4 bits for HARQ-Id signalling). + unique_ue_harq_entity add_ue(du_ue_index_t ue_idx, + rnti_t crnti, + unsigned nof_dl_harq_procs = MAX_NOF_HARQS, + unsigned nof_ul_harq_procs = MAX_NOF_HARQS); + + /// Checks whether an UE with the provided ue index exists. + bool contains(du_ue_index_t ue_idx) const; + + /// Retrieve list of HARQ processes with pending retxs. + dl_harq_pending_retx_list pending_dl_retxs(); + ul_harq_pending_retx_list pending_ul_retxs(); + +private: + friend class unique_ue_harq_entity; + + void destroy_ue(du_ue_index_t ue_idx); + + /// \brief Called on every DL new Tx to allocate an DL HARQ process. + harq_utils::dl_harq_process_impl* new_dl_tx(du_ue_index_t ue_idx, + rnti_t rnti, + slot_point pdsch_slot, + unsigned k1, + unsigned max_harq_nof_retxs, + uint8_t harq_bit_idx); + + /// \brief Called on every UL new Tx to allocate an UL HARQ process. + harq_utils::ul_harq_process_impl* + new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs); + + std::unique_ptr timeout_notifier; + srslog::basic_logger& logger; + + slot_point last_sl_tx; + + harq_utils::cell_harq_repository dl; + harq_utils::cell_harq_repository ul; +}; + class unique_ue_harq_entity { public: diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index f30d0a5a12..8cd4e3198f 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -877,3 +877,62 @@ TEST_F(multi_ue_harq_manager_test, when_harq_entities_are_destroyed_then_pending run_slot(); ASSERT_EQ(this->timeout_handler.last_ue_index, to_du_ue_index(2)); } + +TEST_F(multi_ue_harq_manager_test, when_harq_entities_are_nacked_then_they_appear_in_list_of_harqs_with_pending_retxs) +{ + const unsigned k1 = 4, k2 = 6, max_retxs = 4; + unique_ue_harq_entity harq_ent1 = cell_harqs.add_ue(to_du_ue_index(1), to_rnti(0x4601), nof_harqs, nof_harqs); + unique_ue_harq_entity harq_ent2 = cell_harqs.add_ue(to_du_ue_index(2), to_rnti(0x4602), nof_harqs, nof_harqs); + + ASSERT_TRUE(cell_harqs.pending_dl_retxs().empty()); + ASSERT_TRUE(cell_harqs.pending_ul_retxs().empty()); + + auto h_dl1 = harq_ent1.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_dl2 = harq_ent2.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul1 = harq_ent1.alloc_ul_harq(current_slot + k2, max_retxs); + auto h_ul2 = harq_ent2.alloc_ul_harq(current_slot + k2, max_retxs); + ASSERT_TRUE(h_dl1.has_value() and h_dl2.has_value() and h_ul1.has_value() and h_ul2.has_value()); + + ASSERT_TRUE(cell_harqs.pending_dl_retxs().empty()); + ASSERT_TRUE(cell_harqs.pending_ul_retxs().empty()); + ASSERT_EQ(cell_harqs.pending_dl_retxs().begin(), cell_harqs.pending_dl_retxs().end()); + + ASSERT_EQ(harq_ent1.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_handle::status_update::nacked); + ASSERT_EQ(harq_ent1.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); + ASSERT_EQ(harq_ent2.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_handle::status_update::nacked); + ASSERT_EQ(harq_ent2.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); + + // HARQs are in the list of pending retxs. + ASSERT_FALSE(cell_harqs.pending_dl_retxs().empty()); + ASSERT_FALSE(cell_harqs.pending_ul_retxs().empty()); + ASSERT_NE(cell_harqs.pending_dl_retxs().begin(), cell_harqs.pending_dl_retxs().end()); + unsigned count = 0; + for (dl_harq_process_handle h : cell_harqs.pending_dl_retxs()) { + ASSERT_TRUE(h.has_pending_retx()); + count++; + } + ASSERT_EQ(count, 2); + count = 0; + for (ul_harq_process_handle h : cell_harqs.pending_ul_retxs()) { + ASSERT_TRUE(h.has_pending_retx()); + count++; + } + + // If we cancel the HARQ, it should not show up in the list of pending reTx. + h_dl2->cancel_retxs(); + h_ul1->cancel_retxs(); + count = 0; + for (dl_harq_process_handle h : cell_harqs.pending_dl_retxs()) { + ASSERT_EQ(h.rnti(), to_rnti(0x4601)); + count++; + } + ASSERT_EQ(count, 1); + count = 0; + for (ul_harq_process_handle h : cell_harqs.pending_ul_retxs()) { + ASSERT_EQ(h.rnti(), to_rnti(0x4602)); + count++; + } + ASSERT_EQ(count, 1); +} From 9b9c5dceb941fdd16b83aeee2f29a742fcaf20dd Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 15:12:48 +0200 Subject: [PATCH 395/407] sched: pending HARQ retxs are now ordered based on time of ACK arrival --- include/srsran/adt/intrusive_list.h | 37 +++++++++++++++++-- .../ue_scheduling/cell_harq_manager.cpp | 2 +- .../ue_scheduling/harq_manager_test.cpp | 32 ++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/include/srsran/adt/intrusive_list.h b/include/srsran/adt/intrusive_list.h index 6f495e2a43..78034cf142 100644 --- a/include/srsran/adt/intrusive_list.h +++ b/include/srsran/adt/intrusive_list.h @@ -137,7 +137,7 @@ class intrusive_double_linked_list template class iterator_impl { - using elem_t = typename std::conditional::value, const node_t, node_t>::type; + using elem_t = std::conditional_t::value, const node_t, node_t>; public: using iterator_category = std::bidirectional_iterator_tag; @@ -173,24 +173,28 @@ class intrusive_double_linked_list intrusive_double_linked_list() { - static_assert(std::is_base_of::value, + static_assert(std::is_base_of_v, "Provided template argument T must have intrusive_forward_list_element as base class"); } intrusive_double_linked_list(const intrusive_double_linked_list&) = default; - intrusive_double_linked_list(intrusive_double_linked_list&& other) noexcept : node(other.node) + intrusive_double_linked_list(intrusive_double_linked_list&& other) noexcept : node(other.node), tail(other.tail) { other.node = nullptr; + other.tail = nullptr; } intrusive_double_linked_list& operator=(const intrusive_double_linked_list&) = default; intrusive_double_linked_list& operator=(intrusive_double_linked_list&& other) noexcept { node = other.node; + tail = other.tail; other.node = nullptr; + other.tail = nullptr; return *this; } ~intrusive_double_linked_list() { clear(); } T& front() const { return *static_cast(node); } + T& back() const { return *static_cast(tail); } void push_front(T* t) { @@ -199,15 +203,36 @@ class intrusive_double_linked_list new_head->next_node = node; if (node != nullptr) { node->prev_node = new_head; + } else { + tail = new_head; } node = new_head; } + void push_back(T* t) + { + node_t* new_tail = static_cast(t); + new_tail->prev_node = tail; + new_tail->next_node = nullptr; + if (tail != nullptr) { + tail->next_node = new_tail; + } else { + node = new_tail; + } + tail = new_tail; + } + void pop(T* t) { node_t* to_rem = static_cast(t); if (to_rem == node) { node = to_rem->next_node; + if (node == nullptr) { + tail = nullptr; + } + } else if (to_rem == tail) { + tail = to_rem->prev_node; + // tail==head checked in first if condition. } if (to_rem->prev_node != nullptr) { to_rem->prev_node->next_node = to_rem->next_node; @@ -218,7 +243,11 @@ class intrusive_double_linked_list to_rem->next_node = nullptr; to_rem->prev_node = nullptr; } + void pop_front() { pop(static_cast(node)); } + + void pop_back() { pop(static_cast(tail)); } + void clear() { while (node != nullptr) { @@ -227,6 +256,7 @@ class intrusive_double_linked_list torem->next_node = nullptr; torem->prev_node = nullptr; } + tail = nullptr; } bool empty() const { return node == nullptr; } @@ -238,6 +268,7 @@ class intrusive_double_linked_list private: node_t* node = nullptr; + node_t* tail = nullptr; }; } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 8c3b9e35a2..6616543366 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -217,7 +217,7 @@ void cell_harq_repository::set_pending_retx(harq_type& h) harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].pop(&h); // Add HARQ to pending Retx list. - harq_pending_retx_list.push_front(&h); + harq_pending_retx_list.push_back(&h); // Update HARQ process state. h.status = harq_state_t::pending_retx; diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 8cd4e3198f..8d8dd5ae26 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -936,3 +936,35 @@ TEST_F(multi_ue_harq_manager_test, when_harq_entities_are_nacked_then_they_appea } ASSERT_EQ(count, 1); } + +TEST_F(multi_ue_harq_manager_test, pending_harq_retxs_are_ordered_from_oldest_to_newest_ack) +{ + const unsigned k1 = 4, k2 = 6, max_retxs = 4; + unique_ue_harq_entity harq_ent1 = cell_harqs.add_ue(to_du_ue_index(1), to_rnti(0x4601), nof_harqs, nof_harqs); + unique_ue_harq_entity harq_ent2 = cell_harqs.add_ue(to_du_ue_index(2), to_rnti(0x4602), nof_harqs, nof_harqs); + + ASSERT_TRUE(harq_ent1.alloc_dl_harq(current_slot, k1, max_retxs, 0).has_value()); + ASSERT_TRUE(harq_ent2.alloc_ul_harq(current_slot + k2, max_retxs).has_value()); + ASSERT_TRUE(harq_ent2.alloc_dl_harq(current_slot, k1, max_retxs, 0).has_value()); + ASSERT_TRUE(harq_ent1.alloc_ul_harq(current_slot + k2, max_retxs).has_value()); + + ASSERT_EQ(harq_ent1.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_handle::status_update::nacked); + ASSERT_EQ(harq_ent2.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + dl_harq_process_handle::status_update::nacked); + ASSERT_EQ(harq_ent2.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); + ASSERT_EQ(harq_ent1.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); + + unsigned count = 0; + for (dl_harq_process_handle h : cell_harqs.pending_dl_retxs()) { + ASSERT_EQ(h.rnti(), to_rnti(0x4601 + count)); + count++; + } + ASSERT_EQ(count, 2); + count = 0; + for (ul_harq_process_handle h : cell_harqs.pending_ul_retxs()) { + ASSERT_EQ(h.rnti(), to_rnti(0x4602 - count)); + count++; + } + ASSERT_EQ(count, 2); +} From a420c5547aca1017965b1138636e7c8d9ce160ec Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Aug 2024 17:34:53 +0200 Subject: [PATCH 396/407] sched: add fix for HARQs trapped in pending retx --- .../ue_scheduling/cell_harq_manager.cpp | 48 +++++++++++++------ .../ue_scheduling/cell_harq_manager.h | 13 +++-- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 6616543366..66ba626a7b 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -9,6 +9,7 @@ */ #include "cell_harq_manager.h" +#include "../cell/resource_grid_util.h" #include "srsran/scheduler/scheduler_slot_handler.h" using namespace srsran; @@ -46,21 +47,41 @@ cell_harq_repository::cell_harq_repository(unsigned max_ues, ues[i].harqs.reserve(MAX_NOF_HARQS); } - const unsigned RING_SIZE = 320; // TODO: use function to define this value. It must account the timeout arg and k - // values - harq_timeout_wheel.resize(RING_SIZE); + harq_timeout_wheel.resize(get_allocator_ring_size_gt_min(max_ack_wait_timeout + get_max_slot_ul_alloc_delay(0))); } template void cell_harq_repository::slot_indication(slot_point sl_tx) { + last_sl_ind = sl_tx; + // Handle HARQs that timed out. auto& harqs_timing_out = harq_timeout_wheel[sl_tx.to_uint() % harq_timeout_wheel.size()]; while (not harqs_timing_out.empty()) { handle_harq_ack_timeout(harqs_timing_out.front(), sl_tx); } - last_sl_ind = sl_tx; + // Handle HARQs with pending reTx that are trapped (never scheduled). This is a safety mechanism to account for a + // potential bug or limitation in the scheduler policy that is leaving HARQ processes with pending reTxs for too long. + // Note: we assume that the list is ordered based on when they were last ACKed. + while (not harq_pending_retx_list.empty()) { + auto& h = harq_pending_retx_list.front(); + srsran_sanity_check(h.status == harq_state_t::pending_retx, "HARQ process in wrong state"); + // [Implementation-defined] Maximum time we give to the scheduler policy to retransmit a HARQ process. + const unsigned max_nof_slots_for_retx = last_sl_ind.nof_slots_per_system_frame() / 4; + if (last_sl_ind < (h.slot_ack + max_nof_slots_for_retx)) { + break; + } + + // HARQ is trapped. Remove it. + logger.warning( + "rnti={} h_id={}: Discarding {} HARQ. Cause: Too much time has passed since the last HARQ " + "transmission. The scheduler policy is likely not prioritizing retransmissions of old HARQ processes.", + h.rnti, + h.h_id, + IsDl ? "DL" : "UL"); + dealloc_harq(h); + } } template @@ -306,6 +327,15 @@ unsigned cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, template struct harq_utils::cell_harq_repository; template struct harq_utils::cell_harq_repository; +template +void harq_utils::base_harq_process_handle::cancel_retxs() +{ + harq_repo->cancel_retxs(fetch_impl()); +} + +template class harq_utils::base_harq_process_handle; +template class harq_utils::base_harq_process_handle; + // Cell HARQ manager. cell_harq_manager::cell_harq_manager(unsigned max_ues, @@ -453,11 +483,6 @@ void dl_harq_process_handle::increment_pucch_counter() ++fetch_impl().pucch_ack_to_receive; } -void dl_harq_process_handle::cancel_retxs() -{ - harq_repo->cancel_retxs(fetch_impl()); -} - void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) { srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); @@ -511,11 +536,6 @@ int ul_harq_process_handle::ul_crc_info(bool ack) return ack ? (int)h.prev_tx_params.tbs_bytes : 0; } -void ul_harq_process_handle::cancel_retxs() -{ - harq_repo->cancel_retxs(fetch_impl()); -} - void ul_harq_process_handle::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) { ul_harq_process_impl& impl = fetch_impl(); diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index bda3324d3a..8fd78472bd 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -193,6 +193,11 @@ class base_harq_process_handle unsigned nof_retxs() const { return fetch_impl().nof_retxs; } bool ndi() const { return fetch_impl().ndi; } + /// \brief Cancels any retransmissions for this HARQ process. + /// If the HARQ process has a pending retransmission, it is reset. If the ACK/CRC info has not been received yet, the + /// HARQ process waits for it to arrive before being reset. + void cancel_retxs(); + bool operator==(const base_harq_process_handle& other) const { return harq_repo == other.harq_repo and harq_ref_idx == other.harq_ref_idx; @@ -255,6 +260,8 @@ class dl_harq_process_handle : public harq_utils::base_harq_process_handle using base_type::ndi; using base_type::nof_retxs; + using base_type::cancel_retxs; + [[nodiscard]] bool new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx); /// \brief Update the state of the DL HARQ process waiting for an HARQ-ACK. @@ -265,8 +272,6 @@ class dl_harq_process_handle : public harq_utils::base_harq_process_handle void increment_pucch_counter(); - void cancel_retxs(); - /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that /// they can be later fetched and optionally reused. void save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch); @@ -296,14 +301,14 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handle Date: Tue, 27 Aug 2024 19:52:38 +0200 Subject: [PATCH 397/407] sched: add more tx_params to HARQ manager allocations --- .../ue_scheduling/cell_harq_manager.cpp | 19 +++++++++++++------ .../ue_scheduling/cell_harq_manager.h | 12 +++++++++++- .../ue_scheduling/harq_manager_test.cpp | 10 ++++++---- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp index 66ba626a7b..8f275df979 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.cpp @@ -255,12 +255,10 @@ bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, // Remove HARQ from pending Retx list. harq_pending_retx_list.pop(&h); - h.status = harq_state_t::waiting_ack; - h.slot_tx = sl_tx; - h.slot_ack = sl_ack; - h.ndi = !h.ndi; - h.ack_on_timeout = false; - h.retxs_cancelled = false; + h.status = harq_state_t::waiting_ack; + h.slot_tx = sl_tx; + h.slot_ack = sl_ack; + h.ack_on_timeout = false; h.nof_retxs++; // Add HARQ to the timeout list. @@ -487,6 +485,8 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, { srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); dl_harq_process_impl& impl = fetch_impl(); + srsran_sanity_check(pdsch.rnti == impl.rnti, "RNTI mismatch"); + srsran_sanity_check(pdsch.harq_id == impl.h_id, "HARQ-id mismatch"); srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, "Setting allocation parameters for DL HARQ process id={} in invalid state", id()); @@ -497,8 +497,11 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, if (impl.nof_retxs == 0) { prev_params.tbs_bytes = cw.tb_size_bytes; prev_params.dci_cfg_type = ctx.dci_cfg_type; + prev_params.nof_layers = pdsch.nof_layers; prev_params.olla_mcs = ctx.olla_mcs; prev_params.slice_id = ctx.slice_id; + prev_params.cqi = ctx.cqi.has_value() ? ctx.cqi.value() : cqi_value{1}; + prev_params.is_fallback = ctx.is_fallback; } else { srsran_assert(ctx.dci_cfg_type == prev_params.dci_cfg_type, "DCI format and RNTI type cannot change during DL HARQ retxs"); @@ -510,6 +513,8 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, prev_params.rbs, cw.mcs_index, pdsch.rbs); + srsran_assert(prev_params.nof_layers == pdsch.nof_layers, "Number of layers cannot change during HARQ retxs"); + srsran_assert(prev_params.is_fallback == ctx.is_fallback, "Fallback state cannot change across DL HARQ retxs"); } prev_params.mcs_table = cw.mcs_table; prev_params.mcs = cw.mcs_index; @@ -539,6 +544,8 @@ int ul_harq_process_handle::ul_crc_info(bool ack) void ul_harq_process_handle::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) { ul_harq_process_impl& impl = fetch_impl(); + srsran_sanity_check(pusch.rnti == impl.rnti, "RNTI mismatch"); + srsran_sanity_check(pusch.harq_id == impl.h_id, "HARQ-id mismatch"); srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, "Setting allocation parameters for DL HARQ process id={} in invalid state", id()); diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/ue_scheduling/cell_harq_manager.h index 8fd78472bd..28f9e23fa7 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/ue_scheduling/cell_harq_manager.h @@ -222,6 +222,10 @@ struct dl_harq_sched_context { std::optional olla_mcs; /// RAN slice identifier of the slice to which PDSCH belongs to. std::optional slice_id; + /// CQI value at the moment of newTx. + std::optional cqi; + /// Whether the HARQ allocation was done in fallback mode. + bool is_fallback = false; }; /// \brief Context of the scheduler during the current PUSCH allocation. @@ -290,6 +294,8 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handle; public: + using grant_params = harq_utils::ul_harq_process_impl::alloc_params; + using base_type::base_type; using base_type::empty; @@ -311,9 +317,11 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handle; using ul_harq_pending_retx_list = harq_utils::harq_pending_retx_list_impl; @@ -434,6 +443,7 @@ class cell_harq_manager harq_utils::cell_harq_repository ul; }; +/// HARQ entity that manages a set of HARQ processes of a single UE. class unique_ue_harq_entity { public: diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp index 8d8dd5ae26..37b9706a1b 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp @@ -31,6 +31,8 @@ mac_harq_ack_report_status get_random_harq_ack() pdsch_information make_dummy_pdsch_info() { pdsch_information pdsch; + pdsch.rnti = to_rnti(0x4601); + pdsch.harq_id = to_harq_id(0); pdsch.codewords.resize(1); pdsch.codewords[0].mcs_table = srsran::pdsch_mcs_table::qam64; pdsch.codewords[0].mcs_index = 10; @@ -42,6 +44,8 @@ pdsch_information make_dummy_pdsch_info() pusch_information make_dummy_pusch_info() { pusch_information pusch; + pusch.rnti = to_rnti(0x4601); + pusch.harq_id = to_harq_id(0); pusch.mcs_table = pusch_mcs_table::qam64; pusch.mcs_index = 10; pusch.tb_size_bytes = 10000; @@ -350,10 +354,8 @@ TEST_F(single_harq_process_test, when_max_retxs_reached_then_harq_becomes_empty) ASSERT_TRUE(h_ul.new_retx(current_slot + k2)); ASSERT_EQ(h_dl.nof_retxs(), i + 1); ASSERT_EQ(h_ul.nof_retxs(), i + 1); - ASSERT_NE(old_dl_ndi, h_dl.ndi()); - ASSERT_NE(old_ul_ndi, h_ul.ndi()); - old_dl_ndi = h_dl.ndi(); - old_ul_ndi = h_dl.ndi(); + ASSERT_EQ(old_dl_ndi, h_dl.ndi()); + ASSERT_EQ(old_ul_ndi, h_ul.ndi()); } ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.ul_crc_info(false), 0); From 0c4f47c7035434714b68bd6da1c7e04948c6fe07 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 28 Aug 2024 16:17:29 +0200 Subject: [PATCH 398/407] sched: move cell harq manager to scheduler/cell folder --- lib/scheduler/cell/CMakeLists.txt | 3 +- .../cell_harq_manager.cpp | 29 +++++++++++-------- .../cell_harq_manager.h | 7 +++-- lib/scheduler/ue_scheduling/CMakeLists.txt | 1 - tests/unittests/scheduler/CMakeLists.txt | 2 +- .../CMakeLists.txt | 9 ++++-- .../cell_harq_manager_test.cpp} | 6 ++-- .../cell_resource_grid_test.cpp | 0 .../sched_prb_test.cpp | 0 .../scheduler/ue_scheduling/CMakeLists.txt | 1 - 10 files changed, 34 insertions(+), 24 deletions(-) rename lib/scheduler/{ue_scheduling => cell}/cell_harq_manager.cpp (95%) rename lib/scheduler/{ue_scheduling => cell}/cell_harq_manager.h (98%) rename tests/unittests/scheduler/{cell_resource_grid => cell}/CMakeLists.txt (57%) rename tests/unittests/scheduler/{ue_scheduling/harq_manager_test.cpp => cell/cell_harq_manager_test.cpp} (99%) rename tests/unittests/scheduler/{cell_resource_grid => cell}/cell_resource_grid_test.cpp (100%) rename tests/unittests/scheduler/{cell_resource_grid => cell}/sched_prb_test.cpp (100%) diff --git a/lib/scheduler/cell/CMakeLists.txt b/lib/scheduler/cell/CMakeLists.txt index 26bfd79a51..5612ce9d97 100644 --- a/lib/scheduler/cell/CMakeLists.txt +++ b/lib/scheduler/cell/CMakeLists.txt @@ -10,4 +10,5 @@ add_library(sched_cell OBJECT vrb_alloc.cpp resource_block_group.cpp resource_grid.cpp - scheduler_prb.cpp) + scheduler_prb.cpp + cell_harq_manager.cpp) diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp similarity index 95% rename from lib/scheduler/ue_scheduling/cell_harq_manager.cpp rename to lib/scheduler/cell/cell_harq_manager.cpp index 8f275df979..b88a4d8311 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -9,7 +9,7 @@ */ #include "cell_harq_manager.h" -#include "../cell/resource_grid_util.h" +#include "resource_grid_util.h" #include "srsran/scheduler/scheduler_slot_handler.h" using namespace srsran; @@ -30,12 +30,16 @@ class noop_harq_timeout_notifier : public harq_timeout_notifier template cell_harq_repository::cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_timeout, + unsigned max_harqs_per_ue_, harq_timeout_notifier& timeout_notifier_, srslog::basic_logger& logger_) : - max_ack_wait_in_slots(max_ack_wait_timeout), timeout_notifier(timeout_notifier_), logger(logger_) + max_ack_wait_in_slots(max_ack_wait_timeout), + max_harqs_per_ue(max_harqs_per_ue_), + timeout_notifier(timeout_notifier_), + logger(logger_) { - harqs.resize(MAX_NOF_HARQS * max_ues); - free_harqs.resize(MAX_NOF_HARQS * max_ues); + harqs.resize(max_harqs_per_ue * max_ues); + free_harqs.resize(max_harqs_per_ue * max_ues); for (unsigned i = 0; i != free_harqs.size(); ++i) { free_harqs[i] = free_harqs.size() - i - 1; } @@ -43,8 +47,8 @@ cell_harq_repository::cell_harq_repository(unsigned max_ues, // Reserve space in advance for UEs. ues.resize(max_ues); for (unsigned i = 0; i != max_ues; i++) { - ues[i].free_harq_ids.reserve(MAX_NOF_HARQS); - ues[i].harqs.reserve(MAX_NOF_HARQS); + ues[i].free_harq_ids.reserve(max_harqs_per_ue); + ues[i].harqs.reserve(max_harqs_per_ue); } harq_timeout_wheel.resize(get_allocator_ring_size_gt_min(max_ack_wait_timeout + get_max_slot_ul_alloc_delay(0))); @@ -337,18 +341,19 @@ template class harq_utils::base_harq_process_handle; // Cell HARQ manager. cell_harq_manager::cell_harq_manager(unsigned max_ues, + unsigned max_harqs_per_ue_, std::unique_ptr notifier, unsigned max_ack_wait_timeout) : + max_harqs_per_ue(max_harqs_per_ue_), timeout_notifier(notifier != nullptr ? std::move(notifier) : std::make_unique()), logger(srslog::fetch_basic_logger("SCHED")), - dl(max_ues, max_ack_wait_timeout, *timeout_notifier, logger), - ul(max_ues, max_ack_wait_timeout, *timeout_notifier, logger) + dl(max_ues, max_ack_wait_timeout, max_harqs_per_ue, *timeout_notifier, logger), + ul(max_ues, max_ack_wait_timeout, max_harqs_per_ue, *timeout_notifier, logger) { } void cell_harq_manager::slot_indication(slot_point sl_tx) { - last_sl_tx = sl_tx; dl.slot_indication(sl_tx); ul.slot_indication(sl_tx); } @@ -371,9 +376,9 @@ ul_harq_pending_retx_list cell_harq_manager::pending_ul_retxs() unique_ue_harq_entity cell_harq_manager::add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs) { - srsran_sanity_check(nof_dl_harq_procs > 0, "Invalid number of HARQs"); - srsran_sanity_check(nof_ul_harq_procs > 0, "Invalid number of HARQs"); - srsran_sanity_check(ue_idx < dl.ues.size(), "Invalid ue_index"); + srsran_assert(nof_dl_harq_procs <= max_harqs_per_ue and nof_dl_harq_procs > 0, "Invalid number of DL HARQs"); + srsran_assert(nof_ul_harq_procs <= max_harqs_per_ue and nof_ul_harq_procs > 0, "Invalid number of DL HARQs"); + srsran_assert(ue_idx < dl.ues.size(), "Invalid ue_index"); srsran_assert(not contains(ue_idx), "Creating UE with duplicate ue_index"); dl.reserve_ue_harqs(ue_idx, nof_dl_harq_procs); ul.reserve_ue_harqs(ue_idx, nof_ul_harq_procs); diff --git a/lib/scheduler/ue_scheduling/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h similarity index 98% rename from lib/scheduler/ue_scheduling/cell_harq_manager.h rename to lib/scheduler/cell/cell_harq_manager.h index 28f9e23fa7..9bf4a55cd5 100644 --- a/lib/scheduler/ue_scheduling/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -21,7 +21,6 @@ #include "srsran/scheduler/harq_id.h" #include "srsran/scheduler/scheduler_dci.h" #include "srsran/srslog/srslog.h" -#include namespace srsran { @@ -133,11 +132,13 @@ struct cell_harq_repository { cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_in_slots, + unsigned max_harqs_per_ue, harq_timeout_notifier& timeout_notifier_, srslog::basic_logger& logger_); /// Maximum value of time interval, in slots, before the HARQ process assumes that the ACK/CRC went missing. const unsigned max_ack_wait_in_slots; + const unsigned max_harqs_per_ue; harq_timeout_notifier& timeout_notifier; srslog::basic_logger& logger; @@ -392,6 +393,7 @@ class cell_harq_manager constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U; cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, + unsigned max_harqs_per_ue = MAX_NOF_HARQS, std::unique_ptr notifier = nullptr, unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS); @@ -434,11 +436,10 @@ class cell_harq_manager harq_utils::ul_harq_process_impl* new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs); + const unsigned max_harqs_per_ue; std::unique_ptr timeout_notifier; srslog::basic_logger& logger; - slot_point last_sl_tx; - harq_utils::cell_harq_repository dl; harq_utils::cell_harq_repository ul; }; diff --git a/lib/scheduler/ue_scheduling/CMakeLists.txt b/lib/scheduler/ue_scheduling/CMakeLists.txt index ad638d1ccb..e4363997a6 100644 --- a/lib/scheduler/ue_scheduling/CMakeLists.txt +++ b/lib/scheduler/ue_scheduling/CMakeLists.txt @@ -8,7 +8,6 @@ set(SOURCES harq_process.cpp - cell_harq_manager.cpp dl_logical_channel_manager.cpp ul_logical_channel_manager.cpp ta_manager.cpp diff --git a/tests/unittests/scheduler/CMakeLists.txt b/tests/unittests/scheduler/CMakeLists.txt index 2e729ad5c9..4e99a8683e 100644 --- a/tests/unittests/scheduler/CMakeLists.txt +++ b/tests/unittests/scheduler/CMakeLists.txt @@ -12,7 +12,7 @@ include_directories(../../..) add_subdirectory(test_utils) add_subdirectory(support) -add_subdirectory(cell_resource_grid) +add_subdirectory(cell) add_subdirectory(common_scheduling) add_subdirectory(ue_scheduling) add_subdirectory(uci_and_pucch) diff --git a/tests/unittests/scheduler/cell_resource_grid/CMakeLists.txt b/tests/unittests/scheduler/cell/CMakeLists.txt similarity index 57% rename from tests/unittests/scheduler/cell_resource_grid/CMakeLists.txt rename to tests/unittests/scheduler/cell/CMakeLists.txt index 6ac79e0ce4..566f207847 100644 --- a/tests/unittests/scheduler/cell_resource_grid/CMakeLists.txt +++ b/tests/unittests/scheduler/cell/CMakeLists.txt @@ -6,13 +6,16 @@ # the distribution. # -add_executable(cell_resource_grid_test sched_prb_test.cpp cell_resource_grid_test.cpp) -target_link_libraries(cell_resource_grid_test +add_executable(scheduler_cell_resource_test + sched_prb_test.cpp + cell_resource_grid_test.cpp + cell_harq_manager_test.cpp) +target_link_libraries(scheduler_cell_resource_test srsran_sched srslog mac_configuration_helpers sched_config gtest gtest_main) -gtest_discover_tests(cell_resource_grid_test) +gtest_discover_tests(scheduler_cell_resource_test) diff --git a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp similarity index 99% rename from tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp rename to tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index 37b9706a1b..a4ff2ff543 100644 --- a/tests/unittests/scheduler/ue_scheduling/harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -8,7 +8,7 @@ * */ -#include "lib/scheduler/ue_scheduling/cell_harq_manager.h" +#include "lib/scheduler/cell/cell_harq_manager.h" #include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/test_utils.h" #include @@ -92,7 +92,8 @@ class dummy_harq_timeout_handler class base_harq_manager_test { protected: - base_harq_manager_test(unsigned nof_ues) : cell_harqs(nof_ues, timeout_handler.make_notifier(), max_ack_wait_timeout) + base_harq_manager_test(unsigned nof_ues) : + cell_harqs(nof_ues, max_harqs_per_ue, timeout_handler.make_notifier(), max_ack_wait_timeout) { logger.set_level(srslog::basic_levels::warning); srslog::init(); @@ -109,6 +110,7 @@ class base_harq_manager_test } const unsigned max_ack_wait_timeout = 16; + const unsigned max_harqs_per_ue = 16; dummy_harq_timeout_handler timeout_handler; srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); diff --git a/tests/unittests/scheduler/cell_resource_grid/cell_resource_grid_test.cpp b/tests/unittests/scheduler/cell/cell_resource_grid_test.cpp similarity index 100% rename from tests/unittests/scheduler/cell_resource_grid/cell_resource_grid_test.cpp rename to tests/unittests/scheduler/cell/cell_resource_grid_test.cpp diff --git a/tests/unittests/scheduler/cell_resource_grid/sched_prb_test.cpp b/tests/unittests/scheduler/cell/sched_prb_test.cpp similarity index 100% rename from tests/unittests/scheduler/cell_resource_grid/sched_prb_test.cpp rename to tests/unittests/scheduler/cell/sched_prb_test.cpp diff --git a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt index ae0719fbd7..cac7281755 100644 --- a/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt +++ b/tests/unittests/scheduler/ue_scheduling/CMakeLists.txt @@ -8,7 +8,6 @@ add_executable(ue_scheduler_test logical_channel_test.cpp - harq_manager_test.cpp fallback_scheduler_test.cpp ue_cell_test.cpp ue_configuration_test.cpp From 9b8eb8b9401f0087a229cd09d14a1de40d17df1d Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 29 Aug 2024 12:10:34 +0200 Subject: [PATCH 399/407] sched: refactor cell_harq_manager to fix NDI issue --- lib/scheduler/cell/cell_harq_manager.cpp | 237 ++++++++---------- lib/scheduler/cell/cell_harq_manager.h | 112 ++++----- .../scheduler/cell/cell_harq_manager_test.cpp | 37 +++ 3 files changed, 190 insertions(+), 196 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index b88a4d8311..03304a8e28 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -38,13 +38,7 @@ cell_harq_repository::cell_harq_repository(unsigned max_ues, timeout_notifier(timeout_notifier_), logger(logger_) { - harqs.resize(max_harqs_per_ue * max_ues); - free_harqs.resize(max_harqs_per_ue * max_ues); - for (unsigned i = 0; i != free_harqs.size(); ++i) { - free_harqs[i] = free_harqs.size() - i - 1; - } - - // Reserve space in advance for UEs. + // Reserve space in advance for UEs and their HARQs. ues.resize(max_ues); for (unsigned i = 0; i != max_ues; i++) { ues[i].free_harq_ids.reserve(max_harqs_per_ue); @@ -122,38 +116,24 @@ void cell_harq_repository::handle_harq_ack_timeout(harq_type& h, slot_poin dealloc_harq(h); } -template -unsigned cell_harq_repository::get_harq_ref_idx(const harq_type& h) const -{ - return &h - harqs.data(); -} - template typename cell_harq_repository::harq_type* cell_harq_repository::alloc_harq(du_ue_index_t ue_idx, - rnti_t rnti, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs) { ue_harq_entity_impl& ue_harq_entity = ues[ue_idx]; - if (free_harqs.empty() or ue_harq_entity.free_harq_ids.empty()) { + if (ue_harq_entity.free_harq_ids.empty()) { return nullptr; } // Allocation of free HARQ-id for the UE. const harq_id_t h_id = ue_harq_entity.free_harq_ids.back(); ue_harq_entity.free_harq_ids.pop_back(); - - // Allocation of DL HARQ process for the UE. - unsigned harq_ref_idx = free_harqs.back(); - free_harqs.pop_back(); - ue_harq_entity.harqs[h_id] = harq_ref_idx; - harq_type& h = harqs[harq_ref_idx]; + harq_type& h = ue_harq_entity.harqs[h_id]; + srsran_sanity_check(h.ue_idx == ue_idx and h.h_id == h_id, "Invalid state of HARQ"); // Set allocated HARQ common params. - h.ue_idx = ue_idx; - h.rnti = rnti; - h.h_id = h_id; h.status = harq_state_t::waiting_ack; h.slot_tx = sl_tx; h.slot_ack = sl_ack; @@ -177,15 +157,8 @@ void cell_harq_repository::dealloc_harq(harq_type& h) // No-op return; } - ue_harq_entity_impl& ue_harq_entity = ues[h.ue_idx]; - - // Mark HARQ-Id as available. - ue_harq_entity.harqs[h.h_id] = INVALID_HARQ_REF_INDEX; - ue_harq_entity.free_harq_ids.push_back(h.h_id); - - // Push HARQ resource back to cell free list. - free_harqs.push_back(get_harq_ref_idx(h)); + // Update HARQ process state. if (h.status == harq_state_t::waiting_ack) { // Remove the HARQ from the timeout list. harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].pop(&h); @@ -193,9 +166,11 @@ void cell_harq_repository::dealloc_harq(harq_type& h) // Remove the HARQ from the pending Retx list. harq_pending_retx_list.pop(&h); } - - // Update HARQ process state. h.status = harq_state_t::empty; + + // Mark HARQ as available again. + ue_harq_entity_impl& ue_harq_entity = ues[h.ue_idx]; + ue_harq_entity.free_harq_ids.push_back(h.h_id); } template @@ -272,26 +247,28 @@ bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, } template -void cell_harq_repository::reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs) +void cell_harq_repository::reserve_ue_harqs(du_ue_index_t ue_idx, rnti_t rnti, unsigned nof_harqs) { ues[ue_idx].harqs.resize(nof_harqs); ues[ue_idx].free_harq_ids.resize(nof_harqs); - for (unsigned count = 0; count != nof_harqs; count++) { - harq_id_t h_id = to_harq_id(nof_harqs - count - 1); - ues[ue_idx].free_harq_ids[count] = h_id; - ues[ue_idx].harqs[count] = INVALID_HARQ_REF_INDEX; + for (unsigned count = 0; count != nof_harqs; ++count) { + harq_id_t h_id = to_harq_id(count); + ues[ue_idx].free_harq_ids[nof_harqs - count - 1] = h_id; // add in reverse order. + ues[ue_idx].harqs[h_id].ue_idx = ue_idx; + ues[ue_idx].harqs[h_id].rnti = rnti; + ues[ue_idx].harqs[h_id].h_id = h_id; + ues[ue_idx].harqs[h_id].ndi = false; } } template -void cell_harq_repository::destroy_ue_harqs(du_ue_index_t ue_idx) +void cell_harq_repository::destroy_ue(du_ue_index_t ue_idx) { - // Return back to the pool all HARQ processes allocated by the UE. - for (unsigned h_idx : ues[ue_idx].harqs) { - if (h_idx != INVALID_HARQ_REF_INDEX) { - dealloc_harq(harqs[h_idx]); - } + // Remove HARQ from list of pending retxs or timeout wheel. + for (harq_type& h : ues[ue_idx].harqs) { + dealloc_harq(h); } + ues[ue_idx].harqs.clear(); ues[ue_idx].free_harq_ids.clear(); } @@ -313,17 +290,27 @@ void cell_harq_repository::cancel_retxs(harq_type& h) } template -unsigned cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const -{ - for (unsigned h_ref_idx : ues[ue_idx].harqs) { - if (h_ref_idx != INVALID_HARQ_REF_INDEX) { - const harq_type& h = harqs[h_ref_idx]; - if (h.status == state) { - return h_ref_idx; - } +const typename cell_harq_repository::harq_type* +cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const +{ + for (const harq_type& h : ues[ue_idx].harqs) { + if (h.status == state) { + return &h; } } - return INVALID_HARQ_REF_INDEX; + return nullptr; +} + +template +typename cell_harq_repository::harq_type* +cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) +{ + for (harq_type& h : ues[ue_idx].harqs) { + if (h.status == state) { + return &h; + } + } + return nullptr; } template struct harq_utils::cell_harq_repository; @@ -332,7 +319,7 @@ template struct harq_utils::cell_harq_repository; template void harq_utils::base_harq_process_handle::cancel_retxs() { - harq_repo->cancel_retxs(fetch_impl()); + harq_repo->cancel_retxs(*impl); } template class harq_utils::base_harq_process_handle; @@ -360,7 +347,7 @@ void cell_harq_manager::slot_indication(slot_point sl_tx) bool cell_harq_manager::contains(du_ue_index_t ue_idx) const { - return ue_idx < dl.ues.size() and dl.ues[ue_idx].free_harq_ids.size() != 0; + return ue_idx < dl.ues.size() and not dl.ues[ue_idx].harqs.empty(); } dl_harq_pending_retx_list cell_harq_manager::pending_dl_retxs() @@ -380,15 +367,15 @@ cell_harq_manager::add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_ha srsran_assert(nof_ul_harq_procs <= max_harqs_per_ue and nof_ul_harq_procs > 0, "Invalid number of DL HARQs"); srsran_assert(ue_idx < dl.ues.size(), "Invalid ue_index"); srsran_assert(not contains(ue_idx), "Creating UE with duplicate ue_index"); - dl.reserve_ue_harqs(ue_idx, nof_dl_harq_procs); - ul.reserve_ue_harqs(ue_idx, nof_ul_harq_procs); + dl.reserve_ue_harqs(ue_idx, crnti, nof_dl_harq_procs); + ul.reserve_ue_harqs(ue_idx, crnti, nof_ul_harq_procs); return {this, ue_idx, crnti}; } void cell_harq_manager::destroy_ue(du_ue_index_t ue_idx) { - dl.destroy_ue_harqs(ue_idx); - ul.destroy_ue_harqs(ue_idx); + dl.destroy_ue(ue_idx); + ul.destroy_ue(ue_idx); } harq_utils::dl_harq_process_impl* cell_harq_manager::new_dl_tx(du_ue_index_t ue_idx, @@ -398,7 +385,7 @@ harq_utils::dl_harq_process_impl* cell_harq_manager::new_dl_tx(du_ue_index_t ue_ unsigned max_harq_nof_retxs, uint8_t harq_bit_idx) { - dl_harq_process_impl* h = dl.alloc_harq(ue_idx, rnti, pdsch_slot, pdsch_slot + k1, max_harq_nof_retxs); + dl_harq_process_impl* h = dl.alloc_harq(ue_idx, pdsch_slot, pdsch_slot + k1, max_harq_nof_retxs); if (h == nullptr) { return nullptr; } @@ -416,7 +403,7 @@ harq_utils::dl_harq_process_impl* cell_harq_manager::new_dl_tx(du_ue_index_t ue_ harq_utils::ul_harq_process_impl* cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch_slot, unsigned max_harq_nof_retxs) { - ul_harq_process_impl* h = ul.alloc_harq(ue_idx, rnti, pusch_slot, pusch_slot, max_harq_nof_retxs); + ul_harq_process_impl* h = ul.alloc_harq(ue_idx, pusch_slot, pusch_slot, max_harq_nof_retxs); if (h == nullptr) { return nullptr; } @@ -429,77 +416,75 @@ cell_harq_manager::new_ul_tx(du_ue_index_t ue_idx, rnti_t rnti, slot_point pusch bool dl_harq_process_handle::new_retx(slot_point pdsch_slot, unsigned k1, uint8_t harq_bit_idx) { - dl_harq_process_impl& h = fetch_impl(); - if (not harq_repo->handle_new_retx(h, pdsch_slot, pdsch_slot + k1)) { + if (not harq_repo->handle_new_retx(*impl, pdsch_slot, pdsch_slot + k1)) { return false; } // Reset DL-only HARQ parameters. - h.harq_bit_idx = harq_bit_idx; - h.pucch_ack_to_receive = 0; - h.chosen_ack = mac_harq_ack_report_status::dtx; - h.last_pucch_snr = std::nullopt; + impl->harq_bit_idx = harq_bit_idx; + impl->pucch_ack_to_receive = 0; + impl->chosen_ack = mac_harq_ack_report_status::dtx; + impl->last_pucch_snr = std::nullopt; return true; } dl_harq_process_handle::status_update dl_harq_process_handle::dl_ack_info(mac_harq_ack_report_status ack, std::optional pucch_snr) { - dl_harq_process_impl& h = fetch_impl(); - if (h.status != harq_state_t::waiting_ack) { + if (impl->status != harq_state_t::waiting_ack) { // If the HARQ process is not expecting an HARQ-ACK, it means that it has already been ACKed/NACKed. - harq_repo->logger.warning("rnti={} h_id={}: ACK arrived for inactive DL HARQ", h.rnti, h.h_id); + harq_repo->logger.warning("rnti={} h_id={}: ACK arrived for inactive DL HARQ", impl->rnti, impl->h_id); return status_update::error; } if (ack != mac_harq_ack_report_status::dtx and - (not h.last_pucch_snr.has_value() or (pucch_snr.has_value() and h.last_pucch_snr.value() < pucch_snr.value()))) { + (not impl->last_pucch_snr.has_value() or + (pucch_snr.has_value() and impl->last_pucch_snr.value() < pucch_snr.value()))) { // Case: If there was no previous HARQ-ACK decoded or the previous HARQ-ACK had lower SNR, this HARQ-ACK is chosen. - h.chosen_ack = ack; - h.last_pucch_snr = pucch_snr; + impl->chosen_ack = ack; + impl->last_pucch_snr = pucch_snr; } - if (h.pucch_ack_to_receive <= 1) { + if (impl->pucch_ack_to_receive <= 1) { // Case: This is the last HARQ-ACK that is expected for this HARQ process. // Update HARQ state - bool final_ack = h.chosen_ack == mac_harq_ack_report_status::ack; - harq_repo->handle_ack(h, final_ack); + bool final_ack = impl->chosen_ack == mac_harq_ack_report_status::ack; + harq_repo->handle_ack(*impl, final_ack); return final_ack ? status_update::acked : status_update::nacked; } // Case: This is not the last PUCCH HARQ-ACK that is expected for this HARQ process. - h.pucch_ack_to_receive--; - h.ack_on_timeout = h.chosen_ack == mac_harq_ack_report_status::ack; + impl->pucch_ack_to_receive--; + impl->ack_on_timeout = impl->chosen_ack == mac_harq_ack_report_status::ack; // We reduce the HARQ process timeout to receive the next HARQ-ACK. This is done because the two HARQ-ACKs should // arrive almost simultaneously, and in case the second goes missing, we don't want to block the HARQ for too long. auto& wheel = harq_repo->harq_timeout_wheel; - wheel[h.slot_ack_timeout.to_uint() % wheel.size()].pop(&h); - h.slot_ack_timeout = harq_repo->last_sl_ind + SHORT_ACK_TIMEOUT_DTX; - wheel[h.slot_ack_timeout.to_uint() % wheel.size()].push_front(&h); + wheel[impl->slot_ack_timeout.to_uint() % wheel.size()].pop(impl); + impl->slot_ack_timeout = harq_repo->last_sl_ind + SHORT_ACK_TIMEOUT_DTX; + wheel[impl->slot_ack_timeout.to_uint() % wheel.size()].push_front(impl); return status_update::no_update; } void dl_harq_process_handle::increment_pucch_counter() { - ++fetch_impl().pucch_ack_to_receive; + ++impl->pucch_ack_to_receive; } void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) { srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); - dl_harq_process_impl& impl = fetch_impl(); - srsran_sanity_check(pdsch.rnti == impl.rnti, "RNTI mismatch"); - srsran_sanity_check(pdsch.harq_id == impl.h_id, "HARQ-id mismatch"); - srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, + srsran_sanity_check(pdsch.rnti == impl->rnti, "RNTI mismatch"); + srsran_sanity_check(pdsch.harq_id == impl->h_id, "HARQ-id mismatch"); + srsran_assert(impl->status == harq_utils::harq_state_t::waiting_ack, "Setting allocation parameters for DL HARQ process id={} in invalid state", id()); const pdsch_codeword& cw = pdsch.codewords[0]; - dl_harq_process_impl::alloc_params& prev_params = impl.prev_tx_params; + dl_harq_process_impl::alloc_params& prev_params = impl->prev_tx_params; - if (impl.nof_retxs == 0) { + if (impl->nof_retxs == 0) { prev_params.tbs_bytes = cw.tb_size_bytes; prev_params.dci_cfg_type = ctx.dci_cfg_type; prev_params.nof_layers = pdsch.nof_layers; @@ -529,35 +514,33 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, bool ul_harq_process_handle::new_retx(slot_point pusch_slot) { - return harq_repo->handle_new_retx(fetch_impl(), pusch_slot, pusch_slot); + return harq_repo->handle_new_retx(*impl, pusch_slot, pusch_slot); } int ul_harq_process_handle::ul_crc_info(bool ack) { - ul_harq_process_impl& h = fetch_impl(); - if (h.status != harq_state_t::waiting_ack) { + if (impl->status != harq_state_t::waiting_ack) { // HARQ is not expecting CRC info. - harq_repo->logger.warning("rnti={} h_id={}: CRC arrived for UL HARQ not expecting it", h.rnti, h.h_id); + harq_repo->logger.warning("rnti={} h_id={}: CRC arrived for UL HARQ not expecting it", impl->rnti, impl->h_id); return -1; } - harq_repo->handle_ack(h, ack); + harq_repo->handle_ack(*impl, ack); - return ack ? (int)h.prev_tx_params.tbs_bytes : 0; + return ack ? (int)impl->prev_tx_params.tbs_bytes : 0; } void ul_harq_process_handle::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) { - ul_harq_process_impl& impl = fetch_impl(); - srsran_sanity_check(pusch.rnti == impl.rnti, "RNTI mismatch"); - srsran_sanity_check(pusch.harq_id == impl.h_id, "HARQ-id mismatch"); - srsran_assert(impl.status == harq_utils::harq_state_t::waiting_ack, + srsran_sanity_check(pusch.rnti == impl->rnti, "RNTI mismatch"); + srsran_sanity_check(pusch.harq_id == impl->h_id, "HARQ-id mismatch"); + srsran_assert(impl->status == harq_utils::harq_state_t::waiting_ack, "Setting allocation parameters for DL HARQ process id={} in invalid state", id()); - ul_harq_process_impl::alloc_params& prev_tx_params = impl.prev_tx_params; + ul_harq_process_impl::alloc_params& prev_tx_params = impl->prev_tx_params; - if (impl.nof_retxs == 0) { + if (impl->nof_retxs == 0) { prev_tx_params.dci_cfg_type = ctx.dci_cfg_type; prev_tx_params.olla_mcs = ctx.olla_mcs; prev_tx_params.tbs_bytes = pusch.tb_size_bytes; @@ -621,7 +604,7 @@ unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max if (h == nullptr) { return std::nullopt; } - return dl_harq_process_handle(cell_harq_mgr->dl, cell_harq_mgr->dl.get_harq_ref_idx(*h)); + return dl_harq_process_handle(cell_harq_mgr->dl, *h); } std::optional unique_ue_harq_entity::alloc_ul_harq(slot_point sl_tx, @@ -631,55 +614,52 @@ std::optional unique_ue_harq_entity::alloc_ul_harq(slot_ if (h == nullptr) { return std::nullopt; } - return ul_harq_process_handle(cell_harq_mgr->ul, cell_harq_mgr->ul.get_harq_ref_idx(*h)); + return ul_harq_process_handle(cell_harq_mgr->ul, *h); } std::optional unique_ue_harq_entity::find_pending_dl_retx() { - unsigned h_ref_idx = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); - if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + dl_harq_process_impl* h = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); + if (h == nullptr) { return std::nullopt; } - return dl_harq_process_handle(cell_harq_mgr->dl, h_ref_idx); + return dl_harq_process_handle(cell_harq_mgr->dl, *h); } std::optional unique_ue_harq_entity::find_pending_ul_retx() { - unsigned h_ref_idx = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); - if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + ul_harq_process_impl* h = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); + if (h == nullptr) { return std::nullopt; } - return ul_harq_process_handle(cell_harq_mgr->ul, h_ref_idx); + return ul_harq_process_handle(cell_harq_mgr->ul, *h); } std::optional unique_ue_harq_entity::find_dl_harq_waiting_ack() { - unsigned h_ref_idx = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); - if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + dl_harq_process_impl* h = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); + if (h == nullptr) { return std::nullopt; } - return dl_harq_process_handle(cell_harq_mgr->dl, h_ref_idx); + return dl_harq_process_handle(cell_harq_mgr->dl, *h); } std::optional unique_ue_harq_entity::find_ul_harq_waiting_ack() { - unsigned h_ref_idx = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); - if (h_ref_idx == INVALID_HARQ_REF_INDEX) { + ul_harq_process_impl* h = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); + if (h == nullptr) { return std::nullopt; } - return ul_harq_process_handle(cell_harq_mgr->ul, h_ref_idx); + return ul_harq_process_handle(cell_harq_mgr->ul, *h); } std::optional unique_ue_harq_entity::find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx) { - const std::vector& dl_harqs = cell_harq_mgr->dl.ues[ue_index].harqs; - for (unsigned h_ref_idx : dl_harqs) { - if (h_ref_idx != INVALID_HARQ_REF_INDEX) { - const dl_harq_process_impl& h = cell_harq_mgr->dl.harqs[h_ref_idx]; - if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_ack == uci_slot and - h.harq_bit_idx == harq_bit_idx) { - return dl_harq_process_handle(cell_harq_mgr->dl, h_ref_idx); - } + std::vector& dl_harqs = cell_harq_mgr->dl.ues[ue_index].harqs; + for (dl_harq_process_impl& h : dl_harqs) { + if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_ack == uci_slot and + h.harq_bit_idx == harq_bit_idx) { + return dl_harq_process_handle(cell_harq_mgr->dl, h); } } return std::nullopt; @@ -687,13 +667,10 @@ std::optional unique_ue_harq_entity::find_dl_harq(slot_p std::optional unique_ue_harq_entity::find_ul_harq(slot_point pusch_slot) { - const std::vector& ul_harqs = cell_harq_mgr->ul.ues[ue_index].harqs; - for (unsigned h_ref_idx : ul_harqs) { - if (h_ref_idx != INVALID_HARQ_REF_INDEX) { - const ul_harq_process_impl& h = cell_harq_mgr->ul.harqs[h_ref_idx]; - if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_tx == pusch_slot) { - return ul_harq_process_handle(cell_harq_mgr->ul, h_ref_idx); - } + std::vector& ul_harqs = cell_harq_mgr->ul.ues[ue_index].harqs; + for (ul_harq_process_impl& h : ul_harqs) { + if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_tx == pusch_slot) { + return ul_harq_process_handle(cell_harq_mgr->ul, h); } } return std::nullopt; diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 9bf4a55cd5..49e588b0f4 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -41,8 +41,6 @@ class harq_timeout_notifier namespace harq_utils { -const static unsigned INVALID_HARQ_REF_INDEX = std::numeric_limits::max(); - /// Possible states of a HARQ process. enum class harq_state_t { empty, pending_retx, waiting_ack }; @@ -119,16 +117,14 @@ struct ul_harq_process_impl : public base_harq_process { alloc_params prev_tx_params; }; -struct ue_harq_entity_impl { - std::vector harqs; - std::vector free_harq_ids; -}; - template struct cell_harq_repository { using harq_type = std::conditional_t; - const static unsigned INVALID_HARQ = std::numeric_limits::max(); + struct ue_harq_entity_impl { + std::vector harqs; + std::vector free_harq_ids; + }; cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_in_slots, @@ -136,34 +132,31 @@ struct cell_harq_repository { harq_timeout_notifier& timeout_notifier_, srslog::basic_logger& logger_); - /// Maximum value of time interval, in slots, before the HARQ process assumes that the ACK/CRC went missing. - const unsigned max_ack_wait_in_slots; + /// Time interval, in slots, before the HARQ process assumes that the ACK/CRC went missing. + const unsigned max_ack_wait_in_slots; + /// Maximum number of HARQs allowed per UE. const unsigned max_harqs_per_ue; harq_timeout_notifier& timeout_notifier; srslog::basic_logger& logger; slot_point last_sl_ind; - std::vector harqs; - std::vector free_harqs; std::vector ues; intrusive_double_linked_list harq_pending_retx_list; std::vector> harq_timeout_wheel; - unsigned get_harq_ref_idx(const harq_type& h) const; - - void slot_indication(slot_point sl_tx); - void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); - harq_type* - alloc_harq(du_ue_index_t ue_idx, rnti_t rnti, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); - void dealloc_harq(harq_type& h); - void handle_ack(harq_type& h, bool ack); - void set_pending_retx(harq_type& h); + void slot_indication(slot_point sl_tx); + void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); + harq_type* alloc_harq(du_ue_index_t ue_idx, slot_point sl_tx, slot_point sl_ack, unsigned max_nof_harq_retxs); + void dealloc_harq(harq_type& h); + void handle_ack(harq_type& h, bool ack); + void set_pending_retx(harq_type& h); [[nodiscard]] bool handle_new_retx(harq_type& h, slot_point sl_tx, slot_point sl_ack); - void reserve_ue_harqs(du_ue_index_t ue_idx, unsigned nof_harqs); - void destroy_ue_harqs(du_ue_index_t ue_idx); + void reserve_ue_harqs(du_ue_index_t ue_idx, rnti_t rnti, unsigned nof_harqs); + void destroy_ue(du_ue_index_t ue_idx); void cancel_retxs(harq_type& h); - unsigned find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; + harq_type* find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state); + const harq_type* find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; }; template @@ -175,24 +168,16 @@ class base_harq_process_handle public: base_harq_process_handle() = default; - base_harq_process_handle(harq_pool& pool_, unsigned harq_ref_idx_) : harq_repo(&pool_), harq_ref_idx(harq_ref_idx_) - { - srsran_sanity_check(harq_ref_idx < harq_repo->harqs.size(), "Invalid HARQ created"); - srsran_sanity_check(harq_repo->harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty, - "Empty HARQ process created"); - } + base_harq_process_handle(harq_pool& pool_, harq_impl_type& h_) : harq_repo(&pool_), impl(&h_) {} - rnti_t rnti() const { return fetch_impl().rnti; } - harq_id_t id() const { return fetch_impl().h_id; } - bool is_waiting_ack() const { return fetch_impl().status == harq_utils::harq_state_t::waiting_ack; } - bool has_pending_retx() const { return fetch_impl().status == harq_utils::harq_state_t::pending_retx; } - bool empty() const - { - return harq_ref_idx == harq_pool::INVALID_HARQ or fetch_impl().status == harq_utils::harq_state_t::empty; - } - unsigned max_nof_retxs() const { return fetch_impl().max_nof_harq_retxs; } - unsigned nof_retxs() const { return fetch_impl().nof_retxs; } - bool ndi() const { return fetch_impl().ndi; } + rnti_t rnti() const { return impl->rnti; } + harq_id_t id() const { return impl->h_id; } + bool is_waiting_ack() const { return impl->status == harq_utils::harq_state_t::waiting_ack; } + bool has_pending_retx() const { return impl->status == harq_utils::harq_state_t::pending_retx; } + bool empty() const { return impl->status == harq_utils::harq_state_t::empty; } + unsigned max_nof_retxs() const { return impl->max_nof_harq_retxs; } + unsigned nof_retxs() const { return impl->nof_retxs; } + bool ndi() const { return impl->ndi; } /// \brief Cancels any retransmissions for this HARQ process. /// If the HARQ process has a pending retransmission, it is reset. If the ACK/CRC info has not been received yet, the @@ -201,16 +186,13 @@ class base_harq_process_handle bool operator==(const base_harq_process_handle& other) const { - return harq_repo == other.harq_repo and harq_ref_idx == other.harq_ref_idx; + return harq_repo == other.harq_repo and impl == other.impl; } bool operator!=(const base_harq_process_handle& other) const { return !(*this == other); } protected: - harq_impl_type& fetch_impl() { return harq_repo->harqs[harq_ref_idx]; } - const harq_impl_type& fetch_impl() const { return harq_repo->harqs[harq_ref_idx]; } - - harq_pool* harq_repo = nullptr; - unsigned harq_ref_idx = harq_pool::INVALID_HARQ; + harq_pool* harq_repo = nullptr; + harq_impl_type* impl = nullptr; }; } // namespace harq_utils @@ -281,10 +263,10 @@ class dl_harq_process_handle : public harq_utils::base_harq_process_handle /// they can be later fetched and optionally reused. void save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch); - slot_point pdsch_slot() const { return fetch_impl().slot_tx; } - slot_point uci_slot() const { return fetch_impl().slot_ack; } + slot_point pdsch_slot() const { return impl->slot_tx; } + slot_point uci_slot() const { return impl->slot_ack; } - const grant_params& get_grant_params() const { return fetch_impl().prev_tx_params; } + const grant_params& get_grant_params() const { return impl->prev_tx_params; } }; /// Interface used to fetch and update the status of a UL HARQ process. @@ -320,9 +302,9 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handleslot_tx; } - const grant_params& get_grant_params() const { return fetch_impl().prev_tx_params; } + const grant_params& get_grant_params() const { return impl->prev_tx_params; } }; namespace harq_utils { @@ -352,17 +334,12 @@ class harq_pending_retx_list_impl return value(); } reference operator*() { return value(); } - reference value() - { - return it != pool->harq_pending_retx_list.end() ? handle_type{*pool, get_harq_ref_idx(*it)} : handle_type{}; - } + reference value() { return it != pool->harq_pending_retx_list.end() ? handle_type{*pool, *it} : handle_type{}; } bool operator==(const iterator& other) const { return pool == other.pool and it == other.it; } bool operator!=(const iterator& other) const { return !(*this == other); } private: - unsigned get_harq_ref_idx(const harq_impl_type& h) { return &h - pool->harqs.data(); } - harq_pool* pool; typename intrusive_double_linked_list::iterator it; }; @@ -447,6 +424,9 @@ class cell_harq_manager /// HARQ entity that manages a set of HARQ processes of a single UE. class unique_ue_harq_entity { + using dl_harq_ent_impl = harq_utils::cell_harq_repository::ue_harq_entity_impl; + using ul_harq_ent_impl = harq_utils::cell_harq_repository::ue_harq_entity_impl; + public: unique_ue_harq_entity() = default; unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_); @@ -469,15 +449,15 @@ class unique_ue_harq_entity std::optional dl_harq(harq_id_t h_id) { - if (cell_harq_mgr->dl.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { - return dl_harq_process_handle{cell_harq_mgr->dl, cell_harq_mgr->dl.ues[ue_index].harqs[h_id]}; + if (get_dl_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + return dl_harq_process_handle{cell_harq_mgr->dl, get_dl_ue().harqs[h_id]}; } return std::nullopt; } std::optional ul_harq(harq_id_t h_id) { - if (cell_harq_mgr->ul.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) { - return ul_harq_process_handle{cell_harq_mgr->ul, cell_harq_mgr->ul.ues[ue_index].harqs[h_id]}; + if (get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + return ul_harq_process_handle{cell_harq_mgr->ul, get_ul_ue().harqs[h_id]}; } return std::nullopt; } @@ -504,10 +484,10 @@ class unique_ue_harq_entity std::optional find_ul_harq(slot_point pusch_slot); private: - harq_utils::ue_harq_entity_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } - const harq_utils::ue_harq_entity_impl& get_dl_ue() const { return cell_harq_mgr->dl.ues[ue_index]; } - harq_utils::ue_harq_entity_impl& get_ul_ue() { return cell_harq_mgr->ul.ues[ue_index]; } - const harq_utils::ue_harq_entity_impl& get_ul_ue() const { return cell_harq_mgr->ul.ues[ue_index]; } + dl_harq_ent_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } + const dl_harq_ent_impl& get_dl_ue() const { return cell_harq_mgr->dl.ues[ue_index]; } + ul_harq_ent_impl& get_ul_ue() { return cell_harq_mgr->ul.ues[ue_index]; } + const ul_harq_ent_impl& get_ul_ue() const { return cell_harq_mgr->ul.ues[ue_index]; } cell_harq_manager* cell_harq_mgr = nullptr; du_ue_index_t ue_index = INVALID_DU_UE_INDEX; diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index a4ff2ff543..301b3321f2 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -972,3 +972,40 @@ TEST_F(multi_ue_harq_manager_test, pending_harq_retxs_are_ordered_from_oldest_to } ASSERT_EQ(count, 2); } + +TEST_F(multi_ue_harq_manager_test, when_new_tx_occur_for_different_ues_then_ndi_is_still_valid) +{ + const unsigned k1 = 4, k2 = 6, max_retxs = 4; + unique_ue_harq_entity harq_ent1 = cell_harqs.add_ue(to_du_ue_index(1), to_rnti(0x4601), nof_harqs, nof_harqs); + unique_ue_harq_entity harq_ent2 = cell_harqs.add_ue(to_du_ue_index(2), to_rnti(0x4602), nof_harqs, nof_harqs); + + auto h_dl = harq_ent1.alloc_dl_harq(current_slot, k1, max_retxs, 0); + auto h_ul = harq_ent1.alloc_ul_harq(current_slot + k2, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + + bool ndi_dl1 = h_dl->ndi(); + bool ndi_ul1 = h_ul->ndi(); + + ASSERT_EQ(h_dl->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), + dl_harq_process_handle::status_update::acked); + ASSERT_EQ(h_ul->ul_crc_info(true), 0); + + h_dl = harq_ent2.alloc_dl_harq(current_slot, k1, max_retxs, 0); + h_ul = harq_ent2.alloc_ul_harq(current_slot + k2, max_retxs); + ASSERT_TRUE(h_dl.has_value()); + ASSERT_TRUE(h_ul.has_value()); + + ASSERT_EQ(h_dl->ndi(), ndi_dl1); + ASSERT_EQ(h_ul->ndi(), ndi_ul1); + + ASSERT_EQ(h_dl->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), + dl_harq_process_handle::status_update::acked); + ASSERT_EQ(h_ul->ul_crc_info(true), 0); + + h_dl = harq_ent1.alloc_dl_harq(current_slot, k1, max_retxs, 0); + h_ul = harq_ent1.alloc_ul_harq(current_slot + k2, max_retxs); + + ASSERT_NE(h_dl->ndi(), ndi_dl1); + ASSERT_NE(h_ul->ndi(), ndi_ul1); +} From d125d73e46f2b6edeacc10107ef81f32811e2770 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 29 Aug 2024 13:04:10 +0200 Subject: [PATCH 400/407] sched: add missing methods to unique_ue_harq_entity --- lib/scheduler/cell/cell_harq_manager.cpp | 44 ++++++++++++- lib/scheduler/cell/cell_harq_manager.h | 64 ++++++++++++++----- .../scheduler/cell/cell_harq_manager_test.cpp | 4 +- 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 03304a8e28..21969b966d 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -21,7 +21,7 @@ class noop_harq_timeout_notifier : public harq_timeout_notifier { public: void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override - { /* do nothing */ + { // do nothing } }; @@ -322,6 +322,12 @@ void harq_utils::base_harq_process_handle::cancel_retxs() harq_repo->cancel_retxs(*impl); } +template +void harq_utils::base_harq_process_handle::reset() +{ + harq_repo->dealloc_harq(*impl); +} + template class harq_utils::base_harq_process_handle; template class harq_utils::base_harq_process_handle; @@ -472,7 +478,7 @@ void dl_harq_process_handle::increment_pucch_counter() ++impl->pucch_ack_to_receive; } -void dl_harq_process_handle::save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch) +void dl_harq_process_handle::save_grant_params(const dl_harq_alloc_context& ctx, const pdsch_information& pdsch) { srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); srsran_sanity_check(pdsch.rnti == impl->rnti, "RNTI mismatch"); @@ -530,7 +536,7 @@ int ul_harq_process_handle::ul_crc_info(bool ack) return ack ? (int)impl->prev_tx_params.tbs_bytes : 0; } -void ul_harq_process_handle::save_grant_params(const ul_harq_sched_context& ctx, const pusch_information& pusch) +void ul_harq_process_handle::save_grant_params(const ul_harq_alloc_context& ctx, const pusch_information& pusch) { srsran_sanity_check(pusch.rnti == impl->rnti, "RNTI mismatch"); srsran_sanity_check(pusch.harq_id == impl->h_id, "HARQ-id mismatch"); @@ -626,6 +632,15 @@ std::optional unique_ue_harq_entity::find_pending_dl_ret return dl_harq_process_handle(cell_harq_mgr->dl, *h); } +std::optional unique_ue_harq_entity::find_pending_dl_retx() const +{ + dl_harq_process_impl* h = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); + if (h == nullptr) { + return std::nullopt; + } + return dl_harq_process_handle(cell_harq_mgr->dl, *h); +} + std::optional unique_ue_harq_entity::find_pending_ul_retx() { ul_harq_process_impl* h = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); @@ -635,6 +650,15 @@ std::optional unique_ue_harq_entity::find_pending_ul_ret return ul_harq_process_handle(cell_harq_mgr->ul, *h); } +std::optional unique_ue_harq_entity::find_pending_ul_retx() const +{ + ul_harq_process_impl* h = cell_harq_mgr->ul.find_ue_harq_in_state(ue_index, harq_state_t::pending_retx); + if (h == nullptr) { + return std::nullopt; + } + return ul_harq_process_handle(cell_harq_mgr->ul, *h); +} + std::optional unique_ue_harq_entity::find_dl_harq_waiting_ack() { dl_harq_process_impl* h = cell_harq_mgr->dl.find_ue_harq_in_state(ue_index, harq_state_t::waiting_ack); @@ -675,3 +699,17 @@ std::optional unique_ue_harq_entity::find_ul_harq(slot_p } return std::nullopt; } + +void unique_ue_harq_entity::uci_sched_failed(slot_point uci_slot) +{ + std::vector& dl_harqs = cell_harq_mgr->dl.ues[ue_index].harqs; + for (dl_harq_process_impl& h : dl_harqs) { + if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_ack == uci_slot) { + unsigned nof_nacks = std::max(h.pucch_ack_to_receive, 1U); + auto h_handle = dl_harq_process_handle(cell_harq_mgr->dl, h); + for (unsigned i = 0; i != nof_nacks; ++i) { + h_handle.dl_ack_info(mac_harq_ack_report_status::dtx, std::nullopt); + } + } + } +} diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 49e588b0f4..eb0f1620de 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -170,20 +170,24 @@ class base_harq_process_handle base_harq_process_handle() = default; base_harq_process_handle(harq_pool& pool_, harq_impl_type& h_) : harq_repo(&pool_), impl(&h_) {} - rnti_t rnti() const { return impl->rnti; } - harq_id_t id() const { return impl->h_id; } - bool is_waiting_ack() const { return impl->status == harq_utils::harq_state_t::waiting_ack; } - bool has_pending_retx() const { return impl->status == harq_utils::harq_state_t::pending_retx; } - bool empty() const { return impl->status == harq_utils::harq_state_t::empty; } - unsigned max_nof_retxs() const { return impl->max_nof_harq_retxs; } - unsigned nof_retxs() const { return impl->nof_retxs; } - bool ndi() const { return impl->ndi; } + du_ue_index_t ue_index() const { return impl->ue_idx; } + rnti_t rnti() const { return impl->rnti; } + harq_id_t id() const { return impl->h_id; } + bool is_waiting_ack() const { return impl->status == harq_utils::harq_state_t::waiting_ack; } + bool has_pending_retx() const { return impl->status == harq_utils::harq_state_t::pending_retx; } + bool empty() const { return impl->status == harq_utils::harq_state_t::empty; } + unsigned max_nof_retxs() const { return impl->max_nof_harq_retxs; } + unsigned nof_retxs() const { return impl->nof_retxs; } + bool ndi() const { return impl->ndi; } /// \brief Cancels any retransmissions for this HARQ process. /// If the HARQ process has a pending retransmission, it is reset. If the ACK/CRC info has not been received yet, the /// HARQ process waits for it to arrive before being reset. void cancel_retxs(); + /// Empty the HARQ process. + void reset(); + bool operator==(const base_harq_process_handle& other) const { return harq_repo == other.harq_repo and impl == other.impl; @@ -198,7 +202,7 @@ class base_harq_process_handle } // namespace harq_utils /// \brief Context of the scheduler during the current PDSCH allocation. -struct dl_harq_sched_context { +struct dl_harq_alloc_context { /// DCI format used to signal the PDSCH allocation. dci_dl_rnti_config_type dci_cfg_type; /// MCS suggested by the OLLA. @@ -212,7 +216,7 @@ struct dl_harq_sched_context { }; /// \brief Context of the scheduler during the current PUSCH allocation. -struct ul_harq_sched_context { +struct ul_harq_alloc_context { /// DCI format used to signal the PUSCH allocation. dci_ul_rnti_config_type dci_cfg_type; /// MCS suggested by the OLLA. @@ -261,7 +265,7 @@ class dl_harq_process_handle : public harq_utils::base_harq_process_handle /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that /// they can be later fetched and optionally reused. - void save_grant_params(const dl_harq_sched_context& ctx, const pdsch_information& pdsch); + void save_grant_params(const dl_harq_alloc_context& ctx, const pdsch_information& pdsch); slot_point pdsch_slot() const { return impl->slot_tx; } slot_point uci_slot() const { return impl->slot_ack; } @@ -300,7 +304,7 @@ class ul_harq_process_handle : public harq_utils::base_harq_process_handleslot_tx; } @@ -436,6 +440,8 @@ class unique_ue_harq_entity unique_ue_harq_entity& operator=(const unique_ue_harq_entity&) = delete; unique_ue_harq_entity& operator=(unique_ue_harq_entity&& other) noexcept; + bool empty() const { return cell_harq_mgr == nullptr; } + /// Gets the maximum number of HARQ processes a UE can use, which depends on its configuration. unsigned nof_dl_harqs() const { return get_dl_ue().harqs.size(); } unsigned nof_ul_harqs() const { return get_ul_ue().harqs.size(); } @@ -454,6 +460,13 @@ class unique_ue_harq_entity } return std::nullopt; } + std::optional dl_harq(harq_id_t h_id) const + { + if (get_dl_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + return dl_harq_process_handle{cell_harq_mgr->dl, cell_harq_mgr->dl.ues[ue_index].harqs[h_id]}; + } + return std::nullopt; + } std::optional ul_harq(harq_id_t h_id) { if (get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { @@ -461,13 +474,22 @@ class unique_ue_harq_entity } return std::nullopt; } + std::optional ul_harq(harq_id_t h_id) const + { + if (get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + return ul_harq_process_handle{cell_harq_mgr->ul, cell_harq_mgr->ul.ues[ue_index].harqs[h_id]}; + } + return std::nullopt; + } std::optional alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx); std::optional alloc_ul_harq(slot_point sl_tx, unsigned max_harq_nof_retxs); - std::optional find_pending_dl_retx(); - std::optional find_pending_ul_retx(); + std::optional find_pending_dl_retx(); + std::optional find_pending_dl_retx() const; + std::optional find_pending_ul_retx(); + std::optional find_pending_ul_retx() const; std::optional find_dl_harq_waiting_ack(); std::optional find_ul_harq_waiting_ack(); @@ -483,6 +505,18 @@ class unique_ue_harq_entity /// \return Active UL HARQ process with matching PUSCH slot, if found. std::optional find_ul_harq(slot_point pusch_slot); + /// \brief The UCI scheduling associated with a given slot was cancelled. The associated DL HARQs will be NACKed, and + /// won't expect further UCIs. + /// + /// This function can be called for instance when there is an error indication coming from lower layers. + void uci_sched_failed(slot_point uci_slot); + + unsigned ntn_get_tbs_pending_crcs() const + { + // TODO + return 0; + } + private: dl_harq_ent_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } const dl_harq_ent_impl& get_dl_ue() const { return cell_harq_mgr->dl.ues[ue_index]; } @@ -494,4 +528,4 @@ class unique_ue_harq_entity rnti_t crnti = rnti_t::INVALID_RNTI; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index 301b3321f2..d9424e346c 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -155,10 +155,10 @@ class single_harq_process_test : public base_single_harq_entity_test, public ::t single_harq_process_test() { pdsch_info = make_dummy_pdsch_info(); - dl_harq_sched_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; + dl_harq_alloc_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; h_dl.save_grant_params(harq_ctxt, pdsch_info); pusch_info = make_dummy_pusch_info(); - ul_harq_sched_context ul_harq_ctxt{dci_ul_rnti_config_type::c_rnti_f0_0}; + ul_harq_alloc_context ul_harq_ctxt{dci_ul_rnti_config_type::c_rnti_f0_0}; h_ul.save_grant_params(ul_harq_ctxt, pusch_info); } From 8f4e2707a98ef56bc9ac7c92cccd68e01a0d19b6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 30 Aug 2024 14:41:12 +0200 Subject: [PATCH 401/407] sched: implementation of NTN HARQ history --- lib/scheduler/cell/cell_harq_manager.cpp | 208 +++++++++++++++++++++-- lib/scheduler/cell/cell_harq_manager.h | 15 +- 2 files changed, 211 insertions(+), 12 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 21969b966d..74790883d4 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -25,18 +25,144 @@ class noop_harq_timeout_notifier : public harq_timeout_notifier } }; +template +class base_ntn_harq_history +{ + using harq_impl_type = std::conditional_t; + +public: + base_ntn_harq_history(cell_harq_repository& parent_, unsigned ntn_cs_koffset_) : + harq_pool(parent_), ntn_cs_koffset(ntn_cs_koffset_) + { + srsran_assert(ntn_cs_koffset > 0 and ntn_cs_koffset <= NTN_CELL_SPECIFIC_KOFFSET_MAX, "Invalid NTN koffset"); + unsigned ring_size = get_allocator_ring_size_gt_min(ntn_cs_koffset); + history.resize(ring_size); + } + + void slot_indication(slot_point sl_tx) + { + last_sl_ind = sl_tx; + // If there are no allocations, we do not let last_sl_ack get further away from last_sl_ind, to avoid ambiguity. + if (not last_sl_ack.valid() or last_sl_ack < last_sl_ind - 1) { + last_sl_ack = last_sl_ind - 1; + } + + // Clear old entries. + unsigned idx = get_index(sl_tx - 1); + history[idx].clear(); + } + + void save_harq_newtx_info(const harq_impl_type& h) + { + unsigned idx = get_index(h.slot_ack); + history[idx].emplace_back(h); + + if (h.slot_ack > last_sl_ack) { + last_sl_ack = h.slot_ack; + } + } + + void save_harq_retx_info(const harq_impl_type& h, slot_point last_slot_ack) + { + // Clear previous HARQ transmission so it does not count in pending bytes. + unsigned last_idx = get_index(last_slot_ack); + for (unsigned i = 0; i != history[last_idx].size(); ++i) { + if (history[last_idx][i].ue_idx == h.ue_idx and history[last_idx][i].h_id == h.h_id) { + history[last_idx][i].status = harq_state_t::empty; + } + } + + save_harq_newtx_info(h); + } + +protected: + unsigned get_index(slot_point sl) const { return mod((sl + ntn_cs_koffset).to_uint()); } + unsigned mod(unsigned idx) const { return idx % history.size(); } + + cell_harq_repository& harq_pool; + unsigned ntn_cs_koffset; + std::vector> history; + + slot_point last_sl_ind; + slot_point last_sl_ack; +}; + } // namespace +namespace srsran::harq_utils { + +/// Handles the DL HARQ information in the case NTN mode. +class ntn_dl_harq_alloc_history : public base_ntn_harq_history +{ +public: + using base_ntn_harq_history::base_ntn_harq_history; + + std::optional find_dl_harq(du_ue_index_t ue_idx, slot_point uci_slot, unsigned harq_bit_idx) + { + unsigned idx = get_index(uci_slot); + for (dl_harq_process_impl& h_impl : history[idx]) { + if (h_impl.ue_idx == ue_idx and h_impl.status == harq_state_t::waiting_ack and h_impl.slot_ack == uci_slot and + h_impl.harq_bit_idx == harq_bit_idx) { + return dl_harq_process_handle{harq_pool, h_impl}; + } + } + return std::nullopt; + } +}; + +/// Handles the UL HARQ information in the case NTN mode. +class ntn_ul_harq_alloc_history : public base_ntn_harq_history +{ +public: + using base_ntn_harq_history::base_ntn_harq_history; + + std::optional find_ul_harq(du_ue_index_t ue_idx, slot_point pusch_slot) + { + unsigned idx = get_index(pusch_slot); + for (ul_harq_process_impl& h_impl : history[idx]) { + if (h_impl.ue_idx == ue_idx and h_impl.status == harq_state_t::waiting_ack and h_impl.slot_ack == pusch_slot) { + return ul_harq_process_handle{harq_pool, h_impl}; + } + } + return std::nullopt; + } + + unsigned sum_pending_ul_tbs(du_ue_index_t ue_idx) const + { + if (last_sl_ack < last_sl_ind) { + return 0; + } + unsigned sum = 0; + for (unsigned idx = get_index(last_sl_ind), last_idx = get_index(last_sl_ack + 1); idx != last_idx; + idx = mod(idx + 1)) { + for (const ul_harq_process_impl& h : history[idx]) { + if (h.ue_idx == ue_idx and h.status != harq_state_t::empty) { + sum += h.prev_tx_params.tbs_bytes; + break; + } + } + } + return sum; + } +}; + +} // namespace srsran::harq_utils + +// In NTN case, we timeout the HARQ since we need to reuse the process before the PUSCH arrives. +static const unsigned NTN_ACK_WAIT_TIMEOUT = 1; + template cell_harq_repository::cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_timeout, unsigned max_harqs_per_ue_, + unsigned ntn_cs_koffset, harq_timeout_notifier& timeout_notifier_, srslog::basic_logger& logger_) : - max_ack_wait_in_slots(max_ack_wait_timeout), + max_ack_wait_in_slots(ntn_cs_koffset == 0 ? max_ack_wait_timeout : NTN_ACK_WAIT_TIMEOUT), max_harqs_per_ue(max_harqs_per_ue_), timeout_notifier(timeout_notifier_), - logger(logger_) + logger(logger_), + alloc_hist(ntn_cs_koffset > 0 ? std::make_unique(*this, ntn_cs_koffset) : nullptr) { // Reserve space in advance for UEs and their HARQs. ues.resize(max_ues); @@ -48,6 +174,11 @@ cell_harq_repository::cell_harq_repository(unsigned max_ues, harq_timeout_wheel.resize(get_allocator_ring_size_gt_min(max_ack_wait_timeout + get_max_slot_ul_alloc_delay(0))); } +template +cell_harq_repository::~cell_harq_repository() +{ +} + template void cell_harq_repository::slot_indication(slot_point sl_tx) { @@ -147,6 +278,11 @@ typename cell_harq_repository::harq_type* cell_harq_repository::allo h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); + if (is_ntn_mode()) { + // In NTN mode, save HARQ info separately. + alloc_hist->save_harq_newtx_info(h); + } + return &h; } @@ -195,6 +331,11 @@ void cell_harq_repository::handle_ack(harq_type& h, bool ack) } } + if (is_ntn_mode()) { + // In NTN mode, ACK info does not affect the timeout/retx containers. + return; + } + if (ack or h.nof_retxs >= h.max_nof_harq_retxs) { // If the HARQ process is ACKed or the maximum number of retransmissions has been reached, we can deallocate the // HARQ process. @@ -234,15 +375,22 @@ bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, // Remove HARQ from pending Retx list. harq_pending_retx_list.pop(&h); - h.status = harq_state_t::waiting_ack; - h.slot_tx = sl_tx; - h.slot_ack = sl_ack; - h.ack_on_timeout = false; + slot_point prev_sl_ack = h.slot_ack; + h.status = harq_state_t::waiting_ack; + h.slot_tx = sl_tx; + h.slot_ack = sl_ack; + h.ack_on_timeout = false; h.nof_retxs++; // Add HARQ to the timeout list. h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); + + if (is_ntn_mode()) { + // In NTN mode, save HARQ info separately. + alloc_hist->save_harq_retx_info(h, prev_sl_ack); + } + return true; } @@ -301,6 +449,12 @@ cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, harq_uti return nullptr; } +template +bool cell_harq_repository::is_ntn_mode() const +{ + return alloc_hist != nullptr; +} + template typename cell_harq_repository::harq_type* cell_harq_repository::find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) @@ -336,12 +490,14 @@ template class harq_utils::base_harq_process_handle; cell_harq_manager::cell_harq_manager(unsigned max_ues, unsigned max_harqs_per_ue_, std::unique_ptr notifier, - unsigned max_ack_wait_timeout) : + unsigned max_ack_wait_timeout, + unsigned ntn_cs_koffset) : max_harqs_per_ue(max_harqs_per_ue_), - timeout_notifier(notifier != nullptr ? std::move(notifier) : std::make_unique()), + timeout_notifier(notifier != nullptr and ntn_cs_koffset == 0 ? std::move(notifier) + : std::make_unique()), logger(srslog::fetch_basic_logger("SCHED")), - dl(max_ues, max_ack_wait_timeout, max_harqs_per_ue, *timeout_notifier, logger), - ul(max_ues, max_ack_wait_timeout, max_harqs_per_ue, *timeout_notifier, logger) + dl(max_ues, max_ack_wait_timeout, max_harqs_per_ue, ntn_cs_koffset, *timeout_notifier, logger), + ul(max_ues, max_ack_wait_timeout, max_harqs_per_ue, ntn_cs_koffset, *timeout_notifier, logger) { } @@ -463,6 +619,12 @@ dl_harq_process_handle::status_update dl_harq_process_handle::dl_ack_info(mac_ha // Case: This is not the last PUCCH HARQ-ACK that is expected for this HARQ process. impl->pucch_ack_to_receive--; impl->ack_on_timeout = impl->chosen_ack == mac_harq_ack_report_status::ack; + + if (harq_repo->is_ntn_mode()) { + // Timeouts don't need to be updated in NTN mode. + return status_update::no_update; + } + // We reduce the HARQ process timeout to receive the next HARQ-ACK. This is done because the two HARQ-ACKs should // arrive almost simultaneously, and in case the second goes missing, we don't want to block the HARQ for too long. auto& wheel = harq_repo->harq_timeout_wheel; @@ -679,6 +841,11 @@ std::optional unique_ue_harq_entity::find_ul_harq_waitin std::optional unique_ue_harq_entity::find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx) { + if (cell_harq_mgr->dl.alloc_hist != nullptr) { + // NTN mode. + return cell_harq_mgr->dl.alloc_hist->find_dl_harq(ue_index, uci_slot, harq_bit_idx); + } + std::vector& dl_harqs = cell_harq_mgr->dl.ues[ue_index].harqs; for (dl_harq_process_impl& h : dl_harqs) { if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_ack == uci_slot and @@ -691,6 +858,11 @@ std::optional unique_ue_harq_entity::find_dl_harq(slot_p std::optional unique_ue_harq_entity::find_ul_harq(slot_point pusch_slot) { + if (cell_harq_mgr->ul.alloc_hist != nullptr) { + // NTN mode. + return cell_harq_mgr->ul.alloc_hist->find_ul_harq(ue_index, pusch_slot); + } + std::vector& ul_harqs = cell_harq_mgr->ul.ues[ue_index].harqs; for (ul_harq_process_impl& h : ul_harqs) { if (h.status == harq_utils::harq_state_t::waiting_ack and h.slot_tx == pusch_slot) { @@ -713,3 +885,19 @@ void unique_ue_harq_entity::uci_sched_failed(slot_point uci_slot) } } } + +unsigned unique_ue_harq_entity::total_ul_bytes_waiting_crc() const +{ + if (cell_harq_mgr->ul.is_ntn_mode()) { + return cell_harq_mgr->ul.alloc_hist->sum_pending_ul_tbs(ue_index); + } + + unsigned harq_bytes = 0; + for (unsigned i = 0; i != nof_ul_harqs(); ++i) { + if (get_ul_ue().harqs[i].status != harq_utils::harq_state_t::empty) { + harq_bytes += get_ul_ue().harqs[i].prev_tx_params.tbs_bytes; + } + } + + return harq_bytes; +} diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index eb0f1620de..4a7ac6b214 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -117,9 +117,13 @@ struct ul_harq_process_impl : public base_harq_process { alloc_params prev_tx_params; }; +class ntn_dl_harq_alloc_history; +class ntn_ul_harq_alloc_history; + template struct cell_harq_repository { - using harq_type = std::conditional_t; + using harq_type = std::conditional_t; + using harq_alloc_history = std::conditional_t; struct ue_harq_entity_impl { std::vector harqs; @@ -129,8 +133,10 @@ struct cell_harq_repository { cell_harq_repository(unsigned max_ues, unsigned max_ack_wait_in_slots, unsigned max_harqs_per_ue, + unsigned ntn_cs_koffset, harq_timeout_notifier& timeout_notifier_, srslog::basic_logger& logger_); + ~cell_harq_repository(); /// Time interval, in slots, before the HARQ process assumes that the ACK/CRC went missing. const unsigned max_ack_wait_in_slots; @@ -144,6 +150,7 @@ struct cell_harq_repository { std::vector ues; intrusive_double_linked_list harq_pending_retx_list; std::vector> harq_timeout_wheel; + std::unique_ptr alloc_hist; void slot_indication(slot_point sl_tx); void handle_harq_ack_timeout(harq_type& h, slot_point sl_tx); @@ -157,6 +164,7 @@ struct cell_harq_repository { void cancel_retxs(harq_type& h); harq_type* find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state); const harq_type* find_ue_harq_in_state(du_ue_index_t ue_idx, harq_utils::harq_state_t state) const; + bool is_ntn_mode() const; }; template @@ -376,7 +384,8 @@ class cell_harq_manager cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES, unsigned max_harqs_per_ue = MAX_NOF_HARQS, std::unique_ptr notifier = nullptr, - unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS); + unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS, + unsigned ntn_cs_koffset = 0); /// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK void slot_indication(slot_point sl_tx); @@ -517,6 +526,8 @@ class unique_ue_harq_entity return 0; } + unsigned total_ul_bytes_waiting_crc() const; + private: dl_harq_ent_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } const dl_harq_ent_impl& get_dl_ue() const { return cell_harq_mgr->dl.ues[ue_index]; } From 926ce0d420e251b1453f754a6d79fb5457988887 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 30 Aug 2024 16:18:57 +0200 Subject: [PATCH 402/407] sched: implementation of NTN HARQ history tests --- lib/scheduler/cell/cell_harq_manager.cpp | 75 ++++++++----------- .../scheduler/cell/cell_harq_manager_test.cpp | 64 +++++++++++++++- 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 74790883d4..ceea5a88ab 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -42,41 +42,29 @@ class base_ntn_harq_history void slot_indication(slot_point sl_tx) { last_sl_ind = sl_tx; - // If there are no allocations, we do not let last_sl_ack get further away from last_sl_ind, to avoid ambiguity. - if (not last_sl_ack.valid() or last_sl_ack < last_sl_ind - 1) { - last_sl_ack = last_sl_ind - 1; + // If there are no allocations for a long time, we may need to reset last_sl_ack. + if (last_sl_ack.valid() and last_sl_ack < last_sl_ind - ntn_cs_koffset) { + last_sl_ack.clear(); } // Clear old entries. - unsigned idx = get_index(sl_tx - 1); + unsigned idx = get_current_index(sl_tx - 1); history[idx].clear(); } void save_harq_newtx_info(const harq_impl_type& h) { - unsigned idx = get_index(h.slot_ack); + unsigned idx = get_offset_index(h.slot_ack); history[idx].emplace_back(h); - if (h.slot_ack > last_sl_ack) { + if (not last_sl_ack.valid() or h.slot_ack > last_sl_ack) { last_sl_ack = h.slot_ack; } } - void save_harq_retx_info(const harq_impl_type& h, slot_point last_slot_ack) - { - // Clear previous HARQ transmission so it does not count in pending bytes. - unsigned last_idx = get_index(last_slot_ack); - for (unsigned i = 0; i != history[last_idx].size(); ++i) { - if (history[last_idx][i].ue_idx == h.ue_idx and history[last_idx][i].h_id == h.h_id) { - history[last_idx][i].status = harq_state_t::empty; - } - } - - save_harq_newtx_info(h); - } - protected: - unsigned get_index(slot_point sl) const { return mod((sl + ntn_cs_koffset).to_uint()); } + unsigned get_current_index(slot_point sl) const { return mod(sl.to_uint()); } + unsigned get_offset_index(slot_point sl) const { return get_current_index(sl + ntn_cs_koffset); } unsigned mod(unsigned idx) const { return idx % history.size(); } cell_harq_repository& harq_pool; @@ -99,7 +87,7 @@ class ntn_dl_harq_alloc_history : public base_ntn_harq_history std::optional find_dl_harq(du_ue_index_t ue_idx, slot_point uci_slot, unsigned harq_bit_idx) { - unsigned idx = get_index(uci_slot); + unsigned idx = get_offset_index(uci_slot); for (dl_harq_process_impl& h_impl : history[idx]) { if (h_impl.ue_idx == ue_idx and h_impl.status == harq_state_t::waiting_ack and h_impl.slot_ack == uci_slot and h_impl.harq_bit_idx == harq_bit_idx) { @@ -118,7 +106,7 @@ class ntn_ul_harq_alloc_history : public base_ntn_harq_history std::optional find_ul_harq(du_ue_index_t ue_idx, slot_point pusch_slot) { - unsigned idx = get_index(pusch_slot); + unsigned idx = get_offset_index(pusch_slot); for (ul_harq_process_impl& h_impl : history[idx]) { if (h_impl.ue_idx == ue_idx and h_impl.status == harq_state_t::waiting_ack and h_impl.slot_ack == pusch_slot) { return ul_harq_process_handle{harq_pool, h_impl}; @@ -129,12 +117,12 @@ class ntn_ul_harq_alloc_history : public base_ntn_harq_history unsigned sum_pending_ul_tbs(du_ue_index_t ue_idx) const { - if (last_sl_ack < last_sl_ind) { + if (not last_sl_ack.valid() or last_sl_ack + ntn_cs_koffset < last_sl_ind) { return 0; } - unsigned sum = 0; - for (unsigned idx = get_index(last_sl_ind), last_idx = get_index(last_sl_ack + 1); idx != last_idx; - idx = mod(idx + 1)) { + unsigned sum = 0; + unsigned end_idx = get_current_index(last_sl_ack + ntn_cs_koffset + 1); + for (unsigned idx = get_current_index(last_sl_ind); idx != end_idx; idx = mod(idx + 1)) { for (const ul_harq_process_impl& h : history[idx]) { if (h.ue_idx == ue_idx and h.status != harq_state_t::empty) { sum += h.prev_tx_params.tbs_bytes; @@ -184,6 +172,10 @@ void cell_harq_repository::slot_indication(slot_point sl_tx) { last_sl_ind = sl_tx; + if (is_ntn_mode()) { + alloc_hist->slot_indication(sl_tx); + } + // Handle HARQs that timed out. auto& harqs_timing_out = harq_timeout_wheel[sl_tx.to_uint() % harq_timeout_wheel.size()]; while (not harqs_timing_out.empty()) { @@ -218,7 +210,7 @@ void cell_harq_repository::handle_harq_ack_timeout(harq_type& h, slot_poin { srsran_sanity_check(h.status == harq_state_t::waiting_ack, "HARQ process in wrong state"); - if (max_ack_wait_in_slots != 1) { + if (not is_ntn_mode()) { // Only in non-NTN case, we log a warning. if (h.ack_on_timeout) { // Case: Not all HARQ-ACKs were received, but at least one positive ACK was received. @@ -278,11 +270,6 @@ typename cell_harq_repository::harq_type* cell_harq_repository::allo h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); - if (is_ntn_mode()) { - // In NTN mode, save HARQ info separately. - alloc_hist->save_harq_newtx_info(h); - } - return &h; } @@ -375,22 +362,16 @@ bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, // Remove HARQ from pending Retx list. harq_pending_retx_list.pop(&h); - slot_point prev_sl_ack = h.slot_ack; - h.status = harq_state_t::waiting_ack; - h.slot_tx = sl_tx; - h.slot_ack = sl_ack; - h.ack_on_timeout = false; + h.status = harq_state_t::waiting_ack; + h.slot_tx = sl_tx; + h.slot_ack = sl_ack; + h.ack_on_timeout = false; h.nof_retxs++; // Add HARQ to the timeout list. h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); - if (is_ntn_mode()) { - // In NTN mode, save HARQ info separately. - alloc_hist->save_harq_retx_info(h, prev_sl_ack); - } - return true; } @@ -678,6 +659,11 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_alloc_context& ctx, prev_params.mcs = cw.mcs_index; prev_params.rbs = pdsch.rbs; prev_params.nof_symbols = pdsch.symbols.length(); + + if (harq_repo->is_ntn_mode()) { + // In NTN mode, save the HARQ info in history. + harq_repo->alloc_hist->save_harq_newtx_info(*impl); + } } bool ul_harq_process_handle::new_retx(slot_point pusch_slot) @@ -722,6 +708,11 @@ void ul_harq_process_handle::save_grant_params(const ul_harq_alloc_context& ctx, prev_tx_params.mcs = pusch.mcs_index; prev_tx_params.rbs = pusch.rbs; prev_tx_params.nof_symbols = pusch.symbols.length(); + + if (harq_repo->is_ntn_mode()) { + // In NTN mode, save the HARQ info in history. + harq_repo->alloc_hist->save_harq_newtx_info(*impl); + } } // UE HARQ entity. diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index d9424e346c..376c05f43f 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -92,8 +92,8 @@ class dummy_harq_timeout_handler class base_harq_manager_test { protected: - base_harq_manager_test(unsigned nof_ues) : - cell_harqs(nof_ues, max_harqs_per_ue, timeout_handler.make_notifier(), max_ack_wait_timeout) + base_harq_manager_test(unsigned nof_ues, unsigned ntn_cs_koffset = 0) : + cell_harqs(nof_ues, max_harqs_per_ue, timeout_handler.make_notifier(), max_ack_wait_timeout, ntn_cs_koffset) { logger.set_level(srslog::basic_levels::warning); srslog::init(); @@ -122,7 +122,7 @@ class base_harq_manager_test class base_single_harq_entity_test : public base_harq_manager_test { protected: - base_single_harq_entity_test() : base_harq_manager_test(1) {} + base_single_harq_entity_test(unsigned ntn_cs_koffset = 0) : base_harq_manager_test(1, ntn_cs_koffset) {} const du_ue_index_t ue_index = to_du_ue_index(0); const rnti_t rnti = to_rnti(0x4601); @@ -152,7 +152,7 @@ class single_ue_harq_entity_test : public base_single_harq_entity_test, public : class single_harq_process_test : public base_single_harq_entity_test, public ::testing::Test { protected: - single_harq_process_test() + single_harq_process_test(unsigned ntn_cs_koffset = 0) : base_single_harq_entity_test(ntn_cs_koffset) { pdsch_info = make_dummy_pdsch_info(); dl_harq_alloc_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; @@ -259,6 +259,13 @@ class single_ue_harq_entity_2_bits_tester : public base_single_harq_entity_test, class single_ue_harq_entity_harq_5bit_tester : public base_single_harq_entity_test, public ::testing::Test {}; +// Test for a single UE HARQ process in NTN mode. +class single_ntn_ue_harq_process_test : public single_harq_process_test +{ +public: + single_ntn_ue_harq_process_test() : single_harq_process_test(NTN_CELL_SPECIFIC_KOFFSET_MAX) {} +}; + } // namespace // HARQ process tests @@ -289,6 +296,7 @@ TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_grant_params_h ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); ASSERT_EQ(h_dl.get_grant_params().rbs.type1(), pdsch_info.rbs.type1()); ASSERT_EQ(h_dl.get_grant_params().dci_cfg_type, dci_dl_rnti_config_type::c_rnti_f1_0); + ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_crc()); } TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) @@ -300,6 +308,8 @@ TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) ASSERT_EQ(h_ul.ul_crc_info(true), pusch_info.tb_size_bytes); ASSERT_FALSE(h_ul.is_waiting_ack()); ASSERT_FALSE(h_ul.has_pending_retx()); + + ASSERT_EQ(harq_ent.total_ul_bytes_waiting_crc(), 0); } TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) @@ -1009,3 +1019,49 @@ TEST_F(multi_ue_harq_manager_test, when_new_tx_occur_for_different_ues_then_ndi_ ASSERT_NE(h_dl->ndi(), ndi_dl1); ASSERT_NE(h_ul->ndi(), ndi_ul1); } + +// single_ntn_ue_harq_process_test + +TEST_F(single_ntn_ue_harq_process_test, when_harq_allocated_then_it_flushes_soon_after) +{ + slot_point slot_dl_timeout = current_slot + k1 + 1; + slot_point slot_ul_timeout = current_slot + k2 + 1; + + while (current_slot != std::max(slot_dl_timeout, slot_ul_timeout)) { + if (current_slot < slot_dl_timeout) { + ASSERT_TRUE(h_dl.is_waiting_ack()); + ASSERT_EQ(h_dl, harq_ent.dl_harq(to_harq_id(0))); + } else { + ASSERT_TRUE(h_dl.empty()); + ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(0)).has_value()); + } + if (current_slot < slot_ul_timeout) { + ASSERT_TRUE(h_ul.is_waiting_ack()); + ASSERT_EQ(h_ul, harq_ent.ul_harq(to_harq_id(0))); + } else { + ASSERT_TRUE(h_ul.empty()); + ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(0)).has_value()); + } + run_slot(); + } +} + +TEST_F(single_ntn_ue_harq_process_test, harq_history_is_reachable_after_timeout) +{ + slot_point uci_slot = current_slot + k1; + slot_point pusch_slot = current_slot + k2; + slot_point slot_timeout = std::max(uci_slot, pusch_slot) + 1; + while (current_slot != slot_timeout) { + run_slot(); + } + ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(0)).has_value()); + ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(0)).has_value()); + + h_dl = harq_ent.find_dl_harq(uci_slot, 0).value(); + h_ul = harq_ent.find_ul_harq(pusch_slot).value(); + ASSERT_FALSE(h_dl.empty() and h_ul.empty()); + ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); + ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, pusch_info.tb_size_bytes); + + ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_crc()); +} \ No newline at end of file From fb48b399a2f08d2de6035f578eaa4a2787da1f04 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 30 Aug 2024 16:40:56 +0200 Subject: [PATCH 403/407] sched: extend NTN HARQ unit tests --- lib/scheduler/cell/cell_harq_manager.cpp | 13 ++++++++++++ lib/scheduler/cell/cell_harq_manager.h | 2 +- .../scheduler/cell/cell_harq_manager_test.cpp | 20 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index ceea5a88ab..13d5cd2f6e 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -62,6 +62,18 @@ class base_ntn_harq_history } } + void handle_ack(harq_impl_type& h) + { + auto& hist_entry = history[get_offset_index(h.slot_ack)]; + if (&h < hist_entry.data() or &h >= hist_entry.data() + hist_entry.size()) { + // Check if the HARQ Process being ACKed is the same as the one managed by the NTN history. + srsran_assertion_failure("ACK Info handled for a non-NTN HARQ process"); + srslog::fetch_basic_logger("SCHED").error("ACK Info handled for a non-NTN HARQ process"); + return; + } + h.status = harq_state_t::empty; + } + protected: unsigned get_current_index(slot_point sl) const { return mod(sl.to_uint()); } unsigned get_offset_index(slot_point sl) const { return get_current_index(sl + ntn_cs_koffset); } @@ -320,6 +332,7 @@ void cell_harq_repository::handle_ack(harq_type& h, bool ack) if (is_ntn_mode()) { // In NTN mode, ACK info does not affect the timeout/retx containers. + alloc_hist->handle_ack(h); return; } diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 4a7ac6b214..6de24ef01f 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -402,7 +402,7 @@ class cell_harq_manager unsigned nof_dl_harq_procs = MAX_NOF_HARQS, unsigned nof_ul_harq_procs = MAX_NOF_HARQS); - /// Checks whether an UE with the provided ue index exists. + /// Checks whether a UE with the provided ue index exists. bool contains(du_ue_index_t ue_idx) const; /// Retrieve list of HARQ processes with pending retxs. diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index 376c05f43f..89a3105bec 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -1064,4 +1064,24 @@ TEST_F(single_ntn_ue_harq_process_test, harq_history_is_reachable_after_timeout) ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, pusch_info.tb_size_bytes); ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_crc()); +} + +TEST_F(single_ntn_ue_harq_process_test, when_harq_gets_acked_then_it_reports_the_correct_tbs) +{ + slot_point pusch_slot = current_slot + k2; + slot_point uci_slot = current_slot + k1; + slot_point slot_timeout = std::max(pusch_slot, uci_slot) + 1; + while (current_slot != slot_timeout) { + run_slot(); + } + + h_ul = harq_ent.find_ul_harq(pusch_slot).value(); + ASSERT_EQ(harq_ent.total_ul_bytes_waiting_crc(), pusch_info.tb_size_bytes); + ASSERT_EQ(h_ul.ul_crc_info(true), pusch_info.tb_size_bytes); + ASSERT_EQ(harq_ent.total_ul_bytes_waiting_crc(), 0); + + h_dl = harq_ent.find_dl_harq(uci_slot, 0).value(); + ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), + dl_harq_process_handle::status_update::acked); + ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); } \ No newline at end of file From e249f59eb4d9fcd8710d95932fd2eae37cbeca12 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 28 Aug 2024 18:36:53 +0200 Subject: [PATCH 404/407] sched: integrate new HARQ manager in RA scheduler --- lib/scheduler/cell/cell_harq_manager.cpp | 22 +++- .../common_scheduling/ra_scheduler.cpp | 104 ++++++++++++------ .../common_scheduling/ra_scheduler.h | 10 +- lib/scheduler/support/dci_builder.cpp | 8 +- lib/scheduler/support/dci_builder.h | 7 +- .../ue_scheduling/ue_cell_grid_allocator.cpp | 3 +- 6 files changed, 101 insertions(+), 53 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 13d5cd2f6e..f9185c23a7 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -206,7 +206,7 @@ void cell_harq_repository::slot_indication(slot_point sl_tx) break; } - // HARQ is trapped. Remove it. + // HARQ retransmission is trapped. Deallocate HARQ process. logger.warning( "rnti={} h_id={}: Discarding {} HARQ. Cause: Too much time has passed since the last HARQ " "transmission. The scheduler policy is likely not prioritizing retransmissions of old HARQ processes.", @@ -214,6 +214,9 @@ void cell_harq_repository::slot_indication(slot_point sl_tx) h.h_id, IsDl ? "DL" : "UL"); dealloc_harq(h); + + // Report timeout after the HARQ gets deleted to avoid reentrancy. + timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, false); } } @@ -222,9 +225,10 @@ void cell_harq_repository::handle_harq_ack_timeout(harq_type& h, slot_poin { srsran_sanity_check(h.status == harq_state_t::waiting_ack, "HARQ process in wrong state"); + bool ack_val = h.ack_on_timeout; if (not is_ntn_mode()) { // Only in non-NTN case, we log a warning. - if (h.ack_on_timeout) { + if (ack_val) { // Case: Not all HARQ-ACKs were received, but at least one positive ACK was received. logger.debug("rnti={} h_id={}: Setting {} HARQ to \"ACKed\" state. Cause: HARQ-ACK wait timeout ({} slots) was " "reached with still missing PUCCH HARQ-ACKs. However, one positive ACK was received.", @@ -242,13 +246,16 @@ void cell_harq_repository::handle_harq_ack_timeout(harq_type& h, slot_poin IsDl ? "DL" : "UL", h.slot_ack_timeout - h.slot_ack); } - - // Report timeout with NACK. - timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, h.ack_on_timeout); } // Deallocate HARQ. dealloc_harq(h); + + if (max_ack_wait_in_slots != 1) { + // Report timeout with NACK after we delete the HARQ to avoid reentrancy. + // Only in non-NTN case. + timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, ack_val); + } } template @@ -736,10 +743,11 @@ unique_ue_harq_entity::unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index } unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept : - cell_harq_mgr(other.cell_harq_mgr), ue_index(other.ue_index) + cell_harq_mgr(other.cell_harq_mgr), ue_index(other.ue_index), crnti(other.crnti) { other.cell_harq_mgr = nullptr; other.ue_index = INVALID_DU_UE_INDEX; + other.crnti = rnti_t::INVALID_RNTI; } unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&& other) noexcept @@ -749,8 +757,10 @@ unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&& } cell_harq_mgr = other.cell_harq_mgr; ue_index = other.ue_index; + crnti = other.crnti; other.cell_harq_mgr = nullptr; other.ue_index = INVALID_DU_UE_INDEX; + other.crnti = rnti_t::INVALID_RNTI; return *this; } diff --git a/lib/scheduler/common_scheduling/ra_scheduler.cpp b/lib/scheduler/common_scheduling/ra_scheduler.cpp index 3e31f8938a..66e93d1b63 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.cpp +++ b/lib/scheduler/common_scheduling/ra_scheduler.cpp @@ -68,6 +68,23 @@ static crb_interval msg3_vrb_to_crb(const cell_configuration& cell_cfg, vrb_inte cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start()); } +class ra_scheduler::msg3_harq_timeout_notifier final : public harq_timeout_notifier +{ +public: + msg3_harq_timeout_notifier(std::vector& pending_msg3s_) : pending_msg3s(pending_msg3s_) {} + + void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override + { + srsran_sanity_check(pending_msg3s[ue_idx].busy(), "timeout called but HARQ entity does not exist"); + + // Delete Msg3 HARQ entity to make it available again. + pending_msg3s[ue_idx].msg3_harq_ent.reset(); + } + +private: + std::vector& pending_msg3s; +}; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_, @@ -87,6 +104,7 @@ ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_, band_helper::get_duplex_mode(cell_cfg.band), 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_msg3s(MAX_NOF_MSG3) { // Precompute RAR PDSCH and DCI PDUs. @@ -171,8 +189,7 @@ void ra_scheduler::precompute_msg3_pdus() crb_interval{0, prbs_tbs.nof_prbs}, i, sched_cfg.msg3_mcs_index, - msg3_rv, - dummy_h_ul); + msg3_rv); // Note: RNTI will be overwritten later. build_pusch_f0_0_tc_rnti(msg3_data[i].pusch, @@ -246,7 +263,9 @@ void ra_scheduler::handle_rach_indication_impl(const rach_indication_message& ms prach_preamble.time_advance.to_Ta(get_ul_bwp_cfg().scs)}); // Check if TC-RNTI value to be scheduled is already under use - if (not pending_msg3s[to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3].harq.empty()) { + unsigned msg3_ring_idx = to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3; + auto& msg3_entry = pending_msg3s[msg3_ring_idx]; + if (msg3_entry.busy()) { logger.warning("PRACH ignored, as the allocated TC-RNTI={} is already under use", prach_preamble.tc_rnti); continue; } @@ -254,9 +273,9 @@ void ra_scheduler::handle_rach_indication_impl(const rach_indication_message& ms // Store TC-RNTI of the preamble. rar_req->tc_rntis.emplace_back(prach_preamble.tc_rnti); - // Store Msg3 to allocate. - pending_msg3s[to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3].preamble = prach_preamble; - pending_msg3s[to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3].msg3_harq_logger.set_rnti(prach_preamble.tc_rnti); + // Store Msg3 request and create a HARQ entity of 1 UL HARQ. + msg3_entry.preamble = prach_preamble; + msg3_entry.msg3_harq_ent = msg3_harqs.add_ue(to_du_ue_index(msg3_ring_idx), prach_preamble.tc_rnti, 1, 1); } } } @@ -274,41 +293,51 @@ void ra_scheduler::handle_pending_crc_indications_impl(cell_resource_allocator& for (const ul_crc_indication& crc_ind : new_crc_inds) { 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 ueId assigned yet"); + 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]; - if (pending_msg3.preamble.tc_rnti != crc.rnti) { - logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: Nonexistent rnti.", + if (pending_msg3.preamble.tc_rnti != crc.rnti or pending_msg3.msg3_harq_ent.empty()) { + logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: Nonexistent tc-rnti", cell_cfg.cell_index, crc.rnti, crc.harq_id); continue; } - if (pending_msg3.harq.id != crc.harq_id) { - logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: HARQ-Ids do not match ({} != {})", + + // See TS38.321, 5.4.2.1 - "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is used." + harq_id_t h_id = to_harq_id(0); + std::optional h_ul = pending_msg3.msg3_harq_ent.ul_harq(h_id); + if (not h_ul.has_value() or crc.harq_id != h_id) { + logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: HARQ-Id 0 must be used in Msg3", cell_cfg.cell_index, crc.rnti, - crc.harq_id, - crc.harq_id, - pending_msg3.harq.id); + crc.harq_id); continue; } - pending_msg3.harq.crc_info(crc.tb_crc_success); + + // Handle CRC info. + h_ul->ul_crc_info(crc.tb_crc_success); + if (h_ul->empty()) { + // Deallocate Msg3 entry. + pending_msg3.msg3_harq_ent.reset(); + } } } // Allocate pending Msg3 retransmissions. - for (auto& pending_msg3 : pending_msg3s) { - if (not pending_msg3.harq.empty()) { - pending_msg3.harq.slot_indication(res_alloc.slot_tx()); - if (pending_msg3.harq.has_pending_retx()) { - schedule_msg3_retx(res_alloc, pending_msg3); - } - } + // Note: pending_ul_retxs size will change in this iteration, so we prefetch the next iterator. + auto pending_ul_retxs = msg3_harqs.pending_ul_retxs(); + for (auto it = pending_ul_retxs.begin(); it != pending_ul_retxs.end();) { + ul_harq_process_handle h_ul = *it; + ++it; + schedule_msg3_retx(res_alloc, pending_msg3s[h_ul.ue_index()]); } } void ra_scheduler::run_slot(cell_resource_allocator& res_alloc) { + // Update Msg3 HARQ state. + msg3_harqs.slot_indication(res_alloc.slot_tx()); + // Handle pending CRCs, which may lead to Msg3 reTxs. handle_pending_crc_indications_impl(res_alloc); @@ -648,10 +677,12 @@ void ra_scheduler::fill_rar_grant(cell_resource_allocator& res_alloc, const vrb_interval vrbs = msg3_crb_to_vrb(cell_cfg, msg3_candidate.crbs); auto& pending_msg3 = pending_msg3s[to_value(rar_request.tc_rntis[i]) % MAX_NOF_MSG3]; - srsran_sanity_check(pending_msg3.harq.empty(), "Pending Msg3 should not have been added if HARQ is busy"); + srsran_sanity_check(pending_msg3.busy(), "Pending Msg3 entry should have been reserved when RACH was received"); // Allocate Msg3 UL HARQ - pending_msg3.harq.new_tx(msg3_alloc.slot, sched_cfg.max_nof_msg3_harq_retxs); + std::optional h_ul = + pending_msg3.msg3_harq_ent.alloc_ul_harq(msg3_alloc.slot, sched_cfg.max_nof_msg3_harq_retxs); + srsran_sanity_check(h_ul.has_value(), "Pending Msg3 HARQ must be available when RAR is allocated"); // Add MAC SDU with UL grant (Msg3) in RAR PDU. rar_ul_grant& msg3_info = rar.grants.emplace_back(); @@ -683,7 +714,7 @@ void ra_scheduler::fill_rar_grant(cell_resource_allocator& res_alloc, pusch.pusch_cfg.new_data = true; // Store parameters used in HARQ. - pending_msg3.harq.save_alloc_params(ul_harq_sched_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, pusch.pusch_cfg); + h_ul->save_grant_params(ul_harq_alloc_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, pusch.pusch_cfg); } } @@ -703,6 +734,10 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin return; } + ul_harq_process_handle h_ul = msg3_ctx.msg3_harq_ent.ul_harq(to_harq_id(0)).value(); + srsran_sanity_check(h_ul.has_pending_retx(), "schedule_msg3_retx called when HARQ has no pending reTx"); + const ul_harq_process_handle::grant_params& last_harq_params = h_ul.get_grant_params(); + const span pusch_td_alloc_list = get_pusch_time_domain_resource_table(get_pusch_cfg()); for (unsigned pusch_td_res_index = 0; pusch_td_res_index != pusch_td_alloc_list.size(); ++pusch_td_res_index) { @@ -713,8 +748,7 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - cell_cfg.get_nof_ul_symbol_per_slot(pusch_alloc.slot); // If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for // the first transmission. - const bool sym_length_match_prev_grant_for_retx = - pusch_td_cfg.symbols.length() == msg3_ctx.harq.last_tx_params().nof_symbols; + const bool sym_length_match_prev_grant_for_retx = pusch_td_cfg.symbols.length() == last_harq_params.nof_symbols; if (not cell_cfg.is_ul_enabled(pusch_alloc.slot) or pusch_td_cfg.symbols.start() < start_ul_symbols or !sym_length_match_prev_grant_for_retx) { // Not possible to schedule Msg3s in this TDD slot. @@ -728,7 +762,7 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin } // Try to reuse previous HARQ PRBs. - const vrb_interval msg3_vrbs = msg3_ctx.harq.last_tx_params().rbs.type1(); + const vrb_interval msg3_vrbs = last_harq_params.rbs.type1(); grant_info grant; grant.scs = bwp_ul_cmn.scs; grant.symbols = pusch_td_cfg.symbols; @@ -764,7 +798,10 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin pusch_alloc.ul_res_grid.fill(grant); // Allocate new retx in the HARQ. - msg3_ctx.harq.new_retx(pusch_alloc.slot); + if (not h_ul.new_retx(pusch_alloc.slot)) { + logger.warning("tc-rnti={}: Failed to allocate reTx for Msg3", msg3_ctx.preamble.tc_rnti); + continue; + } // Fill DCI. static constexpr uint8_t msg3_rv = 0; @@ -773,16 +810,15 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin cell_cfg.ul_cfg_common.init_ul_bwp.generic_params, grant.crbs, pusch_td_res_index, - msg3_ctx.harq.last_tx_params().mcs, - msg3_rv, - msg3_ctx.harq); + last_harq_params.mcs, + msg3_rv); // Fill PUSCH. ul_sched_info& ul_info = pusch_alloc.result.ul.puschs.emplace_back(); ul_info.context.ue_index = INVALID_DU_UE_INDEX; ul_info.context.ss_id = cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common.ra_search_space_id; ul_info.context.k2 = k2; - ul_info.context.nof_retxs = msg3_ctx.harq.tb().nof_retxs; + ul_info.context.nof_retxs = h_ul.nof_retxs(); ul_info.pusch_cfg = msg3_data[pusch_td_res_index].pusch; ul_info.pusch_cfg.rnti = msg3_ctx.preamble.tc_rnti; ul_info.pusch_cfg.rbs = msg3_vrbs; @@ -790,7 +826,7 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin ul_info.pusch_cfg.new_data = false; // Store parameters used in HARQ. - msg3_ctx.harq.save_alloc_params(ul_harq_sched_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, ul_info.pusch_cfg); + h_ul.save_grant_params(ul_harq_alloc_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, ul_info.pusch_cfg); // successful allocation. Exit loop. break; diff --git a/lib/scheduler/common_scheduling/ra_scheduler.h b/lib/scheduler/common_scheduling/ra_scheduler.h index 6dc859e83a..a74d896d6b 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.h +++ b/lib/scheduler/common_scheduling/ra_scheduler.h @@ -10,11 +10,11 @@ #pragma once +#include "../cell/cell_harq_manager.h" #include "../cell/resource_grid.h" #include "../pdcch_scheduling/pdcch_resource_allocator.h" #include "../support/prbs_calculator.h" #include "../support/slot_event_list.h" -#include "../ue_scheduling/harq_process.h" #include "srsran/ran/prach/prach_configuration.h" #include "srsran/scheduler/config/scheduler_expert_config.h" #include "srsran/srslog/srslog.h" @@ -61,6 +61,8 @@ class ra_scheduler void run_slot(cell_resource_allocator& res_alloc); private: + class msg3_harq_timeout_notifier; + struct pending_rar_t { rnti_t ra_rnti = rnti_t::INVALID_RNTI; slot_point prach_slot_rx; @@ -71,11 +73,12 @@ class ra_scheduler struct pending_msg3_t { /// Detected PRACH Preamble associated to this Msg3. rach_indication_message::preamble preamble{}; - harq_logger msg3_harq_logger{srslog::fetch_basic_logger("SCHED"), rnti_t::INVALID_RNTI, to_du_cell_index(0), false}; /// UL Harq used to schedule Msg3. /// Note: [TS 38.321, 5.4.2.1] "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is /// used". - ul_harq_process harq{to_harq_id(0), msg3_harq_logger}; + unique_ue_harq_entity msg3_harq_ent; + + bool busy() const { return not msg3_harq_ent.empty(); } }; struct msg3_alloc_candidate { unsigned pusch_td_res_index; @@ -170,6 +173,7 @@ class ra_scheduler sch_mcs_description msg3_mcs_config; // variables + cell_harq_manager msg3_harqs; slot_event_list pending_rachs; slot_event_list pending_crcs; std::deque pending_rars; diff --git a/lib/scheduler/support/dci_builder.cpp b/lib/scheduler/support/dci_builder.cpp index b67c57505f..72254c5ee1 100644 --- a/lib/scheduler/support/dci_builder.cpp +++ b/lib/scheduler/support/dci_builder.cpp @@ -8,6 +8,8 @@ */ #include "dci_builder.h" +#include "../cell/cell_harq_manager.h" +#include "../ue_scheduling/harq_process.h" #include "srsran/adt/optional.h" #include "srsran/ran/pdcch/dci_packing.h" #include "srsran/ran/pdcch/search_space.h" @@ -291,12 +293,8 @@ void srsran::build_dci_f0_0_tc_rnti(dci_ul_info& dci, const crb_interval& crbs, unsigned time_resource, sch_mcs_index mcs_index, - uint8_t rv, - const ul_harq_process& h_ul) + uint8_t rv) { - // See TS38.321, 5.4.2.1 - "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is used." - srsran_assert(h_ul.id == 0, "UL HARQ process used for Msg3 must have id=0"); - dci.type = dci_ul_rnti_config_type::tc_rnti_f0_0; dci.tc_rnti_f0_0 = {}; dci_0_0_tc_rnti_configuration& f0_0 = dci.tc_rnti_f0_0; diff --git a/lib/scheduler/support/dci_builder.h b/lib/scheduler/support/dci_builder.h index 3cb968a3c7..4216e9ce75 100644 --- a/lib/scheduler/support/dci_builder.h +++ b/lib/scheduler/support/dci_builder.h @@ -10,7 +10,6 @@ #pragma once #include "../config/ue_configuration.h" -#include "../ue_scheduling/harq_process.h" #include "srsran/ran/pdcch/search_space.h" #include "srsran/ran/resource_allocation/resource_allocation_frequency.h" #include "srsran/scheduler/config/bwp_configuration.h" @@ -18,6 +17,9 @@ namespace srsran { +class dl_harq_process; +class ul_harq_process; + /// Builds DCI f1_0 for SI-RNTI used in SIBs. void build_dci_f1_0_si_rnti(dci_dl_info& dci, const bwp_downlink_common& init_dl_bwp, @@ -85,8 +87,7 @@ void build_dci_f0_0_tc_rnti(dci_ul_info& dci, const crb_interval& crbs, unsigned time_resource, sch_mcs_index mcs_index, - uint8_t rv, - const ul_harq_process& h_ul); + uint8_t rv); /// Builds DCI f0_0 for C-RNTI. void build_dci_f0_0_c_rnti(dci_ul_info& dci, diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 28a9730e05..e86d5b3c57 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -877,8 +877,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice crbs, param_candidate.pusch_td_res_index(), mcs_tbs_info.value().mcs, - rv, - h_ul); + rv); break; case dci_ul_rnti_config_type::c_rnti_f0_0: build_dci_f0_0_c_rnti(pdcch->dci, From 51c0185f36839efd88c9edf03151612761b82e2b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 29 Aug 2024 17:09:28 +0200 Subject: [PATCH 405/407] sched: integration of new cell harq system in the scheduler --- lib/scheduler/cell/cell_harq_manager.cpp | 3 +- lib/scheduler/cell/cell_harq_manager.h | 8 +- .../common_scheduling/ra_scheduler.cpp | 6 - lib/scheduler/policy/scheduler_time_pf.cpp | 96 +++-- lib/scheduler/policy/scheduler_time_pf.h | 12 +- lib/scheduler/policy/scheduler_time_rr.cpp | 222 ++++++----- lib/scheduler/slicing/slice_scheduler.cpp | 16 +- lib/scheduler/slicing/slice_ue_repository.cpp | 6 +- lib/scheduler/support/dci_builder.cpp | 123 +++--- lib/scheduler/support/dci_builder.h | 104 ++--- lib/scheduler/support/sch_pdu_builder.cpp | 11 +- lib/scheduler/support/sch_pdu_builder.h | 5 +- lib/scheduler/ue_scheduling/ue.cpp | 14 +- lib/scheduler/ue_scheduling/ue.h | 17 +- lib/scheduler/ue_scheduling/ue_cell.cpp | 100 +++-- lib/scheduler/ue_scheduling/ue_cell.h | 17 +- .../ue_scheduling/ue_cell_grid_allocator.cpp | 93 ++--- .../ue_scheduling/ue_event_manager.cpp | 22 +- .../ue_scheduling/ue_event_manager.h | 4 + .../ue_scheduling/ue_fallback_scheduler.cpp | 372 +++++++++--------- .../ue_scheduling/ue_fallback_scheduler.h | 143 +++---- .../ue_pdsch_alloc_param_candidate_searcher.h | 20 +- .../ue_pusch_alloc_param_candidate_searcher.h | 12 +- lib/scheduler/ue_scheduling/ue_repository.cpp | 6 +- .../ue_scheduling/ue_scheduler_impl.cpp | 47 ++- .../ue_scheduling/ue_scheduler_impl.h | 16 +- .../policy/scheduler_policy_test.cpp | 8 +- .../slicing/slice_scheduler_test.cpp | 7 +- .../test_utils/dummy_test_components.h | 18 + .../uci_and_pucch/uci_test_utils.cpp | 25 +- .../scheduler/uci_and_pucch/uci_test_utils.h | 1 + .../ue_scheduling/fallback_scheduler_test.cpp | 116 +++--- .../scheduler/ue_scheduling/ue_cell_test.cpp | 9 +- .../ue_scheduling/ue_configuration_test.cpp | 5 +- .../ue_scheduling/ue_grid_allocator_test.cpp | 66 ++-- .../ue_harq_link_adaptation_test.cpp | 43 +- ...ch_alloc_param_candidate_searcher_test.cpp | 8 +- 37 files changed, 954 insertions(+), 847 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index f9185c23a7..429a0a9065 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -695,7 +695,8 @@ int ul_harq_process_handle::ul_crc_info(bool ack) { if (impl->status != harq_state_t::waiting_ack) { // HARQ is not expecting CRC info. - harq_repo->logger.warning("rnti={} h_id={}: CRC arrived for UL HARQ not expecting it", impl->rnti, impl->h_id); + harq_repo->logger.warning( + "rnti={} h_id={}: Discarding CRC. Cause: UL HARQ process is not expecting any CRC", impl->rnti, impl->h_id); return -1; } diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 6de24ef01f..2d7ba50ea0 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -464,28 +464,28 @@ class unique_ue_harq_entity std::optional dl_harq(harq_id_t h_id) { - if (get_dl_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + if (h_id < get_dl_ue().harqs.size() and get_dl_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { return dl_harq_process_handle{cell_harq_mgr->dl, get_dl_ue().harqs[h_id]}; } return std::nullopt; } std::optional dl_harq(harq_id_t h_id) const { - if (get_dl_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + if (h_id < get_dl_ue().harqs.size() and get_dl_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { return dl_harq_process_handle{cell_harq_mgr->dl, cell_harq_mgr->dl.ues[ue_index].harqs[h_id]}; } return std::nullopt; } std::optional ul_harq(harq_id_t h_id) { - if (get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + if (h_id < get_ul_ue().harqs.size() and get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { return ul_harq_process_handle{cell_harq_mgr->ul, get_ul_ue().harqs[h_id]}; } return std::nullopt; } std::optional ul_harq(harq_id_t h_id) const { - if (get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { + if (h_id < get_ul_ue().harqs.size() and get_ul_ue().harqs[h_id].status != harq_utils::harq_state_t::empty) { return ul_harq_process_handle{cell_harq_mgr->ul, cell_harq_mgr->ul.ues[ue_index].harqs[h_id]}; } return std::nullopt; diff --git a/lib/scheduler/common_scheduling/ra_scheduler.cpp b/lib/scheduler/common_scheduling/ra_scheduler.cpp index 66e93d1b63..748f3c872c 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.cpp +++ b/lib/scheduler/common_scheduling/ra_scheduler.cpp @@ -165,12 +165,6 @@ void ra_scheduler::precompute_msg3_pdus() msg3_data.resize(pusch_td_alloc_list.size()); for (unsigned i = 0; i != msg3_data.size(); ++i) { - // Create a dummy HARQ used to fill DCI and PUSCH. - harq_logger dummy_harq_logger{logger, to_rnti(0x4601), cell_cfg.cell_index, false}; - ul_harq_process dummy_h_ul(to_harq_id(0), dummy_harq_logger); - const slot_point dummy_slot{to_numerology_value(get_ul_bwp_cfg().scs), 0}; - dummy_h_ul.new_tx(dummy_slot, sched_cfg.max_nof_msg3_harq_retxs); - // Compute the required PRBs and TBS for Msg3. const pusch_config_params pusch_cfg = get_pusch_config_f0_0_tc_rnti(cell_cfg, pusch_td_alloc_list[i]); const sch_prbs_tbs prbs_tbs = diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index f485b30f89..db7ef9f0ff 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -54,7 +54,7 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, ue.save_dl_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are // attempted again before scheduling new transmissions. - if (ue.dl_retx_h != nullptr and alloc_result.status == alloc_status::invalid_params) { + if (ue.dl_retx_h.has_value() and alloc_result.status == alloc_status::invalid_params) { dl_queue.push(&ue); } dl_queue.pop(); @@ -99,7 +99,7 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, ue.save_ul_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are // attempted again before scheduling new transmissions. - if (ue.ul_retx_h != nullptr and alloc_result.status == alloc_status::invalid_params) { + if (ue.ul_retx_h.has_value() and alloc_result.status == alloc_status::invalid_params) { ul_queue.push(&ue); } ul_queue.pop(); @@ -115,24 +115,24 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, alloc_result alloc_result = {alloc_status::invalid_params}; ue_pdsch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; // Prioritize reTx over newTx. - if (ctxt.dl_retx_h != nullptr) { - grant.h_id = ctxt.dl_retx_h->id; + if (ctxt.dl_retx_h.has_value()) { + grant.h_id = ctxt.dl_retx_h->id(); alloc_result = pdsch_alloc.allocate_dl_grant(grant); if (alloc_result.status == alloc_status::success) { - ctxt.dl_retx_h = nullptr; + ctxt.dl_retx_h.reset(); } // Return result here irrespective of the outcome so that reTxs of UEs are scheduled before scheduling newTxs of // UEs. return alloc_result; } - if (ctxt.dl_newtx_h != nullptr) { - grant.h_id = ctxt.dl_newtx_h->id; + if (ctxt.has_empty_dl_harq) { + grant.h_id = INVALID_HARQ_ID; grant.recommended_nof_bytes = ues[ctxt.ue_index].pending_dl_newtx_bytes(); grant.max_nof_rbs = max_rbs; alloc_result = pdsch_alloc.allocate_dl_grant(grant); if (alloc_result.status == alloc_status::success) { - ctxt.dl_newtx_h = nullptr; + ctxt.has_empty_dl_harq = false; } return alloc_result; } @@ -148,24 +148,24 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, alloc_result alloc_result = {alloc_status::invalid_params}; ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; // Prioritize reTx over newTx. - if (ctxt.ul_retx_h != nullptr) { - grant.h_id = ctxt.ul_retx_h->id; + if (ctxt.ul_retx_h.has_value()) { + grant.h_id = ctxt.ul_retx_h->id(); alloc_result = pusch_alloc.allocate_ul_grant(grant); if (alloc_result.status == alloc_status::success) { - ctxt.ul_retx_h = nullptr; + ctxt.ul_retx_h.reset(); } // Return result here irrespective of the outcome so that reTxs of UEs are scheduled before scheduling newTxs of // UEs. return alloc_result; } - if (ctxt.ul_newtx_h != nullptr) { - grant.h_id = ctxt.ul_newtx_h->id; + if (ctxt.has_empty_ul_harq) { + grant.h_id = INVALID_HARQ_ID; grant.recommended_nof_bytes = ues[ctxt.ue_index].pending_ul_newtx_bytes(); grant.max_nof_rbs = max_rbs; alloc_result = pusch_alloc.allocate_ul_grant(grant); if (alloc_result.status == alloc_status::success) { - ctxt.ul_newtx_h = nullptr; + ctxt.has_empty_ul_harq = false; } return alloc_result; } @@ -177,8 +177,8 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id_t slice_id) { - dl_retx_h = nullptr; - dl_newtx_h = nullptr; + dl_retx_h.reset(); + has_empty_dl_harq = false; dl_prio = 0; const ue_cell* ue_cc = u.find_cell(cell_index); if (ue_cc == nullptr) { @@ -188,23 +188,21 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id "policy scheduler called for UE={} in fallback", ue_cc->ue_index); - static_vector dl_harq_candidates; - // Create list of DL HARQ processes with pending retx, sorted from oldest to newest. + std::optional oldest_dl_harq_candidate; for (unsigned i = 0; i != ue_cc->harqs.nof_dl_harqs(); ++i) { - const dl_harq_process& h = ue_cc->harqs.dl_harq(i); - if (h.has_pending_retx() and not h.last_alloc_params().is_fallback and - h.last_alloc_params().tb[0]->slice_id == slice_id) { - dl_harq_candidates.push_back(&h); + std::optional h = ue_cc->harqs.dl_harq(to_harq_id(i)); + if (h.has_value() and h->has_pending_retx() and not h->get_grant_params().is_fallback and + h->get_grant_params().slice_id == slice_id) { + if (not oldest_dl_harq_candidate.has_value() or oldest_dl_harq_candidate->uci_slot() > h->uci_slot()) { + oldest_dl_harq_candidate = h; + } } } - std::sort(dl_harq_candidates.begin(), - dl_harq_candidates.end(), - [](const dl_harq_process* lhs, const dl_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); // Calculate DL priority. - dl_retx_h = dl_harq_candidates.empty() ? nullptr : dl_harq_candidates.front(); - dl_newtx_h = ue_cc->harqs.find_empty_dl_harq(); - if (dl_retx_h != nullptr or (dl_newtx_h != nullptr and u.has_pending_dl_newtx_bytes())) { + dl_retx_h = oldest_dl_harq_candidate; + has_empty_dl_harq = ue_cc->harqs.has_empty_dl_harqs(); + if (dl_retx_h.has_value() or (has_empty_dl_harq and u.has_pending_dl_newtx_bytes())) { // NOTE: It does not matter whether it's a reTx or newTx since DL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. // [Implementation-defined] We consider only the SearchSpace defined in UE dedicated configuration. @@ -235,8 +233,8 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id std::optional mcs = ue_cc->link_adaptation_controller().calculate_dl_mcs(pdsch_cfg.mcs_table); if (not mcs.has_value()) { // CQI is either 0, or > 15. - dl_retx_h = nullptr; - dl_newtx_h = nullptr; + has_empty_dl_harq = false; + dl_retx_h = std::nullopt; return; } @@ -251,15 +249,15 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id } return; } - dl_newtx_h = nullptr; + has_empty_dl_harq = false; } void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid, ran_slice_id_t slice_id) { - ul_retx_h = nullptr; - ul_newtx_h = nullptr; + ul_retx_h.reset(); + has_empty_ul_harq = false; ul_prio = 0; sr_ind_received = false; const ue_cell* ue_cc = u.find_cell(cell_index); @@ -270,23 +268,21 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, "policy scheduler called for UE={} in fallback", ue_cc->ue_index); - static_vector ul_harq_candidates; - // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. + std::optional oldest_ul_harq_candidate; for (unsigned i = 0; i != ue_cc->harqs.nof_ul_harqs(); ++i) { - const ul_harq_process& h = ue_cc->harqs.ul_harq(i); - if (h.has_pending_retx() and h.last_tx_params().slice_id == slice_id) { - ul_harq_candidates.push_back(&h); + std::optional h = ue_cc->harqs.ul_harq(to_harq_id(i)); + if (h.has_value() and h->has_pending_retx() and h->get_grant_params().slice_id == slice_id) { + if (not oldest_ul_harq_candidate.has_value() or oldest_ul_harq_candidate->pusch_slot() > h->pusch_slot()) { + oldest_ul_harq_candidate = h; + } } } - std::sort(ul_harq_candidates.begin(), - ul_harq_candidates.end(), - [](const ul_harq_process* lhs, const ul_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); // Calculate UL priority. - ul_retx_h = ul_harq_candidates.empty() ? nullptr : ul_harq_candidates.front(); - ul_newtx_h = ue_cc->harqs.find_empty_ul_harq(); - sr_ind_received = u.has_pending_sr(); - if (ul_retx_h != nullptr or (ul_newtx_h != nullptr and u.pending_ul_newtx_bytes() > 0)) { + ul_retx_h = oldest_ul_harq_candidate; + has_empty_ul_harq = ue_cc->harqs.has_empty_ul_harqs(); + sr_ind_received = u.has_pending_sr(); + if (ul_retx_h.has_value() or (has_empty_ul_harq and u.pending_ul_newtx_bytes() > 0)) { // NOTE: It does not matter whether it's a reTx or newTx since UL priority is computed based on estimated // instantaneous achievable rate to the average throughput of the user. // [Implementation-defined] We consider only the SearchSpace defined in UE dedicated configuration. @@ -340,7 +336,7 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, } return; } - ul_newtx_h = nullptr; + has_empty_ul_harq = false; } void scheduler_time_pf::ue_ctxt::save_dl_alloc(uint32_t alloc_bytes) @@ -368,8 +364,8 @@ void scheduler_time_pf::ue_ctxt::save_ul_alloc(uint32_t alloc_bytes) bool scheduler_time_pf::ue_dl_prio_compare::operator()(const scheduler_time_pf::ue_ctxt* lhs, const scheduler_time_pf::ue_ctxt* rhs) const { - const bool is_lhs_retx = lhs->dl_retx_h != nullptr; - const bool is_rhs_retx = rhs->dl_retx_h != nullptr; + const bool is_lhs_retx = lhs->dl_retx_h.has_value(); + const bool is_rhs_retx = rhs->dl_retx_h.has_value(); // First, prioritize UEs with re-transmissions. // ReTx in one UE and not in other UE. @@ -383,8 +379,8 @@ bool scheduler_time_pf::ue_dl_prio_compare::operator()(const scheduler_time_pf:: bool scheduler_time_pf::ue_ul_prio_compare::operator()(const scheduler_time_pf::ue_ctxt* lhs, const scheduler_time_pf::ue_ctxt* rhs) const { - const bool is_lhs_retx = lhs->ul_retx_h != nullptr; - const bool is_rhs_retx = rhs->ul_retx_h != nullptr; + const bool is_lhs_retx = lhs->ul_retx_h.has_value(); + const bool is_rhs_retx = rhs->ul_retx_h.has_value(); // First, prioritize UEs with pending SR. // SR indication in one UE and not in other UE. if (lhs->sr_ind_received != rhs->sr_ind_received) { diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index c2ddd50fdb..c5fb263069 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -59,10 +59,10 @@ class scheduler_time_pf : public scheduler_policy /// UL priority value of the UE. double ul_prio = 0; - const dl_harq_process* dl_retx_h = nullptr; - const dl_harq_process* dl_newtx_h = nullptr; - const ul_harq_process* ul_retx_h = nullptr; - const ul_harq_process* ul_newtx_h = nullptr; + bool has_empty_dl_harq = false; + bool has_empty_ul_harq = false; + std::optional dl_retx_h; + std::optional ul_retx_h; /// Flag indicating whether SR indication from the UE is received or not. bool sr_ind_received = false; @@ -113,7 +113,7 @@ class scheduler_time_pf : public scheduler_policy // Adapter of the priority_queue push method to avoid adding candidates with skip priority level. void push(ue_ctxt* elem) { - if (elem->dl_retx_h == nullptr and elem->dl_newtx_h == nullptr) { + if (not elem->dl_retx_h.has_value() and not elem->has_empty_dl_harq) { return; } base_type::push(elem); @@ -138,7 +138,7 @@ class scheduler_time_pf : public scheduler_policy // Adapter of the priority_queue push method to avoid adding candidates with skip priority level. void push(ue_ctxt* elem) { - if (elem->ul_retx_h == nullptr and elem->ul_newtx_h == nullptr) { + if (not elem->ul_retx_h.has_value() and not elem->has_empty_ul_harq) { return; } base_type::push(elem); diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 7cc0762731..170f711779 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -128,107 +128,107 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& return (std::min(bwp_crb_limits.length(), slice_max_rbs) / nof_ues_to_be_scheduled_per_slot); } -/// \brief Fetches list of DL HARQ candidates to schedule. -static static_vector get_ue_dl_harq_candidates(const slice_ue& ue_ref, - ue_cell_index_t cell_index, - bool is_retx, - ran_slice_id_t slice_id, - srslog::basic_logger& logger) +static bool can_allocate_dl_newtx(const slice_ue& ue_ref, ue_cell_index_t cell_index, srslog::basic_logger& logger) { - static_vector dl_harq_candidates; + // If there are no pending new Tx bytes, return. + if (not ue_ref.has_pending_dl_newtx_bytes()) { + return false; + } const ue_cell& ue_cc = ue_ref.get_cell(cell_index); - if (is_retx) { - // Create list of DL HARQ processes with pending retx, sorted from oldest to newest. - for (unsigned i = 0; i != ue_cc.harqs.nof_dl_harqs(); ++i) { - const dl_harq_process& h = ue_cc.harqs.dl_harq(i); - if (h.has_pending_retx() and h.last_alloc_params().tb[0]->slice_id == slice_id) { - dl_harq_candidates.push_back(&h); - } + if (not ue_cc.harqs.has_empty_dl_harqs()) { + // No empty HARQs are available. Log this occurrence. + if (ue_cc.harqs.find_pending_dl_retx().has_value()) { + // HARQs are waiting for a grant for a retransmission. + logger.debug("ue={} rnti={} PDSCH allocation skipped. Cause: No available HARQs for new transmissions.", + ue_cc.ue_index, + ue_cc.rnti()); + } else { + // All HARQs are waiting for their respective HARQ-ACK. This may be a symptom of a long RTT for the PDSCH + // and HARQ-ACK. + logger.warning( + "ue={} rnti={} PDSCH allocation skipped. Cause: All the HARQs are allocated and waiting for their " + "respective HARQ-ACK. Check if any HARQ-ACK went missing in the lower layers or is arriving too late to " + "the scheduler.", + ue_cc.ue_index, + ue_cc.rnti()); } - std::sort(dl_harq_candidates.begin(), - dl_harq_candidates.end(), - [](const dl_harq_process* lhs, const dl_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); - } else { - // If there are no pending new Tx bytes, return. - if (not ue_ref.has_pending_dl_newtx_bytes()) { - return dl_harq_candidates; + return false; + } + return true; +} + +/// \brief Fetches list of DL HARQ candidates to schedule. +static static_vector +get_ue_dl_harq_candidates(const slice_ue& ue_ref, ue_cell_index_t cell_index, ran_slice_id_t slice_id) +{ + static_vector dl_harq_candidates; + + const ue_cell& ue_cc = ue_ref.get_cell(cell_index); + // Create list of DL HARQ processes with pending retx, sorted from oldest to newest. + for (unsigned i = 0; i != ue_cc.harqs.nof_dl_harqs(); ++i) { + std::optional h = ue_cc.harqs.dl_harq(to_harq_id(i)); + if (h.has_value() and h->has_pending_retx() and h->get_grant_params().slice_id == slice_id) { + dl_harq_candidates.push_back(*h); } + } + std::sort(dl_harq_candidates.begin(), + dl_harq_candidates.end(), + [](const dl_harq_process_handle& lhs, const dl_harq_process_handle& rhs) { + return lhs.uci_slot() < rhs.uci_slot(); + }); + + return dl_harq_candidates; +} - // Find empty HARQ. If any, add to the list. - const dl_harq_process* h = ue_cc.harqs.find_empty_dl_harq(); - if (h != nullptr) { - dl_harq_candidates.push_back(h); +static bool can_allocate_ul_newtx(const slice_ue& ue_ref, ue_cell_index_t cell_index, srslog::basic_logger& logger) +{ + // If there are no pending new Tx bytes, return. + if (ue_ref.pending_ul_newtx_bytes() == 0) { + return false; + } + + const ue_cell& ue_cc = ue_ref.get_cell(cell_index); + if (not ue_cc.harqs.has_empty_ul_harqs()) { + // No empty HARQs are available. Log this occurrence. + if (ue_cc.harqs.find_pending_ul_retx().has_value()) { + // HARQs are waiting for a grant for a retransmission. + logger.debug("ue={} rnti={} PUSCH allocation skipped. Cause: No available HARQs for new transmissions.", + ue_cc.ue_index, + ue_cc.rnti()); } else { - // No empty HARQs are available. Log this occurrence. - if (ue_cc.harqs.find_pending_dl_retx() != nullptr) { - // HARQs are waiting for a grant for a retransmission. - logger.debug("ue={} rnti={} PDSCH allocation skipped. Cause: No available HARQs for new transmissions.", + // All HARQs are waiting for their respective CRC. This may be a symptom of a slow PUSCH processing chain. + logger.warning("ue={} rnti={} PUSCH allocation skipped. Cause: All the UE HARQs are busy waiting for " + "their respective CRC result. Check if any CRC PDU went missing in the lower layers or is " + "arriving too late to the scheduler.", ue_cc.ue_index, ue_cc.rnti()); - } else { - // All HARQs are waiting for their respective HARQ-ACK. This may be a symptom of a long RTT for the PDSCH - // and HARQ-ACK. - logger.warning( - "ue={} rnti={} PDSCH allocation skipped. Cause: All the HARQs are allocated and waiting for their " - "respective HARQ-ACK. Check if any HARQ-ACK went missing in the lower layers or is arriving too late to " - "the scheduler.", - ue_cc.ue_index, - ue_cc.rnti()); - } } + return false; } - return dl_harq_candidates; + + return true; } /// \brief Fetches list of UL HARQ candidates to schedule. -static static_vector get_ue_ul_harq_candidates(const slice_ue& ue_ref, - ue_cell_index_t cell_index, - bool is_retx, - ran_slice_id_t slice_id, - srslog::basic_logger& logger) +static static_vector +get_ue_ul_harq_candidates(const slice_ue& ue_ref, ue_cell_index_t cell_index, ran_slice_id_t slice_id) { - static_vector ul_harq_candidates; + static_vector ul_harq_candidates; const ue_cell& ue_cc = ue_ref.get_cell(cell_index); - if (is_retx) { - // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. - for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { - const ul_harq_process& h = ue_cc.harqs.ul_harq(i); - if (h.has_pending_retx() and h.last_tx_params().slice_id == slice_id) { - ul_harq_candidates.push_back(&h); - } - } - std::sort(ul_harq_candidates.begin(), - ul_harq_candidates.end(), - [](const ul_harq_process* lhs, const ul_harq_process* rhs) { return lhs->slot_ack() < rhs->slot_ack(); }); - } else { - // If there are no pending new Tx bytes, return. - if (ue_ref.pending_ul_newtx_bytes() == 0) { - return ul_harq_candidates; - } - - // Find empty HARQ. If any, add to the list. - const ul_harq_process* h = ue_cc.harqs.find_empty_ul_harq(); - if (h != nullptr) { - ul_harq_candidates.push_back(h); - } else { - // No empty HARQs are available. Log this occurrence. - if (ue_cc.harqs.find_pending_ul_retx() != nullptr) { - // HARQs are waiting for a grant for a retransmission. - logger.debug("ue={} rnti={} PUSCH allocation skipped. Cause: No available HARQs for new transmissions.", - ue_cc.ue_index, - ue_cc.rnti()); - } else { - // All HARQs are waiting for their respective CRC. This may be a symptom of a slow PUSCH processing chain. - logger.warning("ue={} rnti={} PUSCH allocation skipped. Cause: All the UE HARQs are busy waiting for " - "their respective CRC result. Check if any CRC PDU went missing in the lower layers or is " - "arriving too late to the scheduler.", - ue_cc.ue_index, - ue_cc.rnti()); - } + // Create list of UL HARQ processes with pending retx, sorted from oldest to newest. + for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { + std::optional h = ue_cc.harqs.ul_harq(to_harq_id(i)); + if (h.has_value() and h->has_pending_retx() and h->get_grant_params().slice_id == slice_id) { + ul_harq_candidates.push_back(*h); } } + std::sort(ul_harq_candidates.begin(), + ul_harq_candidates.end(), + [](const ul_harq_process_handle& lhs, const ul_harq_process_handle& rhs) { + return lhs.pusch_slot() < rhs.pusch_slot(); + }); return ul_harq_candidates; } @@ -298,20 +298,21 @@ static alloc_result alloc_dl_ue(const slice_ue& u, return {alloc_status::skip_ue}; } - // Get DL HARQ candidates. - const auto harq_candidates = get_ue_dl_harq_candidates(u, to_ue_cell_index(i), is_retx, slice_id, logger); - if (harq_candidates.empty()) { - // The conditions for a new PDSCH allocation for this UE were not met (e.g. lack of available HARQs). - continue; - } - - // Iterate through allocation parameter candidates. - for (const dl_harq_process* h_dl : harq_candidates) { - ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl->id}; - if (not is_retx) { - grant.recommended_nof_bytes = u.pending_dl_newtx_bytes(); - grant.max_nof_rbs = dl_new_tx_max_nof_rbs_per_ue_per_slot; + if (is_retx) { + // Get DL HARQ candidates. + const auto harq_candidates = get_ue_dl_harq_candidates(u, to_ue_cell_index(i), slice_id); + // Iterate through allocation parameter candidates. + for (dl_harq_process_handle h_dl : harq_candidates) { + ue_pdsch_grant grant{&u, ue_cc.cell_index, h_dl.id()}; + const alloc_result result = pdsch_alloc.allocate_dl_grant(grant); + // If the allocation failed due to invalid parameters, we continue iteration. + if (result.status != alloc_status::invalid_params) { + return result; + } } + } else if (can_allocate_dl_newtx(u, to_ue_cell_index(i), logger)) { + ue_pdsch_grant grant{ + &u, ue_cc.cell_index, INVALID_HARQ_ID, u.pending_dl_newtx_bytes(), dl_new_tx_max_nof_rbs_per_ue_per_slot}; const alloc_result result = pdsch_alloc.allocate_dl_grant(grant); // If the allocation failed due to invalid parameters, we continue iteration. if (result.status != alloc_status::invalid_params) { @@ -349,20 +350,25 @@ static alloc_result alloc_ul_ue(const slice_ue& u, "policy scheduler called for UE={} in fallback", ue_cc.ue_index); - // Get UL HARQ candidates. - const auto harq_candidates = get_ue_ul_harq_candidates(u, to_ue_cell_index(i), is_retx, slice_id, logger); - if (harq_candidates.empty()) { - // The conditions for a new PUSCH allocation for this UE were not met (e.g. lack of available HARQs). - continue; - } - - // Iterate through allocation parameter candidates. - for (const ul_harq_process* h_ul : harq_candidates) { - ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul->id}; - if (not is_retx) { - grant.recommended_nof_bytes = pending_newtx_bytes; - grant.max_nof_rbs = ul_new_tx_max_nof_rbs_per_ue_per_slot; + if (is_retx) { + // Get UL HARQ candidates. + const auto harq_candidates = get_ue_ul_harq_candidates(u, to_ue_cell_index(i), slice_id); + if (harq_candidates.empty()) { + // The conditions for a new PUSCH allocation for this UE were not met (e.g. lack of available HARQs). + continue; + } + // Iterate through allocation parameter candidates. + for (ul_harq_process_handle h_ul : harq_candidates) { + ue_pusch_grant grant{&u, ue_cc.cell_index, h_ul.id()}; + const alloc_result result = pusch_alloc.allocate_ul_grant(grant); + // If the allocation failed due to invalid parameters, we continue iteration. + if (result.status != alloc_status::invalid_params) { + return result; + } } + } else if (can_allocate_ul_newtx(u, to_ue_cell_index(i), logger)) { + ue_pusch_grant grant{ + &u, ue_cc.cell_index, INVALID_HARQ_ID, pending_newtx_bytes, ul_new_tx_max_nof_rbs_per_ue_per_slot}; const alloc_result result = pusch_alloc.allocate_ul_grant(grant); // If the allocation failed due to invalid parameters, we continue iteration. if (result.status != alloc_status::invalid_params) { diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index debcb842cd..11eab4ffca 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -118,17 +118,17 @@ void slice_scheduler::reconf_ue(du_ue_index_t ue_idx) // Check if any UE HARQs need to be cancelled in case the UE got removed from the respective slice. ue_cell& ue_cell = *u->find_cell(cell_cfg.cell_index); for (unsigned i = 0; i != ue_cell.harqs.nof_dl_harqs(); ++i) { - dl_harq_process& h_dl = ue_cell.harqs.dl_harq(to_harq_id(i)); - if (h_dl.has_pending_retx() and h_dl.last_alloc_params().tb[0]->slice_id.has_value() and - not slices[h_dl.last_alloc_params().tb[0]->slice_id->value()].inst.contains(ue_idx)) { - h_dl.cancel_harq_retxs(0); + std::optional h_dl = ue_cell.harqs.dl_harq(to_harq_id(i)); + if (h_dl.has_value() and h_dl->get_grant_params().slice_id.has_value() and + not slices[h_dl->get_grant_params().slice_id->value()].inst.contains(ue_idx)) { + h_dl->cancel_retxs(); } } for (unsigned i = 0; i != ue_cell.harqs.nof_ul_harqs(); ++i) { - ul_harq_process& h_ul = ue_cell.harqs.ul_harq(to_harq_id(i)); - if (h_ul.has_pending_retx() and h_ul.last_tx_params().slice_id.has_value() and - not slices[h_ul.last_tx_params().slice_id->value()].inst.contains(ue_idx)) { - h_ul.cancel_harq_retxs(); + std::optional h_ul = ue_cell.harqs.ul_harq(to_harq_id(i)); + if (h_ul.has_value() and h_ul->get_grant_params().slice_id.has_value() and + not slices[h_ul->get_grant_params().slice_id->value()].inst.contains(ue_idx)) { + h_ul->cancel_retxs(); } } } diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index 17a88ed515..a83dbc49d4 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -82,9 +82,9 @@ unsigned slice_ue::pending_ul_newtx_bytes() const } unsigned harq_bytes = 0; for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { - const ul_harq_process& h_ul = ue_cc.harqs.ul_harq(i); - if (not h_ul.empty()) { - harq_bytes += h_ul.last_tx_params().tbs_bytes; + std::optional h_ul = ue_cc.harqs.ul_harq(to_harq_id(i)); + if (h_ul.has_value()) { + harq_bytes += h_ul->get_grant_params().tbs_bytes; } } harq_bytes += ue_cc.harqs.ntn_get_tbs_pending_crcs(); diff --git a/lib/scheduler/support/dci_builder.cpp b/lib/scheduler/support/dci_builder.cpp index 72254c5ee1..c154616fd2 100644 --- a/lib/scheduler/support/dci_builder.cpp +++ b/lib/scheduler/support/dci_builder.cpp @@ -9,7 +9,6 @@ #include "dci_builder.h" #include "../cell/cell_harq_manager.h" -#include "../ue_scheduling/harq_process.h" #include "srsran/adt/optional.h" #include "srsran/ran/pdcch/dci_packing.h" #include "srsran/ran/pdcch/search_space.h" @@ -111,18 +110,16 @@ void srsran::build_dci_f1_0_ra_rnti(dci_dl_info& dci, ra_dci.tb_scaling = 0; // TODO. } -void srsran::build_dci_f1_0_tc_rnti(dci_dl_info& dci, - const bwp_downlink_common& init_dl_bwp, - crb_interval crbs, - unsigned time_resource, - unsigned k1, - unsigned pucch_res_indicator, - sch_mcs_index mcs_index, - uint8_t rv, - const dl_harq_process& h_dl) +void srsran::build_dci_f1_0_tc_rnti(dci_dl_info& dci, + const bwp_downlink_common& init_dl_bwp, + crb_interval crbs, + unsigned time_resource, + unsigned k1, + unsigned pucch_res_indicator, + sch_mcs_index mcs_index, + uint8_t rv, + const dl_harq_process_handle& h_dl) { - static constexpr unsigned tb_idx = 0; - dci.type = dci_dl_rnti_config_type::tc_rnti_f1_0; dci.tc_rnti_f1_0 = {}; dci_1_0_tc_rnti_configuration& f1_0 = dci.tc_rnti_f1_0; @@ -147,22 +144,22 @@ void srsran::build_dci_f1_0_tc_rnti(dci_dl_info& dci, f1_0.modulation_coding_scheme = mcs_index.to_uint(); // HARQ params. - f1_0.harq_process_number = h_dl.id; - f1_0.new_data_indicator = h_dl.tb(tb_idx).ndi; + f1_0.harq_process_number = h_dl.id(); + f1_0.new_data_indicator = h_dl.ndi(); f1_0.redundancy_version = rv; } -void srsran::build_dci_f1_0_c_rnti(dci_dl_info& dci, - const search_space_info& ss_info, - const bwp_downlink_common& init_dl_bwp, - crb_interval crbs, - unsigned time_resource, - unsigned k1, - unsigned pucch_res_indicator, - unsigned dai, - sch_mcs_index mcs_index, - uint8_t rv, - const dl_harq_process& h_dl) +void srsran::build_dci_f1_0_c_rnti(dci_dl_info& dci, + const search_space_info& ss_info, + const bwp_downlink_common& init_dl_bwp, + crb_interval crbs, + unsigned time_resource, + unsigned k1, + unsigned pucch_res_indicator, + unsigned dai, + sch_mcs_index mcs_index, + uint8_t rv, + const dl_harq_process_handle& h_dl) { const coreset_configuration& cs_cfg = *ss_info.coreset; const bwp_downlink_common& active_dl_bwp_cmn = *ss_info.bwp->dl_common; @@ -205,23 +202,23 @@ void srsran::build_dci_f1_0_c_rnti(dci_dl_info& dci, f1_0.modulation_coding_scheme = mcs_index.to_uint(); // HARQ params. - f1_0.harq_process_number = h_dl.id; - f1_0.new_data_indicator = h_dl.tb(0).ndi; + f1_0.harq_process_number = h_dl.id(); + f1_0.new_data_indicator = h_dl.ndi(); f1_0.redundancy_version = rv; } -void srsran::build_dci_f1_1_c_rnti(dci_dl_info& dci, - const ue_cell_configuration& ue_cell_cfg, - search_space_id ss_id, - prb_interval prbs, - unsigned time_resource, - unsigned k1, - unsigned pucch_res_indicator, - unsigned dai, - sch_mcs_index tb1_mcs_index, - uint8_t rv, - const dl_harq_process& h_dl, - unsigned nof_layers) +void srsran::build_dci_f1_1_c_rnti(dci_dl_info& dci, + const ue_cell_configuration& ue_cell_cfg, + search_space_id ss_id, + prb_interval prbs, + unsigned time_resource, + unsigned k1, + unsigned pucch_res_indicator, + unsigned dai, + sch_mcs_index tb1_mcs_index, + uint8_t rv, + const dl_harq_process_handle& h_dl, + unsigned nof_layers) { const search_space_info& ss_info = ue_cell_cfg.search_space(ss_id); srsran_assert(not ss_info.cfg->is_common_search_space(), "SearchSpace must be of type UE-Specific SearchSpace"); @@ -282,8 +279,8 @@ void srsran::build_dci_f1_1_c_rnti(dci_dl_info& dci, f1_1.tb1_modulation_coding_scheme = tb1_mcs_index.to_uint(); // HARQ params. - f1_1.harq_process_number = h_dl.id; - f1_1.tb1_new_data_indicator = h_dl.tb(0).ndi; + f1_1.harq_process_number = h_dl.id(); + f1_1.tb1_new_data_indicator = h_dl.ndi(); f1_1.tb1_redundancy_version = rv; } @@ -329,14 +326,14 @@ void srsran::build_dci_f0_0_tc_rnti(dci_ul_info& dci, f0_0.redundancy_version = rv; } -void srsran::build_dci_f0_0_c_rnti(dci_ul_info& dci, - const search_space_info& ss_info, - const bwp_uplink_common& init_ul_bwp, - const crb_interval& crbs, - unsigned time_resource, - sch_mcs_index mcs_index, - uint8_t rv, - const ul_harq_process& h_ul) +void srsran::build_dci_f0_0_c_rnti(dci_ul_info& dci, + const search_space_info& ss_info, + const bwp_uplink_common& init_ul_bwp, + const crb_interval& crbs, + unsigned time_resource, + sch_mcs_index mcs_index, + uint8_t rv, + const ul_harq_process_handle& h_ul) { const bwp_configuration& active_ul_bwp = ss_info.bwp->ul_common->generic_params; @@ -370,21 +367,21 @@ void srsran::build_dci_f0_0_c_rnti(dci_ul_info& dci, f0_0.modulation_coding_scheme = mcs_index.to_uint(); // HARQ params. - f0_0.harq_process_number = h_ul.id; - f0_0.new_data_indicator = h_ul.tb().ndi; + f0_0.harq_process_number = h_ul.id(); + f0_0.new_data_indicator = h_ul.ndi(); f0_0.redundancy_version = rv; } -void srsran::build_dci_f0_1_c_rnti(dci_ul_info& dci, - const ue_cell_configuration& ue_cell_cfg, - search_space_id ss_id, - const crb_interval& crbs, - unsigned time_resource, - sch_mcs_index mcs_index, - uint8_t rv, - const ul_harq_process& h_ul, - unsigned dai, - unsigned nof_layers) +void srsran::build_dci_f0_1_c_rnti(dci_ul_info& dci, + const ue_cell_configuration& ue_cell_cfg, + search_space_id ss_id, + const crb_interval& crbs, + unsigned time_resource, + sch_mcs_index mcs_index, + uint8_t rv, + const ul_harq_process_handle& h_ul, + unsigned dai, + unsigned nof_layers) { const search_space_info& ss_info = ue_cell_cfg.search_space(ss_id); srsran_assert(not ss_info.cfg->is_common_search_space(), "SearchSpace must be of type UE-Specific SearchSpace"); @@ -417,8 +414,8 @@ void srsran::build_dci_f0_1_c_rnti(dci_ul_info& dci, f0_1.modulation_coding_scheme = mcs_index.to_uint(); // HARQ params. - f0_1.harq_process_number = h_ul.id; - f0_1.new_data_indicator = h_ul.tb().ndi; + f0_1.harq_process_number = h_ul.id(); + f0_1.new_data_indicator = h_ul.ndi(); f0_1.redundancy_version = rv; // TODO: Set values for - diff --git a/lib/scheduler/support/dci_builder.h b/lib/scheduler/support/dci_builder.h index 4216e9ce75..d3f33f4ad6 100644 --- a/lib/scheduler/support/dci_builder.h +++ b/lib/scheduler/support/dci_builder.h @@ -17,8 +17,8 @@ namespace srsran { -class dl_harq_process; -class ul_harq_process; +class dl_harq_process_handle; +class ul_harq_process_handle; /// Builds DCI f1_0 for SI-RNTI used in SIBs. void build_dci_f1_0_si_rnti(dci_dl_info& dci, @@ -43,42 +43,42 @@ void build_dci_f1_0_ra_rnti(dci_dl_info& dci, sch_mcs_index mcs_index); /// Builds DCI f1_0 for TC-RNTI, used for instance in Msg4. -void build_dci_f1_0_tc_rnti(dci_dl_info& dci, - const bwp_downlink_common& init_dl_bwp, - crb_interval crbs, - unsigned time_resource, - unsigned k1, - unsigned pucch_res_indicator, - sch_mcs_index mcs_index, - uint8_t rv, - const dl_harq_process& h_dl); +void build_dci_f1_0_tc_rnti(dci_dl_info& dci, + const bwp_downlink_common& init_dl_bwp, + crb_interval crbs, + unsigned time_resource, + unsigned k1, + unsigned pucch_res_indicator, + sch_mcs_index mcs_index, + uint8_t rv, + const dl_harq_process_handle& h_dl); /// Builds DCI f1_0 for C-RNTI. -void build_dci_f1_0_c_rnti(dci_dl_info& dci, - const search_space_info& ss_info, - const bwp_downlink_common& init_dl_bwp, - crb_interval crbs, - unsigned time_resource, - unsigned k1, - unsigned pucch_res_indicator, - unsigned dai, - sch_mcs_index mcs_index, - uint8_t rv, - const dl_harq_process& h_dl); +void build_dci_f1_0_c_rnti(dci_dl_info& dci, + const search_space_info& ss_info, + const bwp_downlink_common& init_dl_bwp, + crb_interval crbs, + unsigned time_resource, + unsigned k1, + unsigned pucch_res_indicator, + unsigned dai, + sch_mcs_index mcs_index, + uint8_t rv, + const dl_harq_process_handle& h_dl); /// Builds DCI f1_1 for C-RNTI. -void build_dci_f1_1_c_rnti(dci_dl_info& dci, - const ue_cell_configuration& ue_cell_cfg, - search_space_id ss_id, - prb_interval prbs, - unsigned time_resource, - unsigned k1, - unsigned pucch_res_indicator, - unsigned dai, - sch_mcs_index tb1_mcs_index, - uint8_t rv, - const dl_harq_process& h_dl, - unsigned nof_layers); +void build_dci_f1_1_c_rnti(dci_dl_info& dci, + const ue_cell_configuration& ue_cell_cfg, + search_space_id ss_id, + prb_interval prbs, + unsigned time_resource, + unsigned k1, + unsigned pucch_res_indicator, + unsigned dai, + sch_mcs_index tb1_mcs_index, + uint8_t rv, + const dl_harq_process_handle& h_dl, + unsigned nof_layers); /// Builds DCI f0_0 for TC-RNTI, used in Msg3 retxs. void build_dci_f0_0_tc_rnti(dci_ul_info& dci, @@ -90,25 +90,25 @@ void build_dci_f0_0_tc_rnti(dci_ul_info& dci, uint8_t rv); /// Builds DCI f0_0 for C-RNTI. -void build_dci_f0_0_c_rnti(dci_ul_info& dci, - const search_space_info& ss_info, - const bwp_uplink_common& init_ul_bwp, - const crb_interval& crbs, - unsigned time_resource, - sch_mcs_index mcs_index, - uint8_t rv, - const ul_harq_process& h_ul); +void build_dci_f0_0_c_rnti(dci_ul_info& dci, + const search_space_info& ss_info, + const bwp_uplink_common& init_ul_bwp, + const crb_interval& crbs, + unsigned time_resource, + sch_mcs_index mcs_index, + uint8_t rv, + const ul_harq_process_handle& h_ul); /// Builds DCI f0_1 for C-RNTI. -void build_dci_f0_1_c_rnti(dci_ul_info& dci, - const ue_cell_configuration& ue_cell_cfg, - search_space_id ss_id, - const crb_interval& crbs, - unsigned time_resource, - sch_mcs_index mcs_index, - uint8_t rv, - const ul_harq_process& h_ul, - unsigned total_dai, - unsigned nof_layers); +void build_dci_f0_1_c_rnti(dci_ul_info& dci, + const ue_cell_configuration& ue_cell_cfg, + search_space_id ss_id, + const crb_interval& crbs, + unsigned time_resource, + sch_mcs_index mcs_index, + uint8_t rv, + const ul_harq_process_handle& h_ul, + unsigned total_dai, + unsigned nof_layers); } // namespace srsran diff --git a/lib/scheduler/support/sch_pdu_builder.cpp b/lib/scheduler/support/sch_pdu_builder.cpp index 8ae30c3096..1f81b13ef3 100644 --- a/lib/scheduler/support/sch_pdu_builder.cpp +++ b/lib/scheduler/support/sch_pdu_builder.cpp @@ -8,7 +8,6 @@ */ #include "sch_pdu_builder.h" -#include "../ue_scheduling/ue_channel_state_manager.h" #include "dmrs_helpers.h" #include "pdsch/pdsch_default_time_allocation.h" #include "srsran/adt/optional.h" @@ -16,8 +15,6 @@ #include "srsran/ran/csi_report/csi_report_on_pucch_helpers.h" #include "srsran/ran/csi_report/csi_report_on_pusch_helpers.h" #include "srsran/ran/csi_report/csi_report_pusch_size.h" -#include "srsran/ran/resource_allocation/resource_allocation_frequency.h" -#include "srsran/ran/sch/tbs_calculator.h" #include "srsran/scheduler/config/serving_cell_config.h" using namespace srsran; @@ -545,7 +542,7 @@ void srsran::build_pdsch_f1_1_c_rnti(pdsch_information& pdsch, search_space_id ss_id, const dci_1_1_configuration& dci_cfg, const crb_interval& crbs, - const dl_harq_process& h_dl, + bool is_new_data, const ue_channel_state_manager& cs_mgr) { const cell_configuration& cell_cfg = ue_cell_cfg.cell_cfg_common; @@ -575,7 +572,7 @@ void srsran::build_pdsch_f1_1_c_rnti(pdsch_information& pdsch, // TODO: Add second Codeword when supported. // One Codeword. pdsch_codeword& cw = pdsch.codewords.emplace_back(); - cw.new_data = h_dl.tb(0).nof_retxs == 0; + cw.new_data = is_new_data; cw.rv_index = dci_cfg.tb1_redundancy_version; cw.mcs_index = dci_cfg.tb1_modulation_coding_scheme; cw.mcs_table = pdsch_cfg.mcs_table; @@ -699,7 +696,7 @@ void srsran::build_pusch_f0_1_c_rnti(pusch_information& pusch, search_space_id ss_id, const dci_0_1_configuration& dci_cfg, const crb_interval& crbs, - const ul_harq_process& h_ul) + bool is_new_data) { const cell_configuration& cell_cfg = ue_cell_cfg.cell_cfg_common; const search_space_info& ss_info = ue_cell_cfg.search_space(ss_id); @@ -759,5 +756,5 @@ void srsran::build_pusch_f0_1_c_rnti(pusch_information& pusch, // HARQ. pusch.rv_index = dci_cfg.redundancy_version; pusch.harq_id = dci_cfg.harq_process_number; - pusch.new_data = h_ul.tb().nof_retxs == 0; + pusch.new_data = is_new_data; } diff --git a/lib/scheduler/support/sch_pdu_builder.h b/lib/scheduler/support/sch_pdu_builder.h index 85bb881af9..5b6f09d1d7 100644 --- a/lib/scheduler/support/sch_pdu_builder.h +++ b/lib/scheduler/support/sch_pdu_builder.h @@ -11,7 +11,6 @@ #include "../config/cell_configuration.h" #include "../config/ue_configuration.h" -#include "../ue_scheduling/harq_process.h" #include "../ue_scheduling/ue_channel_state_manager.h" #include "mcs_tbs_calculator.h" #include "srsran/scheduler/harq_id.h" @@ -146,7 +145,7 @@ void build_pdsch_f1_1_c_rnti(pdsch_information& pdsch, search_space_id ss_id, const dci_1_1_configuration& dci_cfg, const crb_interval& crbs, - const dl_harq_process& h_dl, + bool is_new_data, const ue_channel_state_manager& cs_mgr); /// \brief Builds PUSCH PDU for DCI format 0_0, scrambled by TC-RNTI. @@ -179,6 +178,6 @@ void build_pusch_f0_1_c_rnti(pusch_information& pusch, search_space_id ss_id, const dci_0_1_configuration& dci_cfg, const crb_interval& crbs, - const ul_harq_process& h_ul); + bool is_new_data); } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue.cpp b/lib/scheduler/ue_scheduling/ue.cpp index f3c38ed967..84cf7b0ced 100644 --- a/lib/scheduler/ue_scheduling/ue.cpp +++ b/lib/scheduler/ue_scheduling/ue.cpp @@ -21,7 +21,7 @@ ue::ue(const ue_creation_command& cmd) : expert_cfg(cmd.cfg.expert_cfg()), cell_cfg_common(cmd.cfg.pcell_cfg().cell_cfg_common), ue_ded_cfg(&cmd.cfg), - harq_timeout_notif(cmd.harq_timeout_notifier, ue_index), + pcell_harq_pool(cmd.pcell_harq_pool), logger(srslog::fetch_basic_logger("SCHED")), ta_mgr(expert_cfg, cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs, &dl_lc_ch_mgr) { @@ -39,9 +39,6 @@ void ue::slot_indication(slot_point sl_tx) { for (unsigned i = 0; i != ue_du_cells.size(); ++i) { if (ue_du_cells[i] != nullptr) { - // Clear old HARQs. - ue_du_cells[i]->harqs.slot_indication(sl_tx); - // [Implementation-defined] // Clear last PxSCH allocated slot if gap to current \c sl_tx is too large. This is done in order to circumvent // the ambiguity caused by the slot_point wrap around while scheduling next PxSCHs. e.g. last PxSCH allocated @@ -101,8 +98,7 @@ void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) du_cell_index_t cell_index = ue_ded_cfg->ue_cell_cfg(to_ue_cell_index(ue_cell_index)).cell_cfg_common.cell_index; auto& ue_cell_inst = ue_du_cells[cell_index]; if (ue_cell_inst == nullptr) { - ue_cell_inst = - std::make_unique(ue_index, crnti, ue_ded_cfg->ue_cell_cfg(cell_index), harq_timeout_notif); + ue_cell_inst = std::make_unique(ue_index, crnti, ue_ded_cfg->ue_cell_cfg(cell_index), pcell_harq_pool); if (ue_cell_index >= ue_cells.size()) { ue_cells.resize(ue_cell_index + 1); } @@ -153,9 +149,9 @@ unsigned ue::pending_ul_newtx_bytes() const } unsigned harq_bytes = 0; for (unsigned i = 0; i != ue_cc->harqs.nof_ul_harqs(); ++i) { - const ul_harq_process& h_ul = ue_cc->harqs.ul_harq(i); - if (not h_ul.empty()) { - harq_bytes += h_ul.last_tx_params().tbs_bytes; + std::optional h_ul = ue_cc->harqs.ul_harq(to_harq_id(i)); + if (h_ul.has_value()) { + harq_bytes += h_ul->get_grant_params().tbs_bytes; } } harq_bytes += ue_cc->harqs.ntn_get_tbs_pending_crcs(); diff --git a/lib/scheduler/ue_scheduling/ue.h b/lib/scheduler/ue_scheduling/ue.h index 19de4ada24..34674dfebc 100644 --- a/lib/scheduler/ue_scheduling/ue.h +++ b/lib/scheduler/ue_scheduling/ue.h @@ -23,7 +23,7 @@ namespace srsran { struct ue_creation_command { const ue_configuration& cfg; bool starts_in_fallback; - harq_timeout_handler& harq_timeout_notifier; + cell_harq_manager& pcell_harq_pool; }; /// Parameters used to reconfigure a UE. @@ -185,19 +185,14 @@ class ue unsigned build_dl_fallback_transport_block_info(dl_msg_tb_info& tb_info, unsigned tb_size_bytes); private: - /// Expert config parameters used for UE scheduler. + // Expert config parameters used for UE scheduler. const scheduler_ue_expert_config& expert_cfg; - - /// Cell configuration. This is common to all UEs within the same cell. + // Cell configuration. This is common to all UEs within the same cell. const cell_configuration& cell_cfg_common; - - /// Dedicated configuration for the UE. + // Dedicated configuration for the UE. const ue_configuration* ue_ded_cfg = nullptr; - - /// Notifier used by HARQ processes to signal timeouts due to undetected HARQ ACKs/CRCs. - ue_harq_timeout_notifier harq_timeout_notif; - - srslog::basic_logger& logger; + cell_harq_manager& pcell_harq_pool; + srslog::basic_logger& logger; /// List of UE cells indexed by \c du_cell_index_t. If an element is null, it means that the DU cell is not /// configured to be used by the UE. diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index d3a928e172..940f6e1788 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -29,16 +29,15 @@ constexpr unsigned DEFAULT_NOF_DL_HARQS = 8; ue_cell::ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, - ue_harq_timeout_notifier harq_timeout_notifier) : + cell_harq_manager& cell_harq_pool) : ue_index(ue_index_), cell_index(ue_cell_cfg_.cell_cfg_common.cell_index), - harqs(crnti_val, - ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg.has_value() - ? (unsigned)ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg->nof_harq_proc - : DEFAULT_NOF_DL_HARQS, - NOF_UL_HARQS, - harq_timeout_notifier, - ue_cell_cfg_.cell_cfg_common.ntn_cs_koffset), + harqs(cell_harq_pool.add_ue(ue_index, + crnti_val, + ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg.has_value() + ? (unsigned)ue_cell_cfg_.cfg_dedicated().pdsch_serv_cell_cfg->nof_harq_proc + : DEFAULT_NOF_DL_HARQS, + NOF_UL_HARQS)), crnti_(crnti_val), cell_cfg(ue_cell_cfg_.cell_cfg_common), ue_cfg(&ue_cell_cfg_), @@ -55,10 +54,16 @@ void ue_cell::deactivate() // Note: We assume that when this function is called, any RRC container (e.g. containing RRC Release) was already // transmitted+ACKed (ensured by F1AP). for (unsigned hid = 0; hid != harqs.nof_dl_harqs(); ++hid) { - harqs.dl_harq(hid).cancel_harq_retxs(0); + std::optional h_dl = harqs.dl_harq(to_harq_id(hid)); + if (h_dl.has_value()) { + h_dl->cancel_retxs(); + } } for (unsigned hid = 0; hid != harqs.nof_ul_harqs(); ++hid) { - harqs.ul_harq(hid).cancel_harq_retxs(); + std::optional h_ul = harqs.ul_harq(to_harq_id(hid)); + if (h_ul.has_value()) { + h_ul->cancel_retxs(); + } } active = false; } @@ -77,15 +82,15 @@ void ue_cell::set_fallback_state(bool set_fallback) // Cancel pending HARQs retxs of different state. for (unsigned i = 0; i != harqs.nof_dl_harqs(); ++i) { - dl_harq_process& h = harqs.dl_harq(to_harq_id(i)); - if (not h.empty() and h.last_alloc_params().is_fallback != in_fallback_mode) { - h.cancel_harq_retxs(0); + std::optional h_dl = harqs.dl_harq(to_harq_id(i)); + if (h_dl.has_value() and h_dl.value().get_grant_params().is_fallback != in_fallback_mode) { + h_dl.value().cancel_retxs(); } } for (unsigned i = 0; i != harqs.nof_ul_harqs(); ++i) { - ul_harq_process& h = harqs.ul_harq(to_harq_id(i)); - if (not h.empty()) { - h.cancel_harq_retxs(); + std::optional h_ul = harqs.ul_harq(to_harq_id(i)); + if (h_ul.has_value()) { + h_ul->cancel_retxs(); } } @@ -97,16 +102,27 @@ std::optional ue_cell::handle_dl_ack_info(s unsigned harq_bit_idx, std::optional pucch_snr) { - std::optional result = - harqs.dl_ack_info(uci_slot, ack_value, harq_bit_idx, pucch_snr); + std::optional h_dl = harqs.find_dl_harq(uci_slot, harq_bit_idx); + if (not h_dl.has_value()) { + logger.warning("rnti={}: Discarding ACK info. Cause: DL HARQ for uci slot={} not found.", rnti(), uci_slot); + return std::nullopt; + } - if (result.has_value() and (result->update == dl_harq_process::status_update::acked or - result->update == dl_harq_process::status_update::nacked)) { + dl_harq_process_handle::status_update outcome = h_dl->dl_ack_info(ack_value, pucch_snr); + dl_harq_process::dl_ack_info_result result; + result.h_id = h_dl->id(); + result.tb.mcs_table = h_dl->get_grant_params().mcs_table; + result.tb.mcs = h_dl->get_grant_params().mcs; + result.tb.tbs_bytes = h_dl->get_grant_params().tbs_bytes; + result.tb.slice_id = h_dl->get_grant_params().slice_id; + result.tb.olla_mcs = h_dl->get_grant_params().olla_mcs; + result.update = (dl_harq_process::status_update)outcome; + + if (result.update == dl_harq_process::status_update::acked or + result.update == dl_harq_process::status_update::nacked) { // HARQ is not expecting more ACK bits. Consider the feedback in the link adaptation controller. - ue_mcs_calculator.handle_dl_ack_info(result->update == dl_harq_process::status_update::acked, - result->tb.mcs, - result->tb.mcs_table, - result->tb.olla_mcs); + ue_mcs_calculator.handle_dl_ack_info( + result.update == dl_harq_process::status_update::acked, result.tb.mcs, result.tb.mcs_table, result.tb.olla_mcs); } return result; @@ -215,18 +231,33 @@ grant_prbs_mcs ue_cell::required_ul_prbs(const pusch_time_domain_resource_alloca int ue_cell::handle_crc_pdu(slot_point pusch_slot, const ul_crc_pdu_indication& crc_pdu) { + // Find UL HARQ with matching PUSCH slot. + std::optional h_ul = harqs.ul_harq(crc_pdu.harq_id); + if (not h_ul.has_value()) { + logger.warning("rnti={} h_id={}: Discarding CRC. Cause: UL HARQ process is not active", rnti(), crc_pdu.harq_id); + return -1; + } + if (h_ul->pusch_slot() != pusch_slot) { + logger.warning( + "rnti={} h_id={}: Discarding CRC. Cause: UL HARQ process was expecting a CRC at a different slot ({}!={})", + rnti(), + crc_pdu.harq_id, + pusch_slot, + h_ul->pusch_slot()); + return -1; + } + // Update UL HARQ state. - int tbs = harqs.ul_crc_info(crc_pdu.harq_id, crc_pdu.tb_crc_success, pusch_slot); + int tbs = h_ul->ul_crc_info(crc_pdu.tb_crc_success); if (tbs >= 0) { // HARQ with matching ID and UCI slot was found. // Update link adaptation controller. - const ul_harq_process& h_ul = harqs.ul_harq(crc_pdu.harq_id); ue_mcs_calculator.handle_ul_crc_info(crc_pdu.tb_crc_success, - h_ul.last_tx_params().mcs, - h_ul.last_tx_params().mcs_table, - h_ul.last_tx_params().olla_mcs); + h_ul->get_grant_params().mcs, + h_ul->get_grant_params().mcs_table, + h_ul->get_grant_params().olla_mcs); // Update PUSCH KO count metrics. ue_metrics.consecutive_pusch_kos = (crc_pdu.tb_crc_success) ? 0 : ue_metrics.consecutive_pusch_kos + 1; @@ -473,23 +504,22 @@ void ue_cell::apply_link_adaptation_procedures(const csi_report_data& csi_report ? csi_report.ri->value() : channel_state.get_nof_dl_layers(); - static const uint8_t tb_index = 0; // Link adaptation for HARQs. // [Implementation-defined] If the drop in RI or CQI when compared to the RI or CQI at the time of new HARQ // transmission is above threshold then HARQ re-transmissions are cancelled. for (unsigned hid = 0; hid != harqs.nof_dl_harqs(); ++hid) { - dl_harq_process& h_dl = harqs.dl_harq(hid); - if (h_dl.empty()) { + std::optional h_dl = harqs.dl_harq(to_harq_id(hid)); + if (not h_dl.has_value()) { continue; } const bool is_ri_diff_above_threshold = expert_cfg.dl_harq_la_ri_drop_threshold != 0 and - recommended_dl_layers + expert_cfg.dl_harq_la_ri_drop_threshold <= h_dl.last_alloc_params().nof_layers; + recommended_dl_layers + expert_cfg.dl_harq_la_ri_drop_threshold <= h_dl->get_grant_params().nof_layers; const bool is_cqi_diff_above_threshold = expert_cfg.dl_harq_la_cqi_drop_threshold != 0 and - wideband_cqi.to_uint() + expert_cfg.dl_harq_la_cqi_drop_threshold <= h_dl.last_alloc_params().cqi.to_uint(); + wideband_cqi.to_uint() + expert_cfg.dl_harq_la_cqi_drop_threshold <= h_dl->get_grant_params().cqi.to_uint(); if (is_ri_diff_above_threshold or is_cqi_diff_above_threshold) { - h_dl.cancel_harq_retxs(tb_index); + h_dl->cancel_retxs(); } } } diff --git a/lib/scheduler/ue_scheduling/ue_cell.h b/lib/scheduler/ue_scheduling/ue_cell.h index ef030bd916..14c43ce0ad 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.h +++ b/lib/scheduler/ue_scheduling/ue_cell.h @@ -10,10 +10,11 @@ #pragma once +#include "../cell/cell_harq_manager.h" #include "../config/ue_configuration.h" #include "../support/bwp_helpers.h" #include "../support/sch_pdu_builder.h" -#include "harq_process.h" +#include "../ue_scheduling/harq_process.h" #include "ue_channel_state_manager.h" #include "ue_link_adaptation_controller.h" #include "srsran/ran/uci/uci_constants.h" @@ -44,12 +45,12 @@ class ue_cell ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, - ue_harq_timeout_notifier harq_timeout_notifier); + cell_harq_manager& cell_harq_pool); const du_ue_index_t ue_index; const du_cell_index_t cell_index; - harq_entity harqs; + unique_ue_harq_entity harqs; // Slot at which PDSCH was allocated in the past for this UE in this cell. slot_point last_pdsch_allocated_slot; @@ -87,15 +88,13 @@ class ue_cell unsigned pending_bytes, dci_ul_rnti_config_type dci_type) const; - uint8_t get_pdsch_rv(const dl_harq_process& h_dl) const + uint8_t get_pdsch_rv(unsigned nof_retxs) const { - return cell_cfg.expert_cfg.ue - .pdsch_rv_sequence[h_dl.tb(0).nof_retxs % cell_cfg.expert_cfg.ue.pdsch_rv_sequence.size()]; + return cell_cfg.expert_cfg.ue.pdsch_rv_sequence[nof_retxs % cell_cfg.expert_cfg.ue.pdsch_rv_sequence.size()]; } - uint8_t get_pusch_rv(const ul_harq_process& h_ul) const + uint8_t get_pusch_rv(unsigned nof_retxs) const { - return cell_cfg.expert_cfg.ue - .pusch_rv_sequence[h_ul.tb().nof_retxs % cell_cfg.expert_cfg.ue.pusch_rv_sequence.size()]; + return cell_cfg.expert_cfg.ue.pusch_rv_sequence[nof_retxs % cell_cfg.expert_cfg.ue.pusch_rv_sequence.size()]; } /// \brief Handle CRC PDU indication. diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index e86d5b3c57..aa65569800 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -80,11 +80,14 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra return {alloc_status::skip_ue}; } - const ue_cell_configuration& ue_cell_cfg = ue_cc->cfg(); - const cell_configuration& cell_cfg = ue_cell_cfg.cell_cfg_common; - const bwp_downlink_common& bwp_dl_cmn = *ue_cell_cfg.bwp(ue_cc->active_bwp_id()).dl_common; - dl_harq_process& h_dl = ue_cc->harqs.dl_harq(grant.h_id); - const bool is_retx = not h_dl.empty(); + const ue_cell_configuration& ue_cell_cfg = ue_cc->cfg(); + const cell_configuration& cell_cfg = ue_cell_cfg.cell_cfg_common; + const bwp_downlink_common& bwp_dl_cmn = *ue_cell_cfg.bwp(ue_cc->active_bwp_id()).dl_common; + const bool is_retx = grant.h_id != INVALID_HARQ_ID; + std::optional h_dl; + if (is_retx) { + h_dl = ue_cc->harqs.dl_harq(grant.h_id); + } // Fetch PDCCH resource grid allocator. cell_slot_resource_allocator& pdcch_alloc = get_res_alloc(grant.cell_index)[0]; @@ -198,8 +201,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra } grant_prbs_mcs mcs_prbs = - is_retx ? grant_prbs_mcs{h_dl.last_alloc_params().tb.front().value().mcs, - h_dl.last_alloc_params().rbs.type1().length()} + is_retx ? grant_prbs_mcs{h_dl->get_grant_params().mcs, h_dl->get_grant_params().rbs.type1().length()} : ue_cc->required_dl_prbs(pdsch_td_cfg, grant.recommended_nof_bytes.value(), dci_type); // Try to limit the grant PRBs. if (not is_retx) { @@ -242,13 +244,13 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra } // In case of Retx, the #CRBs need to stay the same. - if (is_retx and crbs.length() != h_dl.last_alloc_params().rbs.type1().length()) { + if (is_retx and crbs.length() != h_dl->get_grant_params().rbs.type1().length()) { logger.debug( "ue={} rnti={}: Failed to allocate PDSCH. Cause: No more RBs available at slot={} for h_id={} retransmission", u.ue_index, u.crnti, pdsch_alloc.slot, - h_dl.id); + h_dl->id()); return {alloc_status::skip_ue}; } @@ -256,7 +258,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra ue_cc->get_aggregation_level(ue_cc->link_adaptation_controller().get_effective_cqi(), ss_info, true); // In case of retx, ensure the RI does not change. const unsigned nof_dl_layers = - is_retx ? h_dl.last_alloc_params().nof_layers : ue_cc->channel_state_manager().get_nof_dl_layers(); + is_retx ? h_dl->get_grant_params().nof_layers : ue_cc->channel_state_manager().get_nof_dl_layers(); // Allocate PDCCH position. pdcch_dl_information* pdcch = get_pdcch_sched(grant.cell_index) @@ -348,8 +350,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra mcs_tbs_info = compute_dl_mcs_tbs(pdsch_cfg, adjusted_mcs, crbs.length(), contains_dc); } else { // It is a retx. - mcs_tbs_info.emplace( - sch_mcs_tbs{.mcs = h_dl.last_alloc_params().tb[0]->mcs, .tbs = h_dl.last_alloc_params().tb[0]->tbs_bytes}); + mcs_tbs_info.emplace(sch_mcs_tbs{.mcs = h_dl->get_grant_params().mcs, .tbs = h_dl->get_grant_params().tbs_bytes}); } // If there is not MCS-TBS info, it means no MCS exists such that the effective code rate is <= 0.95. @@ -367,21 +368,18 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra bool is_new_data = not is_retx; if (is_new_data) { // It is a new tx. - h_dl.new_tx(pdsch_alloc.slot, - k1, - expert_cfg.max_nof_harq_retxs, - uci.value().harq_bit_idx, - ue_cc->channel_state_manager().get_wideband_cqi(), - nof_dl_layers); + h_dl = ue_cc->harqs.alloc_dl_harq(pdsch_alloc.slot, k1, expert_cfg.max_nof_harq_retxs, uci.value().harq_bit_idx) + .value(); } else { // It is a retx. - h_dl.new_retx(pdsch_alloc.slot, k1, uci.value().harq_bit_idx); + bool result = h_dl->new_retx(pdsch_alloc.slot, k1, uci.value().harq_bit_idx); + srsran_assert(result, "Harq is in invalid state"); } // Fill DL PDCCH DCI PDU. // Number of possible Downlink Assignment Indexes {0, ..., 3} as per TS38.213 Section 9.1.3. static constexpr unsigned DAI_MOD = 4U; - uint8_t rv = ue_cc->get_pdsch_rv(h_dl); + uint8_t rv = ue_cc->get_pdsch_rv(h_dl->nof_retxs()); // For allocation on PUSCH, we use a PUCCH resource indicator set to 0, as it will get ignored by the UE. const unsigned pucch_res_indicator = uci.value().pucch_res_indicator.has_value() ? uci.value().pucch_res_indicator.value() : 0U; @@ -397,7 +395,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra uci.value().harq_bit_idx % DAI_MOD, mcs_tbs_info.value().mcs, rv, - h_dl); + *h_dl); break; case dci_dl_rnti_config_type::c_rnti_f1_1: build_dci_f1_1_c_rnti(pdcch->dci, @@ -410,7 +408,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra uci.value().harq_bit_idx % DAI_MOD, mcs_tbs_info.value().mcs, rv, - h_dl, + *h_dl, nof_dl_layers); break; default: @@ -422,7 +420,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra msg.context.ue_index = u.ue_index; msg.context.k1 = k1; msg.context.ss_id = ss_cfg.get_id(); - msg.context.nof_retxs = h_dl.tb(0).nof_retxs; + msg.context.nof_retxs = h_dl->nof_retxs(); msg.context.buffer_occupancy = 0; // We fill this value later, after the TB is built. if (is_new_data and ue_cc->link_adaptation_controller().is_dl_olla_enabled()) { msg.context.olla_offset = ue_cc->link_adaptation_controller().dl_cqi_offset(); @@ -448,7 +446,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra ss_cfg.get_id(), pdcch->dci.c_rnti_f1_1, crbs, - h_dl, + h_dl->nof_retxs() == 0, ue_cc->channel_state_manager()); break; default: @@ -456,13 +454,14 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra } // Save set PDCCH and PDSCH PDU parameters in HARQ process. - dl_harq_sched_context pdsch_sched_ctx; + dl_harq_alloc_context pdsch_sched_ctx; pdsch_sched_ctx.dci_cfg_type = pdcch->dci.type; if (is_new_data) { pdsch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_dl_mcs(msg.pdsch_cfg.codewords[0].mcs_table); pdsch_sched_ctx.slice_id = slice_id; } + pdsch_sched_ctx.cqi = ue_cc->channel_state_manager().get_wideband_cqi(); ue_cc->last_pdsch_allocated_slot = pdsch_alloc.slot; if (is_new_data) { @@ -474,9 +473,9 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra msg.context.buffer_occupancy = u.pending_dl_newtx_bytes(); } - h_dl.save_alloc_params(pdsch_sched_ctx, msg.pdsch_cfg); + h_dl->save_grant_params(pdsch_sched_ctx, msg.pdsch_cfg); - return {alloc_status::success, h_dl.last_alloc_params().tb[0]->tbs_bytes, crbs.length()}; + return {alloc_status::success, h_dl->get_grant_params().tbs_bytes, crbs.length()}; } // No candidates for PDSCH allocation. @@ -512,10 +511,10 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice return {alloc_status::skip_ue}; } - const ue_cell_configuration& ue_cell_cfg = ue_cc->cfg(); - const cell_configuration& cell_cfg = ue_cell_cfg.cell_cfg_common; - ul_harq_process& h_ul = ue_cc->harqs.ul_harq(grant.h_id); - const bool is_retx = not h_ul.empty(); + const ue_cell_configuration& ue_cell_cfg = ue_cc->cfg(); + const cell_configuration& cell_cfg = ue_cell_cfg.cell_cfg_common; + std::optional h_ul = ue_cc->harqs.ul_harq(grant.h_id); + const bool is_retx = h_ul.has_value(); // Fetch PDCCH resource grid allocators. cell_slot_resource_allocator& pdcch_alloc = get_res_alloc(grant.cell_index)[pdcch_delay_in_slots]; @@ -642,7 +641,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice // If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for // the first transmission. const bool sym_length_match_prev_grant_for_retx = - is_retx ? pusch_td_cfg.symbols.length() == h_ul.last_tx_params().nof_symbols : true; + is_retx ? pusch_td_cfg.symbols.length() == h_ul->get_grant_params().nof_symbols : true; if (pusch_td_cfg.symbols.start() < start_ul_symbols or pusch_td_cfg.symbols.stop() > (start_ul_symbols + cell_cfg.get_nof_ul_symbol_per_slot(pusch_alloc.slot)) or !sym_length_match_prev_grant_for_retx) { @@ -672,7 +671,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice // Compute the MCS and the number of PRBs, depending on the pending bytes to transmit. grant_prbs_mcs mcs_prbs = - is_retx ? grant_prbs_mcs{h_ul.last_tx_params().mcs, h_ul.last_tx_params().rbs.type1().length()} + is_retx ? grant_prbs_mcs{h_ul->get_grant_params().mcs, h_ul->get_grant_params().rbs.type1().length()} : ue_cc->required_ul_prbs(pusch_td_cfg, grant.recommended_nof_bytes.value(), dci_type); // Try to limit the grant PRBs. if (not is_retx) { @@ -731,13 +730,13 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice } // In case of Retx, the #CRBs need to stay the same. - if (is_retx and crbs.length() != h_ul.last_tx_params().rbs.type1().length()) { + if (is_retx and crbs.length() != h_ul->get_grant_params().rbs.type1().length()) { logger.debug( "ue={} rnti={}: Failed to allocate PUSCH. Cause: No more RBs available at slot={} for h_id={} retransmission", u.ue_index, u.crnti, pusch_alloc.slot, - h_ul.id); + h_ul->id()); return {alloc_status::skip_ue}; } @@ -802,7 +801,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice } // If it's a reTx, fetch the MCS and TBS from the previous transmission. else { - mcs_tbs_info.emplace(sch_mcs_tbs{.mcs = h_ul.last_tx_params().mcs, .tbs = h_ul.last_tx_params().tbs_bytes}); + mcs_tbs_info.emplace(sch_mcs_tbs{.mcs = h_ul->get_grant_params().mcs, .tbs = h_ul->get_grant_params().tbs_bytes}); } // If there is not MCS-TBS info, it means no MCS exists such that the effective code rate is <= 0.95. @@ -844,10 +843,12 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice bool is_new_data = not is_retx; if (is_new_data) { // It is a new tx. - h_ul.new_tx(harq_slot, expert_cfg.max_nof_harq_retxs); + h_ul = ue_cc->harqs.alloc_ul_harq(harq_slot, expert_cfg.max_nof_harq_retxs); + srsran_assert(h_ul.has_value(), "Failed to allocate HARQ"); } else { // It is a retx. - h_ul.new_retx(harq_slot); + bool result = h_ul->new_retx(harq_slot); + srsran_assert(result, "Failed to allocate HARQ retx"); } // Compute total DAI. See TS 38.213, 9.1.3.2. @@ -868,7 +869,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice } // Fill UL PDCCH DCI. - uint8_t rv = ue_cc->get_pusch_rv(h_ul); + uint8_t rv = ue_cc->get_pusch_rv(h_ul->nof_retxs()); switch (dci_type) { case dci_ul_rnti_config_type::tc_rnti_f0_0: build_dci_f0_0_tc_rnti(pdcch->dci, @@ -887,7 +888,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice param_candidate.pusch_td_res_index(), mcs_tbs_info.value().mcs, rv, - h_ul); + *h_ul); break; case dci_ul_rnti_config_type::c_rnti_f0_1: build_dci_f0_1_c_rnti(pdcch->dci, @@ -897,7 +898,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice param_candidate.pusch_td_res_index(), mcs_tbs_info.value().mcs, rv, - h_ul, + *h_ul, dai, ue_cc->channel_state_manager().get_nof_ul_layers()); break; @@ -910,7 +911,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice msg.context.ue_index = u.ue_index; msg.context.ss_id = ss_cfg.get_id(); msg.context.k2 = final_k2; - msg.context.nof_retxs = h_ul.tb().nof_retxs; + msg.context.nof_retxs = h_ul->nof_retxs(); if (is_new_data and ue_cc->link_adaptation_controller().is_ul_olla_enabled()) { msg.context.olla_offset = ue_cc->link_adaptation_controller().ul_snr_offset_db(); } @@ -945,7 +946,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice ss_cfg.get_id(), pdcch->dci.c_rnti_f0_1, crbs, - h_ul); + h_ul->nof_retxs() == 0); break; default: report_fatal_error("Unsupported PDCCH UL DCI format"); @@ -955,7 +956,7 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice get_uci_alloc(grant.cell_index).multiplex_uci_on_pusch(msg, pusch_alloc, ue_cell_cfg, u.crnti); // Save set PDCCH and PUSCH PDU parameters in HARQ process. - ul_harq_sched_context pusch_sched_ctx; + ul_harq_alloc_context pusch_sched_ctx; pusch_sched_ctx.dci_cfg_type = pdcch->dci.type; if (is_new_data) { pusch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_ul_mcs(msg.pusch_cfg.mcs_table); @@ -963,12 +964,12 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice } ue_cc->last_pusch_allocated_slot = pusch_alloc.slot; - h_ul.save_alloc_params(pusch_sched_ctx, msg.pusch_cfg); + h_ul->save_grant_params(pusch_sched_ctx, msg.pusch_cfg); // In case there is a SR pending. Reset it. u.reset_sr_indication(); - return {alloc_status::success, h_ul.last_tx_params().tbs_bytes, crbs.length()}; + return {alloc_status::success, h_ul->get_grant_params().tbs_bytes, crbs.length()}; } // No candidates for PUSCH allocation. diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 1a831a4701..19d52b4641 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -123,8 +123,10 @@ ue_event_manager::~ue_event_manager() {} void ue_event_manager::handle_ue_creation(ue_config_update_event ev) { // Create UE object outside the scheduler slot indication handler to minimize latency. - std::unique_ptr u = std::make_unique(ue_creation_command{ - ev.next_config(), ev.get_fallback_command().has_value() and ev.get_fallback_command().value(), metrics_handler}); + std::unique_ptr u = std::make_unique( + ue_creation_command{ev.next_config(), + ev.get_fallback_command().has_value() and ev.get_fallback_command().value(), + *du_cells[ev.next_config().pcell_common_cfg().cell_index].cell_harqs}); // Defer UE object addition to ue list to the slot indication handler. common_events.emplace(INVALID_DU_UE_INDEX, [this, u = std::move(u), ev = std::move(ev)]() mutable { @@ -512,19 +514,19 @@ static void handle_discarded_pusch(const cell_slot_resource_allocator& prev_slot } // - The lower layers will not attempt to decode the PUSCH and will not send any CRC indication. - ul_harq_process& h_ul = u->get_pcell().harqs.ul_harq(grant.pusch_cfg.harq_id); - if (not h_ul.empty()) { + std::optional h_ul = u->get_pcell().harqs.ul_harq(to_harq_id(grant.pusch_cfg.harq_id)); + if (h_ul.has_value()) { // Note: We don't use this cancellation to update the UL OLLA, as we shouldn't take lates into account in link // adaptation. - if (h_ul.tb().nof_retxs == 0) { + if (h_ul->nof_retxs() == 0) { // Given that the PUSCH grant was discarded before it reached the PHY, the "new_data" flag was not handled // and the UL softbuffer was not reset. To avoid mixing different TBs in the softbuffer, it is important to // reset the UL HARQ process. - h_ul.reset(); + h_ul->reset(); } else { // To avoid a long UL HARQ timeout window (due to lack of CRC indication), it is important to force a NACK // in the UL HARQ process. - h_ul.crc_info(false); + h_ul->ul_crc_info(false); } } @@ -534,7 +536,7 @@ static void handle_discarded_pusch(const cell_slot_resource_allocator& prev_slot // DL HARQ processes with UCI falling in this slot. // Note: We don't use this cancellation to update the DL OLLA, as we shouldn't take lates into account in link // adaptation. - u->get_pcell().harqs.dl_ack_info_cancelled(prev_slot_result.slot); + u->get_pcell().harqs.uci_sched_failed(prev_slot_result.slot); } } } @@ -565,7 +567,7 @@ static void handle_discarded_pucch(const cell_slot_resource_allocator& prev_slot // in the DL HARQ processes with UCI falling in this slot. // Note: We don't use this cancellation to update the DL OLLA, as we shouldn't take lates into account in link // adaptation. - u->get_pcell().harqs.dl_ack_info_cancelled(prev_slot_result.slot); + u->get_pcell().harqs.uci_sched_failed(prev_slot_result.slot); } } } @@ -691,6 +693,7 @@ void ue_event_manager::run(slot_point sl, du_cell_index_t cell_index) } void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, + cell_harq_manager& cell_harqs, ue_fallback_scheduler& fallback_sched, uci_scheduler_impl& uci_sched, scheduler_event_logger& ev_logger, @@ -701,6 +704,7 @@ void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, du_cells[cell_index].cfg = &cell_res_grid.cfg; du_cells[cell_index].res_grid = &cell_res_grid; + du_cells[cell_index].cell_harqs = &cell_harqs; du_cells[cell_index].fallback_sched = &fallback_sched; du_cells[cell_index].uci_sched = &uci_sched; du_cells[cell_index].ev_logger = &ev_logger; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.h b/lib/scheduler/ue_scheduling/ue_event_manager.h index 5872174f52..0ef16ebd4f 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.h +++ b/lib/scheduler/ue_scheduling/ue_event_manager.h @@ -23,6 +23,7 @@ namespace srsran { class cell_metrics_handler; class scheduler_event_logger; class uci_scheduler_impl; +class cell_harq_manager; /// \brief Class used to manage events that arrive to the scheduler and are directed at UEs. /// This class acts as a facade for several of the ue_scheduler subcomponents, managing the asynchronous configuration @@ -36,6 +37,7 @@ class ue_event_manager final : public sched_ue_configuration_handler, ~ue_event_manager(); void add_cell(cell_resource_allocator& cell_res_grid, + cell_harq_manager& cell_harqs, ue_fallback_scheduler& fallback_sched, uci_scheduler_impl& uci_sched, scheduler_event_logger& ev_logger, @@ -115,6 +117,8 @@ class ue_event_manager final : public sched_ue_configuration_handler, cell_resource_allocator* res_grid = nullptr; + cell_harq_manager* cell_harqs = nullptr; + // Reference to fallback scheduler. ue_fallback_scheduler* fallback_sched = nullptr; diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 382c314873..bfaa2fb4fe 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -200,8 +200,8 @@ void ue_fallback_scheduler::handle_sr_indication(du_ue_index_t ue_index) bool ue_fallback_scheduler::schedule_dl_retx(cell_resource_allocator& res_alloc) { for (auto& next_ue_harq_retx : ongoing_ues_ack_retxs) { - auto& u = *ues.find(next_ue_harq_retx.ue_index); - auto* h_dl = next_ue_harq_retx.h_dl; + auto& u = *ues.find(next_ue_harq_retx.ue_index); + std::optional& h_dl = next_ue_harq_retx.h_dl; if (h_dl->has_pending_retx()) { std::optional most_recent_tx_ack = get_most_recent_slot_tx(u.ue_index); @@ -220,9 +220,9 @@ void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& // Processes all the UL UE at once, including UE with new transmissions and UE with retransmissions. for (auto next_ue = pending_ul_ues.begin(); next_ue != pending_ul_ues.end();) { // next_ue must be in the ues list, else it would have been removed by the \ref slot_indication() function. - auto& u = ues[*next_ue]; - ul_harq_process* h_ul_retx = u.get_pcell().harqs.find_pending_ul_retx(); - if (h_ul_retx == nullptr and not u.pending_ul_newtx_bytes()) { + auto& u = ues[*next_ue]; + std::optional h_ul_retx = u.get_pcell().harqs.find_pending_ul_retx(); + if (not h_ul_retx.has_value() and not u.pending_ul_newtx_bytes()) { ++next_ue; continue; } @@ -265,7 +265,7 @@ bool ue_fallback_scheduler::schedule_dl_conres_new_tx(cell_resource_allocator& r } std::optional most_recent_tx_ack = get_most_recent_slot_tx(u.ue_index); - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, nullptr, most_recent_tx_ack, next_ue->is_srb0); + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, most_recent_tx_ack, next_ue->is_srb0); if (outcome == dl_sched_outcome::success) { next_ue = pending_dl_ues_new_tx.erase(next_ue); } else if (outcome == dl_sched_outcome::next_ue) { @@ -301,7 +301,7 @@ bool ue_fallback_scheduler::schedule_dl_new_tx_srb0(cell_resource_allocator& res continue; } - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, nullptr, most_recent_tx_ack, next_ue->is_srb0); + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, most_recent_tx_ack, next_ue->is_srb0); if (outcome == dl_sched_outcome::success) { next_ue = pending_dl_ues_new_tx.erase(next_ue); } else if (outcome == dl_sched_outcome::next_ue) { @@ -344,7 +344,7 @@ void ue_fallback_scheduler::schedule_dl_new_tx_srb1(cell_resource_allocator& res continue; } - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, nullptr, most_recent_tx_ack, next_ue->is_srb0); + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, most_recent_tx_ack, next_ue->is_srb0); if (outcome == dl_sched_outcome::success) { next_ue->is_conres_pending = false; // Move to the next UE ONLY IF the UE has no more pending bytes for SRB1. This is to give priority to the same UE, @@ -380,16 +380,16 @@ static slot_point get_next_srb_slot(const cell_configuration& cell_cfg, slot_poi } ue_fallback_scheduler::dl_sched_outcome -ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_alloc, - ue& u, - dl_harq_process* h_dl_retx, - std::optional most_recent_tx_ack_slots, - std::optional is_srb0) +ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_alloc, + ue& u, + std::optional h_dl_retx, + std::optional most_recent_tx_ack_slots, + std::optional is_srb0) { const auto& bwp_cfg_common = cell_cfg.dl_cfg_common.init_dl_bwp; // Search valid PDSCH time domain resource. - const bool is_retx = h_dl_retx != nullptr; + const bool is_retx = h_dl_retx.has_value(); // \ref sched_ref_slot is the slot that we take as reference for the scheduler, which is processed when calling the // slot_indication(). @@ -503,7 +503,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_a } } - const bool alloc_successful = sched_res.h_dl != nullptr; + const bool alloc_successful = sched_res.h_dl.has_value(); if (alloc_successful) { if (not is_retx) { // The srb1_payload_bytes is meaningful only for SRB1. @@ -530,10 +530,10 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_a } // Helper to determine DCI type to use in PDSCH. -static dci_dl_rnti_config_type get_dci_type(const ue& u, const dl_harq_process& h_dl) +static dci_dl_rnti_config_type get_dci_type(const ue& u, const std::optional& h_dl) { - if (h_dl.has_pending_retx()) { - return h_dl.last_alloc_params().dci_cfg_type; + if (h_dl.has_value()) { + return h_dl->get_grant_params().dci_cfg_type; } else if (u.is_conres_ce_pending()) { return dci_dl_rnti_config_type::tc_rnti_f1_0; } @@ -579,27 +579,26 @@ allocate_ue_fallback_pucch(ue& u, } ue_fallback_scheduler::sched_srb_results -ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - dl_harq_process* h_dl_retx) +ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx) { ue_cell& ue_pcell = u.get_pcell(); const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); - const bool is_retx = h_dl_retx != nullptr; + const bool is_retx = h_dl_retx.has_value(); // Search for empty HARQ. - dl_harq_process* h_dl = is_retx ? h_dl_retx : ue_pcell.harqs.find_empty_dl_harq(); - if (h_dl == nullptr) { + if (not h_dl_retx.has_value() and not ue_pcell.harqs.has_empty_dl_harqs()) { logger.warning("rnti={}: UE must have empty HARQs during ConRes CE allocation", u.crnti); return {}; } - dci_dl_rnti_config_type dci_type = get_dci_type(u, *h_dl); + dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); srsran_assert(dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0, "Only DCI 1_0 with TC-RNTI is supported for ConRes CE scheduling"); @@ -614,9 +613,9 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, sch_mcs_index mcs_idx = 0; if (is_retx) { // Use the same MCS, nof PRBs and TBS as the last allocation. - mcs_idx = h_dl->last_alloc_params().tb[0]->mcs; - prbs_tbs.nof_prbs = h_dl->last_alloc_params().rbs.type1().length(); - prbs_tbs.tbs_bytes = h_dl->last_alloc_params().tb[0].value().tbs_bytes; + mcs_idx = h_dl_retx->get_grant_params().mcs; + prbs_tbs.nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); + prbs_tbs.tbs_bytes = h_dl_retx->get_grant_params().tbs_bytes; } else { // Fetch the pending MAC Contention Resolution CEs bytes. const unsigned pending_bytes = u.pending_conres_ce_bytes(); @@ -723,49 +722,49 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, // Mark resources as occupied in the Resource grid. pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); - fill_dl_srb_grant(u, - pdsch_alloc.slot, - *h_dl, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - mcs_idx, - ue_grant_crbs, - pdsch_cfg, - prbs_tbs.tbs_bytes, - is_retx, - std::nullopt); + auto result = fill_dl_srb_grant(u, + pdsch_alloc.slot, + h_dl_retx, + *pdcch, + dci_type, + pdsch_alloc.result.dl.ue_grants.emplace_back(), + pucch_res_indicator.value(), + pdsch_time_res, + chosen_k1.value(), + mcs_idx, + ue_grant_crbs, + pdsch_cfg, + prbs_tbs.tbs_bytes, + is_retx, + std::nullopt); // No need to pass the nof SRB scheduled bytes. - return sched_srb_results{.h_dl = h_dl}; + return sched_srb_results{.h_dl = result.second}; } -ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - dl_harq_process* h_dl_retx) +ue_fallback_scheduler::sched_srb_results +ue_fallback_scheduler::schedule_dl_srb0(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx) { ue_cell& ue_pcell = u.get_pcell(); const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); - const bool is_retx = h_dl_retx != nullptr; + const bool is_retx = h_dl_retx.has_value(); ue_fallback_scheduler::sched_srb_results result{}; // Search for empty HARQ. - dl_harq_process* h_dl = is_retx ? h_dl_retx : ue_pcell.harqs.find_empty_dl_harq(); - if (h_dl == nullptr) { + if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { logger.warning("rnti={}: UE must have empty HARQs during SRB0 PDU allocation", u.crnti); return {}; } - dci_dl_rnti_config_type dci_type = get_dci_type(u, *h_dl); + dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) @@ -785,9 +784,9 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 sch_mcs_index mcs_idx = 0; if (is_retx) { // Use the same MCS, nof PRBs and TBS as the last allocation. - mcs_idx = h_dl->last_alloc_params().tb[0]->mcs; - prbs_tbs.nof_prbs = h_dl->last_alloc_params().rbs.type1().length(); - prbs_tbs.tbs_bytes = h_dl->last_alloc_params().tb[0].value().tbs_bytes; + mcs_idx = h_dl_retx->get_grant_params().mcs; + prbs_tbs.nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); + prbs_tbs.tbs_bytes = h_dl_retx->get_grant_params().tbs_bytes; } else { // Required PRBs and TBS information for scheduling only ConRes CE in case PDSCH does not have enough space to // accommodate ConRes CE + SRB0. @@ -936,48 +935,48 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb0 if (not result.is_srb_data_pending) { is_srb0 = true; } - fill_dl_srb_grant(u, - pdsch_alloc.slot, - *h_dl, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - mcs_idx, - ue_grant_crbs, - pdsch_cfg, - prbs_tbs.tbs_bytes, - is_retx, - is_srb0); + auto outcome = fill_dl_srb_grant(u, + pdsch_alloc.slot, + h_dl_retx, + *pdcch, + dci_type, + pdsch_alloc.result.dl.ue_grants.emplace_back(), + pucch_res_indicator.value(), + pdsch_time_res, + chosen_k1.value(), + mcs_idx, + ue_grant_crbs, + pdsch_cfg, + prbs_tbs.tbs_bytes, + is_retx, + is_srb0); // No need to pass the nof SRB scheduled bytes with SRB0. - result.h_dl = h_dl; + result.h_dl = outcome.second; return result; } -ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1(ue& u, - slot_point sched_ref_slot, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - dl_harq_process* h_dl_retx) +ue_fallback_scheduler::sched_srb_results +ue_fallback_scheduler::schedule_dl_srb1(ue& u, + slot_point sched_ref_slot, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx) { ue_cell& ue_pcell = u.get_pcell(); const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); - const bool is_retx = h_dl_retx != nullptr; + const bool is_retx = h_dl_retx.has_value(); // Search for empty HARQ. - dl_harq_process* h_dl = is_retx ? h_dl_retx : ue_pcell.harqs.find_empty_dl_harq(); - if (h_dl == nullptr) { + if (not h_dl_retx.has_value() and not ue_pcell.harqs.has_empty_dl_harqs()) { return {}; } - dci_dl_rnti_config_type dci_type = get_dci_type(u, *h_dl); + dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) @@ -1012,9 +1011,9 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 const bool is_srb0 = false; if (is_retx) { - const unsigned final_nof_prbs = h_dl->last_alloc_params().rbs.type1().length(); - final_mcs_tbs.mcs = h_dl->last_alloc_params().tb.front().value().mcs; - final_mcs_tbs.tbs = h_dl->last_alloc_params().tb.front().value().tbs_bytes; + const unsigned final_nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); + final_mcs_tbs.mcs = h_dl_retx->get_grant_params().mcs; + final_mcs_tbs.tbs = h_dl_retx->get_grant_params().tbs_bytes; ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, final_nof_prbs, 0); if (ue_grant_crbs.empty() or ue_grant_crbs.length() < final_nof_prbs) { @@ -1101,7 +1100,8 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 logger.debug("ue={} rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: Grant is too small to fit even " "ConRes CE.", u.ue_index, - u.crnti); + u.crnti, + pdsch_alloc.slot); return {}; } } @@ -1149,56 +1149,51 @@ ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1 // Mark resources as occupied in the ResourceGrid. pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); - unsigned nof_srb1_scheduled_bytes = fill_dl_srb_grant(u, - pdsch_alloc.slot, - *h_dl, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - final_mcs_tbs.mcs, - ue_grant_crbs, - pdsch_cfg, - final_mcs_tbs.tbs, - is_retx, - is_srb0); + auto [nof_srb1_scheduled_bytes, h_dl] = fill_dl_srb_grant(u, + pdsch_alloc.slot, + h_dl_retx, + *pdcch, + dci_type, + pdsch_alloc.result.dl.ue_grants.emplace_back(), + pucch_res_indicator.value(), + pdsch_time_res, + chosen_k1.value(), + final_mcs_tbs.mcs, + ue_grant_crbs, + pdsch_cfg, + final_mcs_tbs.tbs, + is_retx, + is_srb0); return sched_srb_results{.h_dl = h_dl, .nof_srb1_scheduled_bytes = nof_srb1_scheduled_bytes}; } -unsigned ue_fallback_scheduler::fill_dl_srb_grant(ue& u, - slot_point pdsch_slot, - dl_harq_process& h_dl, - pdcch_dl_information& pdcch, - dci_dl_rnti_config_type dci_type, - dl_msg_alloc& msg, - unsigned pucch_res_indicator, - unsigned pdsch_time_res, - unsigned k1, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pdsch_config_params& pdsch_params, - unsigned tbs_bytes, - bool is_retx, - std::optional is_srb0) +std::pair +ue_fallback_scheduler::fill_dl_srb_grant(ue& u, + slot_point pdsch_slot, + std::optional h_dl, + pdcch_dl_information& pdcch, + dci_dl_rnti_config_type dci_type, + dl_msg_alloc& msg, + unsigned pucch_res_indicator, + unsigned pdsch_time_res, + unsigned k1, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pdsch_config_params& pdsch_params, + unsigned tbs_bytes, + bool is_retx, + std::optional is_srb0) { // Allocate DL HARQ. // NOTE: We do not multiplex the SRB1 PUCCH with existing PUCCH HARQs, thus both DAI and HARQ-ACK bit index are 0. static constexpr uint8_t srb_dai = 0; if (not is_retx) { - const bool is_fallback = true; - h_dl.new_tx(pdsch_slot, - k1, - expert_cfg.max_nof_harq_retxs, - srb_dai, - u.get_pcell().channel_state_manager().get_wideband_cqi(), - pdsch_params.nof_layers, - is_fallback); + h_dl = u.get_pcell().harqs.alloc_dl_harq(pdsch_slot, k1, expert_cfg.max_nof_harq_retxs, srb_dai); } else { const unsigned harq_bit_idx = 0U; - h_dl.new_retx(pdsch_slot, k1, harq_bit_idx); + bool result = h_dl->new_retx(pdsch_slot, k1, harq_bit_idx); + srsran_sanity_check(result, "Unable to allocate HARQ retx"); } // Fill DL PDCCH DCI. @@ -1213,7 +1208,7 @@ unsigned ue_fallback_scheduler::fill_dl_srb_grant(ue& u, pucch_res_indicator, mcs_idx, msg4_rv, - h_dl); + *h_dl); break; } case dci_dl_rnti_config_type::c_rnti_f1_0: { @@ -1227,7 +1222,7 @@ unsigned ue_fallback_scheduler::fill_dl_srb_grant(ue& u, srb_dai, mcs_idx, msg4_rv, - h_dl); + *h_dl); break; } default: { @@ -1239,7 +1234,7 @@ unsigned ue_fallback_scheduler::fill_dl_srb_grant(ue& u, msg.context.ue_index = u.ue_index; msg.context.k1 = k1; msg.context.ss_id = pdcch.ctx.context.ss_id; - msg.context.nof_retxs = h_dl.tb(0).nof_retxs; + msg.context.nof_retxs = h_dl->nof_retxs(); msg.context.olla_offset = 0; unsigned srb1_bytes_allocated = 0; @@ -1303,13 +1298,16 @@ unsigned ue_fallback_scheduler::fill_dl_srb_grant(ue& u, } // Save in HARQ the parameters set for this PDCCH and PDSCH PDUs. - h_dl.save_alloc_params(dl_harq_sched_context{pdcch.dci.type}, msg.pdsch_cfg); + dl_harq_alloc_context ctxt{pdcch.dci.type, std::nullopt, std::nullopt, std::nullopt, true}; + h_dl->save_grant_params(ctxt, msg.pdsch_cfg); - return srb1_bytes_allocated; + return std::make_pair(srb1_bytes_allocated, *h_dl); } ue_fallback_scheduler::ul_srb_sched_outcome -ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u, ul_harq_process* h_ul_retx) +ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, + ue& u, + std::optional h_ul_retx) { // The caller ensures the slot is Ul enabled. const cell_slot_resource_allocator& pdcch_alloc = res_alloc[0]; @@ -1319,10 +1317,10 @@ ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u, static_vector pusch_td_res_index_list = get_pusch_td_resource_indices(cell_cfg, pdcch_slot); - bool is_retx = h_ul_retx != nullptr; + bool is_retx = h_ul_retx.has_value(); if (is_retx) { - srsran_sanity_check(h_ul_retx->last_tx_params().dci_cfg_type == dci_ul_rnti_config_type::c_rnti_f0_0, + srsran_sanity_check(h_ul_retx->get_grant_params().dci_cfg_type == dci_ul_rnti_config_type::c_rnti_f0_0, "Invalid DCI type for UL retransmission for fallback UE"); } static_vector search_spaces = @@ -1344,7 +1342,7 @@ ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u, // If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for // the first transmission. const bool sym_length_match_prev_grant_for_retx = - is_retx ? pusch_td.symbols.length() == h_ul_retx->last_tx_params().nof_symbols : true; + is_retx ? pusch_td.symbols.length() == h_ul_retx->get_grant_params().nof_symbols : true; if (pusch_td.symbols.start() < start_ul_symbols or pusch_td.symbols.stop() > (start_ul_symbols + cell_cfg.get_nof_ul_symbol_per_slot(pusch_slot)) or !sym_length_match_prev_grant_for_retx) { @@ -1429,7 +1427,7 @@ ue_fallback_scheduler::schedule_ul_srb(ue& cell_resource_allocator& res_alloc, unsigned pusch_time_res, const pusch_time_domain_resource_allocation& pusch_td, - ul_harq_process* h_ul_retx) + std::optional h_ul_retx) { ue_cell& ue_pcell = u.get_pcell(); cell_slot_resource_allocator& pdcch_alloc = res_alloc[0]; @@ -1440,11 +1438,10 @@ ue_fallback_scheduler::schedule_ul_srb(ue& const prb_bitmap used_crbs = pusch_alloc.ul_res_grid.used_crbs( cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.scs, init_ul_bwp_crbs, pusch_td.symbols); - const bool is_retx = h_ul_retx != nullptr; + const bool is_retx = h_ul_retx.has_value(); // Search for empty HARQ. - ul_harq_process* h_ul = is_retx ? h_ul_retx : ue_pcell.harqs.find_empty_ul_harq(); - if (h_ul == nullptr) { + if (not h_ul_retx.has_value() and not ue_pcell.harqs.has_empty_ul_harqs()) { logger.debug("ue={} rnti={} PUSCH allocation skipped. Cause: no HARQ available", u.ue_index, u.crnti); return ul_srb_sched_outcome::next_ue; } @@ -1463,9 +1460,9 @@ ue_fallback_scheduler::schedule_ul_srb(ue& crb_interval ue_grant_crbs; sch_mcs_tbs final_mcs_tbs; if (is_retx) { - const unsigned final_nof_prbs = h_ul->last_tx_params().rbs.type1().length(); - final_mcs_tbs.mcs = h_ul->last_tx_params().mcs; - final_mcs_tbs.tbs = h_ul->last_tx_params().tbs_bytes; + const unsigned final_nof_prbs = h_ul_retx->get_grant_params().rbs.type1().length(); + final_mcs_tbs.mcs = h_ul_retx->get_grant_params().mcs; + final_mcs_tbs.tbs = h_ul_retx->get_grant_params().tbs_bytes; ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, final_nof_prbs, 0); if (ue_grant_crbs.empty() or ue_grant_crbs.length() < final_nof_prbs) { @@ -1549,7 +1546,7 @@ ue_fallback_scheduler::schedule_ul_srb(ue& fill_ul_srb_grant(u, pdcch_alloc.slot, - *h_ul, + h_ul_retx, *pdcch, pusch_alloc.result.ul.puschs.emplace_back(), pusch_time_res, @@ -1563,28 +1560,29 @@ ue_fallback_scheduler::schedule_ul_srb(ue& return ul_srb_sched_outcome::next_ue; } -void ue_fallback_scheduler::fill_ul_srb_grant(ue& u, - slot_point pdcch_slot, - ul_harq_process& h_ul, - pdcch_ul_information& pdcch, - ul_sched_info& msg, - unsigned pusch_time_res, - unsigned k2, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pusch_config_params& pusch_params, - unsigned tbs_bytes, - bool is_retx) +void ue_fallback_scheduler::fill_ul_srb_grant(ue& u, + slot_point pdcch_slot, + std::optional h_ul, + pdcch_ul_information& pdcch, + ul_sched_info& msg, + unsigned pusch_time_res, + unsigned k2, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pusch_config_params& pusch_params, + unsigned tbs_bytes, + bool is_retx) { if (is_retx) { // It is a retx. - h_ul.new_retx(pdcch_slot + k2 + cell_cfg.ntn_cs_koffset); + bool result = h_ul->new_retx(pdcch_slot + k2 + cell_cfg.ntn_cs_koffset); + srsran_sanity_check(result, "Failed to setup HARQ retx"); } else { // It is a new tx. - h_ul.new_tx(pdcch_slot + k2 + cell_cfg.ntn_cs_koffset, expert_cfg.max_nof_harq_retxs); + h_ul = u.get_pcell().harqs.alloc_ul_harq(pdcch_slot + k2 + cell_cfg.ntn_cs_koffset, expert_cfg.max_nof_harq_retxs); } - uint8_t rv = u.get_pcell().get_pusch_rv(h_ul); + uint8_t rv = u.get_pcell().get_pusch_rv(h_ul->nof_retxs()); build_dci_f0_0_c_rnti(pdcch.dci, u.get_pcell().cfg().search_space(pdcch.ctx.context.ss_id), cell_cfg.ul_cfg_common.init_ul_bwp, @@ -1592,13 +1590,13 @@ void ue_fallback_scheduler::fill_ul_srb_grant(ue& u, pusch_time_res, mcs_idx, rv, - h_ul); + *h_ul); // Fill PDSCH PDU. msg.context.ue_index = u.ue_index; msg.context.ss_id = ss_cfg.get_id(); msg.context.k2 = k2; - msg.context.nof_retxs = h_ul.tb().nof_retxs; + msg.context.nof_retxs = h_ul->nof_retxs(); if (msg.context.nof_retxs == 0 and u.get_pcell().link_adaptation_controller().is_ul_olla_enabled()) { msg.context.olla_offset = u.get_pcell().link_adaptation_controller().ul_snr_offset_db(); } @@ -1613,7 +1611,7 @@ void ue_fallback_scheduler::fill_ul_srb_grant(ue& u, not is_retx); // Save set PDCCH and PUSCH PDU parameters in HARQ process. - h_ul.save_alloc_params(ul_harq_sched_context{pdcch.dci.type}, msg.pusch_cfg); + h_ul->save_grant_params(ul_harq_alloc_context{pdcch.dci.type}, msg.pusch_cfg); // In case there is a SR pending, reset it. u.reset_sr_indication(); @@ -1629,9 +1627,10 @@ const pdsch_time_domain_resource_allocation& ue_fallback_scheduler::get_pdsch_td return cell_cfg.dl_cfg_common.init_dl_bwp.pdsch_common.pdsch_td_alloc_list[pdsch_time_res_idx]; } -std::optional ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsch_config_common& pdsch_cfg, - slot_point sl_tx, - const dl_harq_process* h_dl_retx) const +std::optional +ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsch_config_common& pdsch_cfg, + slot_point sl_tx, + const std::optional& h_dl_retx) const { std::optional candidate_pdsch_time_res_idx; for (unsigned time_res_idx = 0; time_res_idx != pdsch_cfg.pdsch_td_alloc_list.size(); ++time_res_idx) { @@ -1647,8 +1646,8 @@ std::optional ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsc } // For retransmissions, we want to make sure we use the same number of symbols as the original transmission. - if (h_dl_retx != nullptr) { - if (h_dl_retx->last_alloc_params().nof_symbols != pdsch_td_cfg.symbols.length()) { + if (h_dl_retx.has_value()) { + if (h_dl_retx->get_grant_params().nof_symbols != pdsch_td_cfg.symbols.length()) { continue; } return candidate_pdsch_time_res_idx = time_res_idx; @@ -1670,8 +1669,8 @@ ue_fallback_scheduler::get_most_recent_slot_tx(du_ue_index_t ue_idx) const std::optional most_recent_tx_ack_slot; for (const auto& ue_proc : ongoing_ues_ack_retxs) { if (ue_proc.ue_index == ue_idx) { - slot_point h_dl_slot_tx = ue_proc.h_dl->slot_tx(); - slot_point h_dl_slot_ack = ue_proc.h_dl->slot_ack(); + slot_point h_dl_slot_tx = ue_proc.h_dl->pdsch_slot(); + slot_point h_dl_slot_ack = ue_proc.h_dl->uci_slot(); if (not most_recent_tx_ack_slot.has_value()) { most_recent_tx_ack_slot.emplace( most_recent_tx_slots{.most_recent_tx_slot = h_dl_slot_tx, .most_recent_ack_slot = h_dl_slot_ack}); @@ -1688,10 +1687,10 @@ ue_fallback_scheduler::get_most_recent_slot_tx(du_ue_index_t ue_idx) const return most_recent_tx_ack_slot; } -void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ue_index, - dl_harq_process* h_dl, - unsigned srb_payload_bytes, - std::optional is_srb0) +void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ue_index, + std::optional h_dl, + unsigned srb_payload_bytes, + std::optional is_srb0) { srsran_sanity_check(ongoing_ues_ack_retxs.end() == std::find_if(ongoing_ues_ack_retxs.begin(), @@ -1766,8 +1765,8 @@ void ue_fallback_scheduler::update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_id (ack_tracker.is_srb0.has_value() and ack_tracker.is_srb0.value())) { continue; } - if (ack_tracker.h_dl->is_waiting_ack() and ack_tracker.h_dl->slot_tx() >= sl and - ack_tracker.h_dl->tb(0).nof_retxs == 0) { + if (ack_tracker.h_dl->is_waiting_ack() and ack_tracker.h_dl->pdsch_slot() >= sl and + ack_tracker.h_dl->nof_retxs() == 0) { unsigned tx_ed_bytes = ack_tracker.srb1_payload_bytes; srb1_buffer_bytes = srb1_buffer_bytes > tx_ed_bytes ? srb1_buffer_bytes - tx_ed_bytes : 0; } @@ -1825,14 +1824,12 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) // fallback mode. This is not needed for SRB0, which doesn't allow segmentation. if ((it_ue_harq->is_srb0.has_value() and not it_ue_harq->is_srb0.value()) and (not ues[it_ue_harq->ue_index].get_pcell().is_in_fallback_mode())) { - const unsigned tb_index = 0U; - it_ue_harq->h_dl->cancel_harq_retxs(tb_index); + it_ue_harq->h_dl->cancel_retxs(); it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); continue; } - dl_harq_process& h_dl = *it_ue_harq->h_dl; - if (h_dl.empty()) { + if (not it_ue_harq->h_dl.has_value() or it_ue_harq->h_dl->empty()) { it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); continue; } @@ -1840,7 +1837,7 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) // If the HARQ process has the "fallback" flag set to false, it means that the HARQ process got reset by its // timeout, and in the meantime got reused by the non-fallback scheduler. In this case, it cannot be processed by // the fallback scheduler. NOTE: this very unlikely to happen, but not impossible under certain extreme conditions. - if (not h_dl.last_alloc_params().is_fallback) { + if (not it_ue_harq->h_dl->get_grant_params().is_fallback) { it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); continue; } @@ -1864,8 +1861,8 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) ongoing_ues_ack_retxs.end(), [ue_idx = ue.ue_index, sl](const ack_and_retx_tracker& tracker) { return tracker.ue_index == ue_idx and tracker.h_dl->is_waiting_ack() and - tracker.h_dl->tb(0).nof_retxs == 0 and - tracker.h_dl->slot_tx() >= sl; + tracker.h_dl->nof_retxs() == 0 and + tracker.h_dl->pdsch_slot() >= sl; }); if (remove_ue) { @@ -1886,7 +1883,10 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) auto& ue = ues[*ue_it]; if (not ue.get_pcell().is_in_fallback_mode()) { for (uint32_t h_id = 0; h_id != ue.get_pcell().harqs.nof_ul_harqs(); ++h_id) { - ue.get_pcell().harqs.ul_harq(h_id).cancel_harq_retxs(); + auto h_ul = ue.get_pcell().harqs.ul_harq(to_harq_id(h_id)); + if (h_ul.has_value()) { + h_ul->cancel_retxs(); + } } ue_it = pending_ul_ues.erase(ue_it); continue; diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 90355c0ddf..d9531a2317 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -102,20 +102,21 @@ class ue_fallback_scheduler /// \brief Tries to schedule DL SRB0/SRB1 message and/or ConRes CE only for a UE, iterating over several PDSCH slots /// ahead of the current reference slot. /// \remark If \c is_srb0 is empty, then only ConRes CE is scheduled. - dl_sched_outcome schedule_dl_srb(cell_resource_allocator& res_alloc, - ue& u, - dl_harq_process* h_dl_retx, - std::optional most_recent_tx_ack_slots = std::nullopt, - std::optional is_srb0 = std::nullopt); + dl_sched_outcome schedule_dl_srb(cell_resource_allocator& res_alloc, + ue& u, + std::optional h_dl_retx, + std::optional most_recent_tx_ack_slots = std::nullopt, + std::optional is_srb0 = std::nullopt); enum class ul_srb_sched_outcome { next_ue, next_slot, stop_ul_scheduling }; /// \brief Tries to schedule UL SRB1 message for a UE iterating over the possible k2 values. Returns true if the /// scheduler should keep allocating the next UL UE, false if it should stop the UL allocation. - ul_srb_sched_outcome schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u, ul_harq_process* h_ul_retx); + ul_srb_sched_outcome + schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u, std::optional h_ul_retx); struct sched_srb_results { - dl_harq_process* h_dl = nullptr; + std::optional h_dl; // This field represents whether SRB data was scheduled along with ConRes CE or only ConRes CE was scheduled. bool is_srb_data_pending = false; // This is only meaningful for SRB1, and represents the number of LCID-1 bytes (excluding any overhead) that have @@ -127,12 +128,12 @@ class ue_fallback_scheduler /// \remark This function handles the following scenarios: /// - Schedules ConRes CE only if ConRes indication is received from MAC but no buffer status update is received /// for SRB0/SRB1. - sched_srb_results schedule_dl_conres_ce(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - dl_harq_process* h_dl_retx); + sched_srb_results schedule_dl_conres_ce(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx); /// \brief Tries to schedule DL SRB0 message for a UE and for a specific PDSCH slot. /// \remark This function handles the following scenarios: @@ -140,67 +141,67 @@ class ue_fallback_scheduler /// - Schedules SRB0 (not empty) + ConRes CE (if pending) if there is enough space in PDSCH resource grid. /// - Schedules ConRes CE only (if pending) if there is not enough space in PDSCH resource grid to fit SRB0 (not /// empty) + ConRes CE. - sched_srb_results schedule_dl_srb0(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - dl_harq_process* h_dl_retx); + sched_srb_results schedule_dl_srb0(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx); /// \brief Tries to schedule DL SRB1 message for a UE and for a specific PDSCH slot. /// \remark This function handles the following scenarios: /// - Schedules SRB1 (not empty) + ConRes CE (if pending). - sched_srb_results schedule_dl_srb1(ue& u, - slot_point sched_ref_slot, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - dl_harq_process* h_dl_retx = nullptr); + sched_srb_results schedule_dl_srb1(ue& u, + slot_point sched_ref_slot, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx = std::nullopt); /// \brief Tries to schedule SRB1 message for a specific PUSCH time domain resource. ul_srb_sched_outcome schedule_ul_srb(ue& u, cell_resource_allocator& res_alloc, unsigned pusch_time_res, const pusch_time_domain_resource_allocation& pusch_td, - ul_harq_process* h_ul_retx); - - unsigned fill_dl_srb_grant(ue& u, - slot_point pdsch_slot, - dl_harq_process& h_dl, - pdcch_dl_information& pdcch, - dci_dl_rnti_config_type dci_type, - dl_msg_alloc& msg, - unsigned pucch_res_indicator, - unsigned pdsch_time_res, - unsigned k1, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pdsch_config_params& pdsch_params, - unsigned tbs_bytes, - bool is_retx, - std::optional is_srb0 = std::nullopt); - - void fill_ul_srb_grant(ue& u, - slot_point pdcch_slot, - ul_harq_process& h_ul, - pdcch_ul_information& pdcch, - ul_sched_info& msg, - unsigned pusch_time_res, - unsigned k2_offset, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pusch_config_params& pusch_params, - unsigned tbs_bytes, - bool is_retx); + std::optional h_ul_retx); + + std::pair fill_dl_srb_grant(ue& u, + slot_point pdsch_slot, + std::optional h_dl, + pdcch_dl_information& pdcch, + dci_dl_rnti_config_type dci_type, + dl_msg_alloc& msg, + unsigned pucch_res_indicator, + unsigned pdsch_time_res, + unsigned k1, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pdsch_config_params& pdsch_params, + unsigned tbs_bytes, + bool is_retx, + std::optional is_srb0 = std::nullopt); + + void fill_ul_srb_grant(ue& u, + slot_point pdcch_slot, + std::optional h_ul, + pdcch_ul_information& pdcch, + ul_sched_info& msg, + unsigned pusch_time_res, + unsigned k2_offset, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pusch_config_params& pusch_params, + unsigned tbs_bytes, + bool is_retx); /// Returns the PDSCH time domain resource allocation for a given PDSCH time resource index. const pdsch_time_domain_resource_allocation& get_pdsch_td_cfg(unsigned pdsch_time_res_idx) const; // Returns the PDSCH time resource index that is suitable for a given PDSCH configuration. - std::optional get_pdsch_time_res_idx(const pdsch_config_common& pdsch_cfg, - slot_point sl_tx, - const dl_harq_process* h_dl_retx) const; + std::optional get_pdsch_time_res_idx(const pdsch_config_common& pdsch_cfg, + slot_point sl_tx, + const std::optional& h_dl_retx) const; /// Defines the information that is needed to track the DL UEs that are pending for new SRB0/SRB1/ConRes CE TX. struct fallback_ue { @@ -226,34 +227,34 @@ class ue_fallback_scheduler class ack_and_retx_tracker { public: - explicit ack_and_retx_tracker(du_ue_index_t ue_idx, - dl_harq_process* h_dl_, - ue_repository& ues_, - unsigned srb_payload_bytes_, - std::optional is_srb0_ = std::nullopt) : + explicit ack_and_retx_tracker(du_ue_index_t ue_idx, + const std::optional& h_dl_, + ue_repository& ues_, + unsigned srb_payload_bytes_, + std::optional is_srb0_ = std::nullopt) : ue_index(ue_idx), is_srb0(is_srb0_), h_dl(h_dl_), srb1_payload_bytes(srb_payload_bytes_) { } explicit ack_and_retx_tracker(const ack_and_retx_tracker& other) = default; - bool match_ue_harq(du_ue_index_t ue_idx_, dl_harq_process* h_dl_) const + bool match_ue_harq(du_ue_index_t ue_idx_, const std::optional& h_dl_) const { return ue_index == ue_idx_ and h_dl == h_dl_; } du_ue_index_t ue_index; // This field is empty if HARQ is used to schedule ConRes CE only. - std::optional is_srb0; - dl_harq_process* h_dl; + std::optional is_srb0; + std::optional h_dl; // Represents the number of LCID-1 bytes (excluding any overhead) that have been allocated for this TX. // This is only meaningful for SRB1, unsigned srb1_payload_bytes = 0; }; - void store_harq_tx(du_ue_index_t ue_index, - dl_harq_process* h_dl, - unsigned srb_payload_bytes, - std::optional is_srb0 = std::nullopt); + void store_harq_tx(du_ue_index_t ue_index, + std::optional h_dl, + unsigned srb_payload_bytes, + std::optional is_srb0 = std::nullopt); // If there are any pending SRB0, SRB1 transmissions or ConRes CE for the UE, the function returns the most recent // slot with PDSCH for SRB0/SRB1/ConRes CE allocation and the most recent slot with the corresponding PUCCH. diff --git a/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h b/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h index 925a32a5cf..9bddf4d382 100644 --- a/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h +++ b/lib/scheduler/ue_scheduling/ue_pdsch_alloc_param_candidate_searcher.h @@ -149,16 +149,16 @@ class ue_pdsch_alloc_param_candidate_searcher }; /// Create a searcher for UE PDSCH parameters. - ue_pdsch_alloc_param_candidate_searcher(const ue& ue_ref_, - du_cell_index_t cell_index, - dl_harq_process& dl_harq_, - slot_point pdcch_slot_, - span slots_with_no_pdsch_space_) : + ue_pdsch_alloc_param_candidate_searcher(const ue& ue_ref_, + du_cell_index_t cell_index, + const std::optional& dl_harq_, + slot_point pdcch_slot_, + span slots_with_no_pdsch_space_) : ue_ref(ue_ref_), ue_cc(ue_ref.find_cell(cell_index)), slots_with_no_pdsch_space(slots_with_no_pdsch_space_), dl_harq(dl_harq_), - is_retx(not dl_harq.empty()), + is_retx(dl_harq.has_value()), pdcch_slot(pdcch_slot_) { // Cell is not part of UE configured cells. @@ -166,8 +166,8 @@ class ue_pdsch_alloc_param_candidate_searcher return; } - if (not dl_harq.empty()) { - preferred_rnti_type = dl_harq.last_alloc_params().dci_cfg_type; + if (dl_harq.has_value()) { + preferred_rnti_type = dl_harq->get_grant_params().dci_cfg_type; } // Generate list of Search Spaces. @@ -253,7 +253,7 @@ class ue_pdsch_alloc_param_candidate_searcher // If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for // the first transmission. - if (is_retx and current.pdsch_td_res().symbols.length() != dl_harq.last_alloc_params().nof_symbols) { + if (is_retx and current.pdsch_td_res().symbols.length() != dl_harq->get_grant_params().nof_symbols) { return false; } @@ -291,7 +291,7 @@ class ue_pdsch_alloc_param_candidate_searcher span slots_with_no_pdsch_space; // DL HARQ considered for allocation. - const dl_harq_process& dl_harq; + const std::optional& dl_harq; // Whether the current search is for a newTx or a reTx. const bool is_retx; // List of Search Space candidates for the DL HARQ considered for allocation. diff --git a/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h b/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h index ec690bc901..1959b4e0fd 100644 --- a/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h +++ b/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h @@ -155,7 +155,7 @@ class ue_pusch_alloc_param_candidate_searcher /// Create a searcher for UE PUSCH parameters. ue_pusch_alloc_param_candidate_searcher(const ue& ue_ref_, du_cell_index_t cell_index, - ul_harq_process& ul_harq_, + const std::optional& ul_harq_, slot_point pdcch_slot_, span slots_with_no_pusch_space_, slot_point pusch_slot_) : @@ -163,7 +163,7 @@ class ue_pusch_alloc_param_candidate_searcher ue_cc(ue_ref.find_cell(cell_index)), slots_with_no_pusch_space(slots_with_no_pusch_space_), ul_harq(ul_harq_), - is_retx(not ul_harq.empty()), + is_retx(ul_harq.has_value()), pdcch_slot(pdcch_slot_), pusch_slot(pusch_slot_) { @@ -172,8 +172,8 @@ class ue_pusch_alloc_param_candidate_searcher return; } - if (not ul_harq.empty()) { - preferred_rnti_type = ul_harq.last_tx_params().dci_cfg_type; + if (ul_harq.has_value()) { + preferred_rnti_type = ul_harq->get_grant_params().dci_cfg_type; } // Generate list of Search Spaces. @@ -259,7 +259,7 @@ class ue_pusch_alloc_param_candidate_searcher // If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for // the first transmission. - if (is_retx and current.pusch_td_res().symbols.length() != ul_harq.last_tx_params().nof_symbols) { + if (is_retx and current.pusch_td_res().symbols.length() != ul_harq->get_grant_params().nof_symbols) { return false; } @@ -301,7 +301,7 @@ class ue_pusch_alloc_param_candidate_searcher span slots_with_no_pusch_space; // UL HARQ considered for allocation. - const ul_harq_process& ul_harq; + const std::optional& ul_harq; // Whether the current search is for a newTx or a reTx. const bool is_retx; // List of SearchSpace candidates for the UL HARQ considered for allocation. diff --git a/lib/scheduler/ue_scheduling/ue_repository.cpp b/lib/scheduler/ue_scheduling/ue_repository.cpp index 715079d9ac..df00616e42 100644 --- a/lib/scheduler/ue_scheduling/ue_repository.cpp +++ b/lib/scheduler/ue_scheduling/ue_repository.cpp @@ -26,14 +26,14 @@ static bool is_ue_ready_for_removal(ue& u) // Ensure that there no currently active HARQs. unsigned nof_ue_cells = u.nof_cells(); for (unsigned cell_idx = 0; cell_idx != nof_ue_cells; ++cell_idx) { - ue_cell& c = u.get_cell((ue_cell_index_t)cell_idx); + const ue_cell& c = u.get_cell((ue_cell_index_t)cell_idx); for (unsigned i = 0; i != c.harqs.nof_dl_harqs(); ++i) { - if (not c.harqs.dl_harq(i).empty()) { + if (c.harqs.dl_harq(to_harq_id(i)).has_value()) { return false; } } for (unsigned i = 0; i != c.harqs.nof_ul_harqs(); ++i) { - if (not c.harqs.ul_harq(i).empty()) { + if (c.harqs.ul_harq(to_harq_id(i)).has_value()) { return false; } } diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 8bca9b5622..d79c9ce45e 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -9,16 +9,18 @@ */ #include "ue_scheduler_impl.h" +#include "../logging/scheduler_metrics_handler.h" #include "../policy/scheduler_policy_factory.h" using namespace srsran; ue_scheduler_impl::ue_scheduler_impl(const scheduler_ue_expert_config& expert_cfg_, sched_configuration_notifier& mac_notif, - cell_metrics_handler& metric_handler) : + cell_metrics_handler& metric_handler_) : expert_cfg(expert_cfg_), + metrics_handler(metric_handler_), ue_alloc(expert_cfg, ue_db, srslog::fetch_basic_logger("SCHED")), - event_mng(ue_db, metric_handler), + event_mng(ue_db, metrics_handler), logger(srslog::fetch_basic_logger("SCHED")) { } @@ -26,8 +28,9 @@ ue_scheduler_impl::ue_scheduler_impl(const scheduler_ue_expert_config& expert_cf void ue_scheduler_impl::add_cell(const ue_scheduler_cell_params& params) { ue_res_grid_view.add_cell(*params.cell_res_alloc); - cells[params.cell_index] = std::make_unique(expert_cfg, params, ue_db); + cells[params.cell_index] = std::make_unique(expert_cfg, params, ue_db, metrics_handler); event_mng.add_cell(*params.cell_res_alloc, + cells[params.cell_index]->cell_harqs, cells[params.cell_index]->fallback_sched, cells[params.cell_index]->uci_sched, *params.ev_logger, @@ -104,8 +107,9 @@ void ue_scheduler_impl::update_harq_pucch_counter(cell_resource_allocator& cell_ // Each PUCCH grants can potentially carry ACKs for different HARQ processes (as many as the harq_ack_nof_bits) // expecting to be acknowledged on the same slot. for (unsigned harq_bit_idx = 0; harq_bit_idx != nof_harqs_per_rnti_per_slot; ++harq_bit_idx) { - dl_harq_process* h_dl = user->get_pcell().harqs.find_dl_harq_waiting_ack_slot(slot_alloc.slot, harq_bit_idx); - if (h_dl == nullptr) { + std::optional h_dl = + user->get_pcell().harqs.find_dl_harq(slot_alloc.slot, harq_bit_idx); + if (not h_dl.has_value() or not h_dl->is_waiting_ack()) { logger.warning( "ue={} rnti={}: No DL HARQ process with state waiting-for-ack found at slot={} for harq-bit-index={}", user->ue_index, @@ -174,6 +178,9 @@ void ue_scheduler_impl::run_slot(slot_point slot_tx, du_cell_index_t cell_index) // Run cell-specific SRB0 scheduler. cells[cell_index]->fallback_sched.run_slot(*cells[cell_index]->cell_res_alloc); + // Check for timeouts in the cell HARQ processes. + cells[cell_index]->cell_harqs.slot_indication(slot_tx); + // Synchronize all carriers. Last thread to reach this synchronization point, runs UE scheduling strategy. sync_point.wait( slot_tx, ue_alloc.nof_cells(), [this, slot_tx, cell_index]() { run_sched_strategy(slot_tx, cell_index); }); @@ -184,3 +191,33 @@ void ue_scheduler_impl::run_slot(slot_point slot_tx, du_cell_index_t cell_index) // TODO: remove this. puxch_grant_sanitizer(*cells[cell_index]->cell_res_alloc); } + +namespace { + +class harq_manager_timeout_notifier : public harq_timeout_notifier +{ +public: + explicit harq_manager_timeout_notifier(cell_metrics_handler& metrics_handler_) : metrics_handler(metrics_handler_) {} + + void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override + { + metrics_handler.handle_harq_timeout(ue_idx, is_dl); + } + +private: + cell_metrics_handler& metrics_handler; +}; + +} // namespace + +ue_scheduler_impl::cell::cell(const scheduler_ue_expert_config& expert_cfg, + const ue_scheduler_cell_params& params, + ue_repository& ues, + cell_metrics_handler& metrics_handler) : + cell_res_alloc(params.cell_res_alloc), + 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) +{ +} diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h index a7e72b521e..9e4efbef53 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h @@ -10,6 +10,7 @@ #pragma once +#include "../cell/cell_harq_manager.h" #include "../logging/scheduler_event_logger.h" #include "../policy/scheduler_policy.h" #include "../pucch_scheduling/pucch_guardbands_scheduler.h" @@ -61,6 +62,9 @@ class ue_scheduler_impl final : public ue_scheduler struct cell { cell_resource_allocator* cell_res_alloc; + /// HARQ pool for this cell. + cell_harq_manager cell_harqs; + /// PUCCH scheduler. uci_scheduler_impl uci_sched; @@ -70,13 +74,10 @@ class ue_scheduler_impl final : public ue_scheduler /// Slice scheduler. slice_scheduler slice_sched; - cell(const scheduler_ue_expert_config& expert_cfg, const ue_scheduler_cell_params& params, ue_repository& ues) : - cell_res_alloc(params.cell_res_alloc), - 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) - { - } + cell(const scheduler_ue_expert_config& expert_cfg, + const ue_scheduler_cell_params& params, + ue_repository& ues, + cell_metrics_handler& metrics_handler); }; // Helper to catch simultaneous PUCCH and PUSCH grants allocated for the same UE. @@ -84,6 +85,7 @@ class ue_scheduler_impl final : public ue_scheduler void puxch_grant_sanitizer(cell_resource_allocator& cell_alloc); const scheduler_ue_expert_config& expert_cfg; + cell_metrics_handler& metrics_handler; std::array, MAX_NOF_DU_CELLS> cells; diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index 457276bcc0..51f523b7c3 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -70,6 +70,7 @@ class base_scheduler_policy_test slice_sched.slot_indication(next_slot); res_grid.slot_indication(next_slot); + cell_harqs.slot_indication(next_slot); pdcch_alloc.slot_indication(next_slot); pucch_alloc.slot_indication(next_slot); uci_alloc.slot_indication(next_slot); @@ -119,8 +120,8 @@ class base_scheduler_policy_test { ue_ded_cell_cfg_list.push_back( std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); - ues.add_ue(std::make_unique( - ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, harq_timeout_handler})); + ues.add_ue( + std::make_unique(ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, cell_harqs})); slice_sched.add_ue(ue_req.ue_index); return ues[ue_req.ue_index]; } @@ -176,6 +177,9 @@ class base_scheduler_policy_test scheduler_harq_timeout_dummy_handler harq_timeout_handler; cell_resource_allocator res_grid{cell_cfg}; + cell_harq_manager cell_harqs{MAX_NOF_DU_UES, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; pdcch_resource_allocator_impl pdcch_alloc{cell_cfg}; pucch_allocator_impl pucch_alloc{cell_cfg, sched_cfg.ue.max_pucchs_per_slot, sched_cfg.ue.max_ul_grants_per_slot}; uci_allocator_impl uci_alloc{pucch_alloc}; diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 26125e79da..aabb0b4b9c 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -45,7 +45,7 @@ class slice_scheduler_test const ue_configuration* add_ue(const sched_ue_creation_request_message& req) { const ue_configuration* ue_cfg = test_cfg.add_ue(req); - ues.add_ue(std::make_unique(ue_creation_command{*ue_cfg, req.starts_in_fallback, harq_timeout_handler})); + ues.add_ue(std::make_unique(ue_creation_command{*ue_cfg, req.starts_in_fallback, cell_harqs})); slice_sched.add_ue(req.ue_index); return ue_cfg; } @@ -56,7 +56,10 @@ class slice_scheduler_test scheduler_harq_timeout_dummy_handler harq_timeout_handler; - ue_repository ues; + cell_harq_manager cell_harqs{MAX_NOF_DU_UES, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; + ue_repository ues; slice_scheduler slice_sched{cell_cfg, ues}; diff --git a/tests/unittests/scheduler/test_utils/dummy_test_components.h b/tests/unittests/scheduler/test_utils/dummy_test_components.h index d7bb0245f9..6a3b4b8a2c 100644 --- a/tests/unittests/scheduler/test_utils/dummy_test_components.h +++ b/tests/unittests/scheduler/test_utils/dummy_test_components.h @@ -10,6 +10,7 @@ #pragma once +#include "lib/scheduler/cell/cell_harq_manager.h" #include "lib/scheduler/logging/scheduler_metrics_ue_configurator.h" #include "lib/scheduler/pdcch_scheduling/pdcch_resource_allocator.h" #include "lib/scheduler/uci_scheduling/uci_allocator.h" @@ -164,6 +165,23 @@ class scheduler_harq_timeout_dummy_handler : public harq_timeout_handler void handle_harq_timeout(du_ue_index_t ue_index, bool is_dl) override { last_ue_idx = ue_index; } }; +class scheduler_harq_timeout_dummy_notifier : public harq_timeout_notifier +{ +public: + scheduler_harq_timeout_dummy_notifier() = default; + explicit scheduler_harq_timeout_dummy_notifier(harq_timeout_handler& handler_) : handler(&handler_) {} + + void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override + { + if (handler != nullptr) { + handler->handle_harq_timeout(ue_idx, is_dl); + } + } + +private: + harq_timeout_handler* handler = nullptr; +}; + class scheduler_ue_metrics_dummy_configurator : public sched_metrics_ue_configurator { public: diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 1ba6ff5b67..05ae3fca6e 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -105,6 +105,24 @@ bool srsran::pucch_info_match(const pucch_info& expected, const pucch_info& test return is_equal; } +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 + ///////// TEST BENCH for PUCCH scheduler ///////// // Test bench with all that is needed for the PUCCH. @@ -120,6 +138,7 @@ test_bench::test_bench(const test_bench_params& params, expert_cfg, make_custom_sched_cell_configuration_request(params.pucch_res_common, 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)}, dci_info{make_default_dci(params.n_cces, &cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common.coreset0.value())}, k0(cell_cfg.dl_cfg_common.init_dl_bwp.pdsch_common.pdsch_td_alloc_list[0].k0), max_pucchs_per_slot{max_pucchs_per_slot_}, @@ -205,8 +224,7 @@ test_bench::test_bench(const test_bench_params& params, } ue_ded_cfgs.push_back(std::make_unique(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, harq_timeout_handler})); + ues.add_ue(std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, cell_harqs})); uci_sched.add_ue(ues[ue_req.ue_index].get_pcell().cfg()); last_allocated_rnti = ue_req.crnti; last_allocated_ue_idx = main_ue_idx; @@ -243,8 +261,7 @@ void test_bench::add_ue() "UE PUCCH configuration couldn't be built"); ue_ded_cfgs.push_back(std::make_unique(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, harq_timeout_handler})); + ues.add_ue(std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, cell_harqs})); last_allocated_rnti = ue_req.crnti; } diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h index 59073bdadb..0930684415 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h @@ -127,6 +127,7 @@ class test_bench std::vector> ue_ded_cfgs; cell_resource_allocator res_grid{cell_cfg}; + cell_harq_manager cell_harqs; pdcch_dl_information dci_info; const unsigned k0; const unsigned k1{4}; diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index b836552556..f91b455849 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -85,6 +85,9 @@ struct test_bench { const cell_configuration& cell_cfg; cell_resource_allocator res_grid{cell_cfg}; + cell_harq_manager cell_harqs{MAX_NOF_DU_UES, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; pdcch_resource_allocator_impl pdcch_sch{cell_cfg}; pucch_allocator_impl pucch_alloc{cell_cfg, 31U, 32U}; uci_allocator_impl uci_alloc{pucch_alloc}; @@ -114,8 +117,7 @@ struct test_bench { } // Add UE to UE DB. - auto u = std::make_unique( - ue_creation_command{ev.next_config(), create_req.starts_in_fallback, harq_timeout_handler}); + auto u = std::make_unique(ue_creation_command{ev.next_config(), create_req.starts_in_fallback, cell_harqs}); if (ue_db.contains(create_req.ue_index)) { // UE already exists. ev.abort(); @@ -825,12 +827,11 @@ TEST_P(fallback_scheduler_head_scheduling, test_ahead_scheduling_for_srb_allocat } // Ack the HARQ processes that are waiting for ACK, otherwise the scheduler runs out of empty HARQs. - const unsigned bit_index_1_harq_only = 0U; - dl_harq_process* dl_harq = - test_ue.get_pcell().harqs.find_dl_harq_waiting_ack_slot(current_slot, bit_index_1_harq_only); - if (dl_harq != nullptr) { - static constexpr unsigned tb_idx = 0U; - dl_harq->ack_info(tb_idx, mac_harq_ack_report_status::ack, {}); + const unsigned bit_index_1_harq_only = 0U; + std::optional dl_harq = + test_ue.get_pcell().harqs.find_dl_harq(current_slot, bit_index_1_harq_only); + if (dl_harq.has_value()) { + dl_harq->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt); } } } @@ -883,8 +884,8 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T case ue_state::waiting_for_tx: { for (harq_id_t h_id = to_harq_id(0); h_id != MAX_HARQ_ID; h_id = to_harq_id(std::underlying_type_t(h_id) + 1)) { - const auto& h_dl = test_ue.get_pcell().harqs.dl_harq(h_id); - if (h_dl.is_waiting_ack()) { + std::optional h_dl = test_ue.get_pcell().harqs.dl_harq(h_id); + if (h_dl.has_value() and h_dl->is_waiting_ack()) { ongoing_h_id = h_id; break; } @@ -898,18 +899,16 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T } // Wait until the slot at which the ACK is expected and update successful and unsuccessful TX counters. case ue_state::waiting_for_ack: { - const dl_harq_process& h_dl = test_ue.get_pcell().harqs.dl_harq(ongoing_h_id); + std::optional h_dl = test_ue.get_pcell().harqs.dl_harq(ongoing_h_id); - if (h_dl.slot_ack() == sl) { + if (h_dl.has_value() and h_dl->uci_slot() == sl) { static constexpr double ack_probability = 0.5f; ack_outcome = test_rgen::bernoulli(ack_probability); if (ack_outcome) { ++successful_tx_cnt; state = ue_state::reset_harq; } else { - const unsigned tb_index_only_1_tb_supported = 0U; - if (h_dl.tb(tb_index_only_1_tb_supported).nof_retxs != - h_dl.tb(tb_index_only_1_tb_supported).max_nof_harq_retxs) { + if (h_dl->nof_retxs() != h_dl->max_nof_retxs()) { state = ue_state::waiting_for_retx; } else { ++unsuccessful_tx_cnt; @@ -921,11 +920,11 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T } // Wait for UE to re-transmit the SRBO / SRB1 related PDSCH case ue_state::waiting_for_retx: { - const dl_harq_process& h_dl = test_ue.get_pcell().harqs.dl_harq(ongoing_h_id); - if (h_dl.empty()) { + std::optional h_dl = test_ue.get_pcell().harqs.dl_harq(ongoing_h_id); + if (not h_dl.has_value() or h_dl->empty()) { ++missed_srb_cnt; state = ue_state::reset_harq; - } else if (h_dl.is_waiting_ack()) { + } else if (h_dl->is_waiting_ack()) { state = ue_state::waiting_for_ack; } break; @@ -946,12 +945,11 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T void ack_harq_process(slot_point sl) { // Ack the HARQ processes that are waiting for ACK, otherwise the scheduler runs out of empty HARQs. - const unsigned bit_index_1_harq_only = 0U; - dl_harq_process* dl_harq = test_ue.get_pcell().harqs.find_dl_harq_waiting_ack_slot(sl, bit_index_1_harq_only); - if (dl_harq != nullptr) { - srsran_assert(dl_harq->id == ongoing_h_id, "HARQ process mismatch"); - static constexpr unsigned tb_idx = 0U; - dl_harq->ack_info(tb_idx, ack_outcome ? mac_harq_ack_report_status::ack : mac_harq_ack_report_status::nack, {}); + const unsigned bit_index_1_harq_only = 0U; + std::optional dl_harq = test_ue.get_pcell().harqs.find_dl_harq(sl, bit_index_1_harq_only); + if (dl_harq.has_value()) { + srsran_assert(dl_harq->id() == ongoing_h_id, "HARQ process mismatch"); + dl_harq->dl_ack_info(ack_outcome ? mac_harq_ack_report_status::ack : mac_harq_ack_report_status::nack, {}); } } @@ -1076,11 +1074,10 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public for (uint8_t h_id_idx = 0; h_id_idx != std::underlying_type_t(MAX_HARQ_ID); ++h_id_idx) { harq_id_t h_id = to_harq_id(h_id_idx); - dl_harq_process& h_dl = test_ue.get_pcell().harqs.dl_harq(h_id); - if (h_dl.is_waiting_ack() and h_dl.tb(0).nof_retxs == 0 and h_dl.slot_tx() == sl) { - const unsigned tb_idx = 0U; - const unsigned tx_bytes = h_dl.last_alloc_params().tb[tb_idx]->tbs_bytes > MAX_MAC_SDU_SUBHEADER_SIZE - ? h_dl.last_alloc_params().tb[tb_idx]->tbs_bytes - MAX_MAC_SDU_SUBHEADER_SIZE + std::optional h_dl = test_ue.get_pcell().harqs.dl_harq(h_id); + if (h_dl.has_value() and h_dl->is_waiting_ack() and h_dl->nof_retxs() == 0 and h_dl->pdsch_slot() == sl) { + const unsigned tx_bytes = h_dl->get_grant_params().tbs_bytes > MAX_MAC_SDU_SUBHEADER_SIZE + ? h_dl->get_grant_params().tbs_bytes - MAX_MAC_SDU_SUBHEADER_SIZE : 0U; if (pending_srb1_bytes > tx_bytes) { pending_srb1_bytes -= tx_bytes; @@ -1090,7 +1087,7 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public test_logger.debug("rnti={}, slot={}: RLC buffer state update for h_id={} with {} bytes", test_ue.crnti, sl, - to_harq_id(h_dl.id), + to_harq_id(h_dl->id()), pending_srb1_bytes); parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false); latest_rlc_update_slot.emplace(sl); @@ -1117,30 +1114,30 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public for (uint8_t h_id_idx = 0; h_id_idx != std::underlying_type_t(MAX_HARQ_ID); ++h_id_idx) { harq_id_t h_id = to_harq_id(h_id_idx); - auto& h_dl = test_ue.get_pcell().harqs.dl_harq(h_id); - if (h_dl.is_waiting_ack() and h_dl.tb(0).nof_retxs == 0 and h_dl.slot_tx() == sl) { - const unsigned tb_idx = 0U; - const unsigned tx_bytes = h_dl.last_alloc_params().tb[tb_idx]->tbs_bytes > MAX_MAC_SDU_SUBHEADER_SIZE - ? h_dl.last_alloc_params().tb[tb_idx]->tbs_bytes - MAX_MAC_SDU_SUBHEADER_SIZE + std::optional h_dl = test_ue.get_pcell().harqs.dl_harq(h_id); + if (h_dl.has_value() and h_dl->is_waiting_ack() and h_dl->nof_retxs() == 0 and h_dl->pdsch_slot() == sl) { + const unsigned tx_bytes = h_dl->get_grant_params().tbs_bytes > MAX_MAC_SDU_SUBHEADER_SIZE + ? h_dl->get_grant_params().tbs_bytes - MAX_MAC_SDU_SUBHEADER_SIZE : 0U; pending_srb1_bytes > tx_bytes ? pending_srb1_bytes -= tx_bytes : pending_srb1_bytes = 0U; test_logger.debug("rnti={}, slot={}: RLC buffer state update for h_id={} with {} bytes", test_ue.crnti, sl, - to_harq_id(h_dl.id), + to_harq_id(h_dl->id()), pending_srb1_bytes); parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false); } // Check if any HARQ process with pending transmissions is re-set by the scheduler. - if (latest_harq_states[h_id_idx] == h_state::pending_retx and test_ue.get_pcell().harqs.dl_harq(h_id).empty()) { + if (latest_harq_states[h_id_idx] == h_state::pending_retx and + not test_ue.get_pcell().harqs.dl_harq(h_id).has_value()) { ++missing_retx; } // Save HARQ process latest. - if (test_ue.get_pcell().harqs.dl_harq(h_id).empty()) { + if (not test_ue.get_pcell().harqs.dl_harq(h_id).has_value()) { latest_harq_states[h_id_idx] = h_state::empty; - } else if (test_ue.get_pcell().harqs.dl_harq(h_id).is_waiting_ack()) { + } else if (test_ue.get_pcell().harqs.dl_harq(h_id)->is_waiting_ack()) { latest_harq_states[h_id_idx] = h_state::waiting_ack; } else { latest_harq_states[h_id_idx] = h_state::pending_retx; @@ -1154,17 +1151,16 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public void ack_harq_process(slot_point sl) { // Ack the HARQ processes that are waiting for ACK, otherwise the scheduler runs out of empty HARQs. - const unsigned bit_index_1_harq_only = 0U; - dl_harq_process* dl_harq = test_ue.get_pcell().harqs.find_dl_harq_waiting_ack_slot(sl, bit_index_1_harq_only); - if (dl_harq != nullptr) { - static constexpr unsigned tb_idx = 0U; - static constexpr double ack_probability = 0.5f; - const bool ack = test_rgen::bernoulli(ack_probability); - dl_harq->ack_info(tb_idx, ack ? mac_harq_ack_report_status::ack : mac_harq_ack_report_status::nack, {}); + const unsigned bit_index_1_harq_only = 0U; + std::optional dl_harq = test_ue.get_pcell().harqs.find_dl_harq(sl, bit_index_1_harq_only); + if (dl_harq.has_value()) { + static constexpr double ack_probability = 0.5f; + const bool ack = test_rgen::bernoulli(ack_probability); + dl_harq->dl_ack_info(ack ? mac_harq_ack_report_status::ack : mac_harq_ack_report_status::nack, {}); test_logger.debug("Slot={}, rnti={}: acking process h_id={} with {}", sl, test_ue.crnti, - to_harq_id(dl_harq->id), + to_harq_id(dl_harq->id()), ack ? "ACK" : "NACK"); } } @@ -1271,11 +1267,11 @@ class ul_fallback_scheduler_tester : public base_fallback_tester, for (uint8_t h_id_idx = 0; h_id_idx != std::underlying_type_t(MAX_HARQ_ID); ++h_id_idx) { harq_id_t h_id = to_harq_id(h_id_idx); - auto& h_ul = test_ue.get_pcell().harqs.ul_harq(h_id); - if (h_ul.is_waiting_ack() and h_ul.slot_ack() == sl) { + std::optional h_ul = test_ue.get_pcell().harqs.ul_harq(h_id); + if (h_ul.has_value() and h_ul->is_waiting_ack() and h_ul->pusch_slot() == sl) { test_ue.pending_ul_newtx_bytes(); - bool ack = ack_harq_process(sl, h_ul); - const unsigned delivered_bytes = ack ? h_ul.last_tx_params().tbs_bytes - 10U : 0U; + bool ack = ack_harq_process(sl, *h_ul); + const unsigned delivered_bytes = ack ? h_ul->get_grant_params().tbs_bytes - 10U : 0U; buffer_bytes > delivered_bytes ? buffer_bytes -= delivered_bytes : buffer_bytes = 0U; test_logger.info( "rnti={}, slot={}: generating BSR indication with {} bytes", test_ue.crnti, sl, buffer_bytes); @@ -1284,17 +1280,17 @@ class ul_fallback_scheduler_tester : public base_fallback_tester, } } - bool ack_harq_process(slot_point sl, ul_harq_process& h_ul) + bool ack_harq_process(slot_point sl, ul_harq_process_handle h_ul) { static constexpr double ack_probability = 0.5f; // NOTE: to simply the generation of SRB1 buffer, we only allow max 3 NACKs. - const bool ack = h_ul.tb().nof_retxs <= 3U ? test_rgen::bernoulli(ack_probability) : true; - h_ul.crc_info(ack); + const bool ack = h_ul.nof_retxs() <= 3U ? test_rgen::bernoulli(ack_probability) : true; + h_ul.ul_crc_info(ack); test_logger.info("Slot={}, rnti={}: ACKing process h_id={} with {}", sl, test_ue.crnti, - to_harq_id(h_ul.id), + to_harq_id(h_ul.id()), ack ? "ACK" : "NACK"); return ack; } @@ -1447,11 +1443,11 @@ TEST_F(fallback_sched_ue_w_out_pucch_cfg, when_srb0_is_retx_ed_only_pucch_common } // NACK the HARQ processes that are waiting for ACK to trigger a retransmissions. - const unsigned bit_index_1_harq_only = 0U; - dl_harq_process* dl_harq = u.get_pcell().harqs.find_dl_harq_waiting_ack_slot(current_slot, bit_index_1_harq_only); - if (dl_harq != nullptr) { - static constexpr unsigned tb_idx = 0U; - dl_harq->ack_info(tb_idx, mac_harq_ack_report_status::nack, {}); + const unsigned bit_index_1_harq_only = 0U; + std::optional dl_harq = + u.get_pcell().harqs.find_dl_harq(current_slot, bit_index_1_harq_only); + if (dl_harq.has_value()) { + dl_harq->dl_ack_info(mac_harq_ack_report_status::nack, {}); } } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp index 5af445c304..5fc6d3d766 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp @@ -78,11 +78,12 @@ class ue_cell_tester : public ::testing::Test cell_configuration cell_cfg; serving_cell_config serv_cell_cfg; ue_cell_configuration ue_cc_cfg; + cell_harq_manager cell_harqs{1, MAX_NOF_HARQS}; }; TEST_F(ue_cell_tester, when_dl_nof_prb_allocated_increases_estimated_dl_rate_increases) { - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, {}}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; double current_rate = 0; @@ -107,7 +108,7 @@ TEST_F(ue_cell_tester, when_mcs_increases_estimated_dl_rate_increases) // Maximum MCS value for 64QAM MCS table. const sch_mcs_index max_mcs = 28; - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, {}}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; double current_rate = 0; @@ -131,7 +132,7 @@ TEST_F(ue_cell_tester, when_mcs_increases_estimated_dl_rate_increases) TEST_F(ue_cell_tester, when_ul_nof_prb_allocated_increases_estimated_ul_rate_increases) { - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, {}}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; double current_rate = 0; @@ -156,7 +157,7 @@ TEST_F(ue_cell_tester, when_mcs_increases_estimated_ul_rate_increases) // Maximum MCS value for 64QAM MCS table. const sch_mcs_index max_mcs = 28; - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, {}}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; double current_rate = 0; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp index 19d530cbdb..ffcde2a897 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp @@ -25,6 +25,9 @@ class ue_configuration_test : public ::testing::Test scheduler_harq_timeout_dummy_handler harq_timeout_handler; cell_common_configuration_list cell_cfg_db; + cell_harq_manager cell_harqs{1, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; }; TEST_F(ue_configuration_test, configuration_valid_on_creation) @@ -74,7 +77,7 @@ TEST_F(ue_configuration_test, when_reconfiguration_is_received_then_ue_updates_l // Test Preamble. cell_cfg_db.emplace(to_du_cell_index(0), std::make_unique(sched_cfg, msg)); ue_configuration ue_ded_cfg{ue_create_msg.ue_index, ue_create_msg.crnti, cell_cfg_db, ue_create_msg.cfg}; - ue u{ue_creation_command{ue_ded_cfg, ue_create_msg.starts_in_fallback, harq_timeout_handler}}; + ue u{ue_creation_command{ue_ded_cfg, ue_create_msg.starts_in_fallback, cell_harqs}}; // Pass Reconfiguration to UE with an new Logical Channel. sched_ue_reconfiguration_message recfg{}; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 26a0f62236..6daf9b60a3 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -71,6 +71,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam logger.set_context(current_slot.sfn(), current_slot.slot_index()); res_grid.slot_indication(current_slot); + cell_harqs.slot_indication(current_slot); pdcch_alloc.slot_indication(current_slot); pucch_alloc.slot_indication(current_slot); uci_alloc.slot_indication(current_slot); @@ -107,8 +108,8 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam ue& add_ue(const sched_ue_creation_request_message& ue_creation_req) { auto ev = cfg_mng.add_ue(ue_creation_req); - ues.add_ue(std::make_unique( - ue_creation_command{ev.next_config(), ue_creation_req.starts_in_fallback, harq_timeout_handler})); + ues.add_ue( + std::make_unique(ue_creation_command{ev.next_config(), ue_creation_req.starts_in_fallback, cell_harqs})); slice_ues.emplace(ue_creation_req.ue_index, ues[ue_creation_req.ue_index]); for (const auto& lc_cfg : *ue_creation_req.cfg.lc_config_list) { slice_ues[ue_creation_req.ue_index].add_logical_channel(lc_cfg.lcid, lc_cfg.lc_group); @@ -127,6 +128,9 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam sched_config_manager cfg_mng{scheduler_config{sched_cfg, mac_notif, metrics_notif}}; const cell_configuration& cell_cfg; + cell_harq_manager cell_harqs{MAX_NOF_DU_UES, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; cell_resource_allocator res_grid{cell_cfg}; pdcch_resource_allocator_impl pdcch_alloc{cell_cfg}; @@ -167,7 +171,7 @@ TEST_P(ue_grid_allocator_tester, ue_pdsch_grant grant{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -192,7 +196,7 @@ TEST_P(ue_grid_allocator_tester, when_using_non_fallback_dci_format_use_mcs_tabl // SearchSpace#2 uses non-fallback DCI format hence the MCS table set in dedicated PDSCH configuration must be used. const ue_pdsch_grant grant{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -215,7 +219,7 @@ TEST_P(ue_grid_allocator_tester, allocates_pdsch_restricted_to_recommended_max_n const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -240,7 +244,7 @@ TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_n const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -265,7 +269,7 @@ TEST_P(ue_grid_allocator_tester, does_not_allocate_pusch_with_all_remaining_rbs_ const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = u1.pending_ul_newtx_bytes()}; const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), @@ -292,13 +296,13 @@ TEST_P(ue_grid_allocator_tester, no_two_pdschs_are_allocated_in_same_slot_for_a_ // First PDSCH grant for the UE. const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; // Second PDSCH grant for the UE. const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { @@ -325,13 +329,13 @@ TEST_P(ue_grid_allocator_tester, no_two_puschs_are_allocated_in_same_slot_for_a_ // First PUSCH grant for the UE. const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; // Second PUSCH grant for the UE. const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { @@ -358,7 +362,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in // First PUSCH grant for the UE. const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until( @@ -370,7 +374,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_puschs_for_a_ue_are_allocated_in_in // Second PUSCH grant for the UE trying to allocate PUSCH in a slot previous to grant1. const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_FALSE(run_until([&]() { @@ -390,7 +394,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_in // First PDSCH grant for the UE. const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -403,7 +407,7 @@ TEST_P(ue_grid_allocator_tester, consecutive_pdschs_for_a_ue_are_allocated_in_in // Second PDSCH grant in the same slot for the UE. const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -425,7 +429,7 @@ TEST_P(ue_grid_allocator_tester, // First PDSCH grant for the UE. const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -438,7 +442,7 @@ TEST_P(ue_grid_allocator_tester, // Second PDSCH grant in the same slot for the UE. const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -465,7 +469,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga // First PDSCH grant for the UE. const ue_pdsch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -481,7 +485,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga // Next PDSCH grant to be allocated. const ue_pdsch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE( @@ -507,7 +511,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga // First PUSCH grant for the UE. const ue_pusch_grant grant1{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { @@ -525,7 +529,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga // Second PUSCH grant for the UE. const ue_pusch_grant grant2{.user = &slice_ues[u.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(1), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = nof_bytes_to_schedule}; ASSERT_TRUE(run_until( @@ -564,14 +568,14 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_dl_rbs_are_alloca static const unsigned sched_bytes = 20U; const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = sched_bytes}; // Since UE dedicated SearchSpace is a UE specific SearchSpace (Not CSS). Entire BWP CRBs can be used for allocation. const unsigned total_crbs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(); const ue_pdsch_grant grant2{.user = &slice_ues[u2.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = sched_bytes}; ASSERT_TRUE(run_until([&]() { @@ -613,11 +617,11 @@ TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_ul_rbs_are_alloca slot_point pusch_to_alloc_slot = get_next_ul_slot(current_slot); const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; const ue_pusch_grant grant2{.user = &slice_ues[u2.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; ASSERT_TRUE(run_until([&]() { @@ -666,7 +670,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -693,7 +697,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -720,7 +724,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -749,7 +753,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -801,7 +805,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_wit const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = sched_bytes, .max_nof_rbs = max_nof_rbs_to_schedule}; @@ -826,7 +830,7 @@ TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pusch_wit const ue_pusch_grant grant1{.user = &slice_ues[u1.ue_index], .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), + .h_id = INVALID_HARQ_ID, .recommended_nof_bytes = recommended_nof_bytes_to_schedule, .max_nof_rbs = max_nof_rbs_to_schedule}; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp index b08dc846bd..125257dea5 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp @@ -42,9 +42,8 @@ class ue_harq_link_adaptation_test : public ::testing::Test ue_creation_req.cfg.lc_config_list->push_back(config_helpers::create_default_logical_channel_config(lcid)); } ue_ded_cfg.emplace(ue_creation_req.ue_index, ue_creation_req.crnti, cell_cfg_list, ue_creation_req.cfg); - ue_ptr = std::make_unique( - ue_creation_command{*ue_ded_cfg, ue_creation_req.starts_in_fallback, harq_timeout_handler}); - ue_cc = &ue_ptr->get_cell(to_ue_cell_index(0)); + ue_ptr = std::make_unique(ue_creation_command{*ue_ded_cfg, ue_creation_req.starts_in_fallback, cell_harqs}); + ue_cc = &ue_ptr->get_cell(to_ue_cell_index(0)); } void run_slot() @@ -53,10 +52,12 @@ class ue_harq_link_adaptation_test : public ::testing::Test ue_ptr->slot_indication(next_slot); } - void handle_harq_newtx(harq_id_t harq_id, unsigned k1 = 4) + dl_harq_process_handle handle_harq_newtx(unsigned k1 = 4) { const search_space_info& ss = ue_cc->cfg().search_space(to_search_space_id(2)); + dl_harq_process_handle h_dl = ue_cc->harqs.alloc_dl_harq(next_slot, k1, 4, 0).value(); + // Create dummy PDSCH grant. const pdsch_codeword cw{ sch_mcs_description{modulation_scheme::QAM256, 0.9}, sch_mcs_index{5}, pdsch_mcs_table::qam64, 0, 128}; @@ -72,12 +73,13 @@ class ue_harq_link_adaptation_test : public ::testing::Test false, search_space_set_type::ue_specific, dci_dl_format::f1_1, - harq_id, + h_dl.id(), std::nullopt}; - ue_cc->harqs.dl_harq(harq_id).new_tx(next_slot, k1, 4, 0, 15, 2); - dl_harq_sched_context ctxt{dci_dl_rnti_config_type::c_rnti_f1_1, pdsch.codewords[0].mcs_index}; - ue_cc->harqs.dl_harq(harq_id).save_alloc_params(ctxt, pdsch); + dl_harq_alloc_context ctxt{dci_dl_rnti_config_type::c_rnti_f1_1, pdsch.codewords[0].mcs_index, std::nullopt, 15}; + h_dl.save_grant_params(ctxt, pdsch); + + return h_dl; } const scheduler_expert_config sched_cfg = config_helpers::make_default_scheduler_expert_config(); @@ -85,6 +87,9 @@ class ue_harq_link_adaptation_test : public ::testing::Test cell_configuration* cell_cfg = nullptr; std::optional ue_ded_cfg; scheduler_harq_timeout_dummy_handler harq_timeout_handler; + cell_harq_manager cell_harqs{1, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; srslog::basic_logger& logger; @@ -101,12 +106,9 @@ TEST_F(ue_harq_link_adaptation_test, harq_not_retx_when_cqi_drops_below_threshol csi.first_tb_wideband_cqi = cqi_value{15}; ue_cc->handle_csi_report(csi); - static const harq_id_t harq_id = to_harq_id(0); - handle_harq_newtx(harq_id); + dl_harq_process_handle h = handle_harq_newtx(); - const dl_harq_process& h = ue_cc->harqs.dl_harq(harq_id); - - while (h.slot_ack() != next_slot) { + while (h.uci_slot() != next_slot) { // Run until ACK slot. run_slot(); } @@ -116,10 +118,10 @@ TEST_F(ue_harq_link_adaptation_test, harq_not_retx_when_cqi_drops_below_threshol ue_cc->handle_csi_report(csi); // Action: NACK the HARQ. - ue_cc->harqs.dl_harq(harq_id).ack_info(0, mac_harq_ack_report_status::nack, std::nullopt); + h.dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt); // Result: There should not be retx for HARQ. - ASSERT_EQ(ue_cc->harqs.find_pending_dl_retx(), nullptr) << "HARQ must not be retransmitted due to drop in CQI"; + ASSERT_EQ(ue_cc->harqs.find_pending_dl_retx(), std::nullopt) << "HARQ must not be retransmitted due to drop in CQI"; } TEST_F(ue_harq_link_adaptation_test, harq_not_retx_when_ri_drops_below_threshold) @@ -130,12 +132,9 @@ TEST_F(ue_harq_link_adaptation_test, harq_not_retx_when_ri_drops_below_threshold csi.ri = 2; ue_cc->handle_csi_report(csi); - static const harq_id_t harq_id = to_harq_id(0); - handle_harq_newtx(harq_id); - - const dl_harq_process& h = ue_cc->harqs.dl_harq(harq_id); + dl_harq_process_handle h = handle_harq_newtx(); - while (h.slot_ack() != next_slot) { + while (h.uci_slot() != next_slot) { // Run until ACK slot. run_slot(); } @@ -145,8 +144,8 @@ TEST_F(ue_harq_link_adaptation_test, harq_not_retx_when_ri_drops_below_threshold ue_cc->handle_csi_report(csi); // Action: NACK the HARQ. - ue_cc->harqs.dl_harq(harq_id).ack_info(0, mac_harq_ack_report_status::nack, std::nullopt); + h.dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt); // Result: There should not be retx for HARQ. - ASSERT_EQ(ue_cc->harqs.find_pending_dl_retx(), nullptr) << "HARQ must not be retransmitted due to drop in RI"; + ASSERT_EQ(ue_cc->harqs.find_pending_dl_retx(), std::nullopt) << "HARQ must not be retransmitted due to drop in RI"; } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp index ed48c2f7a5..b198e4204f 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_pxsch_alloc_param_candidate_searcher_test.cpp @@ -39,9 +39,8 @@ class ue_pxsch_alloc_param_candidate_searcher_test : public ::testing::Test ue_creation_req.cfg.lc_config_list->push_back(config_helpers::create_default_logical_channel_config(lcid)); } ue_ded_cfg.emplace(ue_creation_req.ue_index, ue_creation_req.crnti, cell_cfg_list, ue_creation_req.cfg); - ue_ptr = std::make_unique( - ue_creation_command{*ue_ded_cfg, ue_creation_req.starts_in_fallback, harq_timeout_handler}); - ue_cc = &ue_ptr->get_cell(to_ue_cell_index(0)); + ue_ptr = std::make_unique(ue_creation_command{*ue_ded_cfg, ue_creation_req.starts_in_fallback, cell_harqs}); + ue_cc = &ue_ptr->get_cell(to_ue_cell_index(0)); } slot_point get_next_ul_slot(slot_point start_slot) @@ -60,6 +59,9 @@ class ue_pxsch_alloc_param_candidate_searcher_test : public ::testing::Test cell_common_configuration_list cell_cfg_list; const cell_configuration& cell_cfg; scheduler_harq_timeout_dummy_handler harq_timeout_handler; + cell_harq_manager cell_harqs{1, + MAX_NOF_HARQS, + std::make_unique(harq_timeout_handler)}; std::optional ue_ded_cfg; srslog::basic_logger& logger; From f65c1f7d66d5b5cd7bab09451d51ea7811d4bddd Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 30 Aug 2024 18:15:43 +0200 Subject: [PATCH 406/407] sched: improvements on CRC info handling in HARQ --- lib/scheduler/cell/cell_harq_manager.cpp | 7 ++- lib/scheduler/cell/cell_harq_manager.h | 15 ++--- lib/scheduler/slicing/slice_ue_repository.cpp | 9 +-- lib/scheduler/ue_scheduling/ue.cpp | 9 +-- lib/scheduler/ue_scheduling/ue_cell.cpp | 20 +++---- .../ue_scheduling/ue_fallback_scheduler.h | 1 + .../ue_pusch_alloc_param_candidate_searcher.h | 10 ++-- .../ue_scheduling/ue_scheduler_impl.cpp | 2 +- .../scheduler/cell/cell_harq_manager_test.cpp | 56 ++++++++++--------- .../ue_scheduling/fallback_scheduler_test.cpp | 10 ++-- 10 files changed, 61 insertions(+), 78 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 429a0a9065..04587bcef0 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -854,7 +854,8 @@ std::optional unique_ue_harq_entity::find_ul_harq_waitin return ul_harq_process_handle(cell_harq_mgr->ul, *h); } -std::optional unique_ue_harq_entity::find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx) +std::optional unique_ue_harq_entity::find_dl_harq_waiting_ack(slot_point uci_slot, + uint8_t harq_bit_idx) { if (cell_harq_mgr->dl.alloc_hist != nullptr) { // NTN mode. @@ -871,7 +872,7 @@ std::optional unique_ue_harq_entity::find_dl_harq(slot_p return std::nullopt; } -std::optional unique_ue_harq_entity::find_ul_harq(slot_point pusch_slot) +std::optional unique_ue_harq_entity::find_ul_harq_waiting_ack(slot_point pusch_slot) { if (cell_harq_mgr->ul.alloc_hist != nullptr) { // NTN mode. @@ -901,7 +902,7 @@ void unique_ue_harq_entity::uci_sched_failed(slot_point uci_slot) } } -unsigned unique_ue_harq_entity::total_ul_bytes_waiting_crc() const +unsigned unique_ue_harq_entity::total_ul_bytes_waiting_ack() const { if (cell_harq_mgr->ul.is_ntn_mode()) { return cell_harq_mgr->ul.alloc_hist->sum_pending_ul_tbs(ue_index); diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 2d7ba50ea0..0aaec54590 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -503,16 +503,16 @@ class unique_ue_harq_entity std::optional find_dl_harq_waiting_ack(); std::optional find_ul_harq_waiting_ack(); - /// Fetch active DL HARQ process based on HARQ-ACK UCI slot and HARQ bit index. + /// Fetch a DL HARQ process expecting ACK info based on HARQ-ACK UCI slot and HARQ bit index. /// \param[in] uci_slot Slot when the UCI is to be received. /// \param[in] harq_bit_idx Bit index of the HARQ-ACK in the UCI indication. /// \return Active DL HARQ process with matching UCI slot and HARQ bit index, if found. - std::optional find_dl_harq(slot_point uci_slot, uint8_t harq_bit_idx); + std::optional find_dl_harq_waiting_ack(slot_point uci_slot, uint8_t harq_bit_idx); /// Fetch active UL HARQ process based on slot when its PUSCH was transmitted. /// \param[in] pusch_slot Slot when the PUSCH was transmitted. /// \return Active UL HARQ process with matching PUSCH slot, if found. - std::optional find_ul_harq(slot_point pusch_slot); + std::optional find_ul_harq_waiting_ack(slot_point pusch_slot); /// \brief The UCI scheduling associated with a given slot was cancelled. The associated DL HARQs will be NACKed, and /// won't expect further UCIs. @@ -520,13 +520,8 @@ class unique_ue_harq_entity /// This function can be called for instance when there is an error indication coming from lower layers. void uci_sched_failed(slot_point uci_slot); - unsigned ntn_get_tbs_pending_crcs() const - { - // TODO - return 0; - } - - unsigned total_ul_bytes_waiting_crc() const; + /// Determines the sum of the number of bytes that are in active UL HARQ processes. + unsigned total_ul_bytes_waiting_ack() const; private: dl_harq_ent_impl& get_dl_ue() { return cell_harq_mgr->dl.ues[ue_index]; } diff --git a/lib/scheduler/slicing/slice_ue_repository.cpp b/lib/scheduler/slicing/slice_ue_repository.cpp index a83dbc49d4..3dd7638d9d 100644 --- a/lib/scheduler/slicing/slice_ue_repository.cpp +++ b/lib/scheduler/slicing/slice_ue_repository.cpp @@ -80,14 +80,7 @@ unsigned slice_ue::pending_ul_newtx_bytes() const if (pending_bytes == 0) { break; } - unsigned harq_bytes = 0; - for (unsigned i = 0; i != ue_cc.harqs.nof_ul_harqs(); ++i) { - std::optional h_ul = ue_cc.harqs.ul_harq(to_harq_id(i)); - if (h_ul.has_value()) { - harq_bytes += h_ul->get_grant_params().tbs_bytes; - } - } - harq_bytes += ue_cc.harqs.ntn_get_tbs_pending_crcs(); + unsigned harq_bytes = ue_cc.harqs.total_ul_bytes_waiting_ack(); pending_bytes -= std::min(pending_bytes, harq_bytes); } diff --git a/lib/scheduler/ue_scheduling/ue.cpp b/lib/scheduler/ue_scheduling/ue.cpp index 84cf7b0ced..8cb39af7a3 100644 --- a/lib/scheduler/ue_scheduling/ue.cpp +++ b/lib/scheduler/ue_scheduling/ue.cpp @@ -147,14 +147,7 @@ unsigned ue::pending_ul_newtx_bytes() const if (pending_bytes == 0) { break; } - unsigned harq_bytes = 0; - for (unsigned i = 0; i != ue_cc->harqs.nof_ul_harqs(); ++i) { - std::optional h_ul = ue_cc->harqs.ul_harq(to_harq_id(i)); - if (h_ul.has_value()) { - harq_bytes += h_ul->get_grant_params().tbs_bytes; - } - } - harq_bytes += ue_cc->harqs.ntn_get_tbs_pending_crcs(); + unsigned harq_bytes = ue_cc->harqs.total_ul_bytes_waiting_ack(); pending_bytes -= std::min(pending_bytes, harq_bytes); } diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index 940f6e1788..38323f2d7d 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -102,7 +102,7 @@ std::optional ue_cell::handle_dl_ack_info(s unsigned harq_bit_idx, std::optional pucch_snr) { - std::optional h_dl = harqs.find_dl_harq(uci_slot, harq_bit_idx); + std::optional h_dl = harqs.find_dl_harq_waiting_ack(uci_slot, harq_bit_idx); if (not h_dl.has_value()) { logger.warning("rnti={}: Discarding ACK info. Cause: DL HARQ for uci slot={} not found.", rnti(), uci_slot); return std::nullopt; @@ -232,18 +232,12 @@ grant_prbs_mcs ue_cell::required_ul_prbs(const pusch_time_domain_resource_alloca int ue_cell::handle_crc_pdu(slot_point pusch_slot, const ul_crc_pdu_indication& crc_pdu) { // Find UL HARQ with matching PUSCH slot. - std::optional h_ul = harqs.ul_harq(crc_pdu.harq_id); - if (not h_ul.has_value()) { - logger.warning("rnti={} h_id={}: Discarding CRC. Cause: UL HARQ process is not active", rnti(), crc_pdu.harq_id); - return -1; - } - if (h_ul->pusch_slot() != pusch_slot) { - logger.warning( - "rnti={} h_id={}: Discarding CRC. Cause: UL HARQ process was expecting a CRC at a different slot ({}!={})", - rnti(), - crc_pdu.harq_id, - pusch_slot, - h_ul->pusch_slot()); + std::optional h_ul = harqs.find_ul_harq_waiting_ack(pusch_slot); + if (not h_ul.has_value() or h_ul->id() != crc_pdu.harq_id) { + logger.warning("rnti={} h_id={}: Discarding CRC. Cause: UL HARQ process is not expecting CRC for PUSCH slot {}", + rnti(), + crc_pdu.harq_id, + pusch_slot); return -1; } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index d9531a2317..7758fba092 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -166,6 +166,7 @@ class ue_fallback_scheduler const pusch_time_domain_resource_allocation& pusch_td, std::optional h_ul_retx); + /// \return A pair with the number of SRB bytes allocated and which DL HARQ process was used. std::pair fill_dl_srb_grant(ue& u, slot_point pdsch_slot, std::optional h_dl, diff --git a/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h b/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h index 1959b4e0fd..bf9d4c5ab1 100644 --- a/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h +++ b/lib/scheduler/ue_scheduling/ue_pusch_alloc_param_candidate_searcher.h @@ -153,12 +153,12 @@ class ue_pusch_alloc_param_candidate_searcher }; /// Create a searcher for UE PUSCH parameters. - ue_pusch_alloc_param_candidate_searcher(const ue& ue_ref_, - du_cell_index_t cell_index, + ue_pusch_alloc_param_candidate_searcher(const ue& ue_ref_, + du_cell_index_t cell_index, const std::optional& ul_harq_, - slot_point pdcch_slot_, - span slots_with_no_pusch_space_, - slot_point pusch_slot_) : + slot_point pdcch_slot_, + span slots_with_no_pusch_space_, + slot_point pusch_slot_) : ue_ref(ue_ref_), ue_cc(ue_ref.find_cell(cell_index)), slots_with_no_pusch_space(slots_with_no_pusch_space_), diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index d79c9ce45e..0fd5443e8c 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -108,7 +108,7 @@ void ue_scheduler_impl::update_harq_pucch_counter(cell_resource_allocator& cell_ // expecting to be acknowledged on the same slot. for (unsigned harq_bit_idx = 0; harq_bit_idx != nof_harqs_per_rnti_per_slot; ++harq_bit_idx) { std::optional h_dl = - user->get_pcell().harqs.find_dl_harq(slot_alloc.slot, harq_bit_idx); + user->get_pcell().harqs.find_dl_harq_waiting_ack(slot_alloc.slot, harq_bit_idx); if (not h_dl.has_value() or not h_dl->is_waiting_ack()) { logger.warning( "ue={} rnti={}: No DL HARQ process with state waiting-for-ack found at slot={} for harq-bit-index={}", diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index 89a3105bec..0a8f6a150e 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -296,7 +296,7 @@ TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_grant_params_h ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); ASSERT_EQ(h_dl.get_grant_params().rbs.type1(), pdsch_info.rbs.type1()); ASSERT_EQ(h_dl.get_grant_params().dci_cfg_type, dci_dl_rnti_config_type::c_rnti_f1_0); - ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_crc()); + ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_ack()); } TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) @@ -309,7 +309,7 @@ TEST_F(single_harq_process_test, positive_ack_sets_harq_to_empty) ASSERT_FALSE(h_ul.is_waiting_ack()); ASSERT_FALSE(h_ul.has_pending_retx()); - ASSERT_EQ(harq_ent.total_ul_bytes_waiting_crc(), 0); + ASSERT_EQ(harq_ent.total_ul_bytes_waiting_ack(), 0); } TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) @@ -317,7 +317,7 @@ TEST_F(single_harq_process_test, negative_ack_sets_harq_to_pending_retx) ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_handle::status_update::nacked); ASSERT_FALSE(h_dl.is_waiting_ack()); ASSERT_TRUE(h_dl.has_pending_retx()); - ASSERT_EQ(harq_ent.find_ul_harq(current_slot + k2), h_ul); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(current_slot + k2), h_ul); ASSERT_EQ(h_ul.ul_crc_info(false), 0); ASSERT_FALSE(h_ul.is_waiting_ack()); ASSERT_TRUE(h_ul.has_pending_retx()); @@ -677,8 +677,8 @@ TEST_F(single_ue_harq_entity_test, when_max_retxs_reached_then_harq_entity_does_ ASSERT_TRUE(h_dl.has_value()); ASSERT_TRUE(h_ul.has_value()); for (unsigned i = 0; i != max_retxs; ++i) { - ASSERT_EQ(harq_ent.find_dl_harq(current_slot + k1, 0), h_dl); - ASSERT_EQ(harq_ent.find_ul_harq(current_slot + k2), h_ul); + ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(current_slot + k1, 0), h_dl); + ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(current_slot + k2), h_ul); ASSERT_EQ(h_dl.value().dl_ack_info(mac_harq_ack_report_status::nack, 5), dl_harq_process_handle::status_update::nacked); ASSERT_EQ(h_ul.value().ul_crc_info(false), 0); @@ -744,15 +744,15 @@ TEST_P(single_ue_harq_entity_2_bits_tester, handle_pucchs) auto params = GetParam(); // First PUCCH, 2 HARQ bits, different indexes. - auto h_dl1 = harq_ent.find_dl_harq(pucch_slot, 0); - auto h_dl2 = harq_ent.find_dl_harq(pucch_slot, 1); + auto h_dl1 = harq_ent.find_dl_harq_waiting_ack(pucch_slot, 0); + auto h_dl2 = harq_ent.find_dl_harq_waiting_ack(pucch_slot, 1); h_dl1->dl_ack_info((mac_harq_ack_report_status)params.ack[0][0], std::nullopt); h_dl2->dl_ack_info((mac_harq_ack_report_status)params.ack[0][1], std::nullopt); // Second PUCCH, 2 HARQ bits, different indexes. if (params.ack.size() > 1) { - h_dl1 = harq_ent.find_dl_harq(pucch_slot, 0); - h_dl2 = harq_ent.find_dl_harq(pucch_slot, 1); + h_dl1 = harq_ent.find_dl_harq_waiting_ack(pucch_slot, 0); + h_dl2 = harq_ent.find_dl_harq_waiting_ack(pucch_slot, 1); h_dl1->dl_ack_info((mac_harq_ack_report_status)params.ack[1][0], std::nullopt); h_dl2->dl_ack_info((mac_harq_ack_report_status)params.ack[1][1], std::nullopt); } @@ -812,7 +812,7 @@ TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_acks_then_al // ACK received. for (unsigned i = 0; i != active_harqs; ++i) { - auto h_dl = this->harq_ent.find_dl_harq(pucch_slot, i); + auto h_dl = this->harq_ent.find_dl_harq_waiting_ack(pucch_slot, i); ASSERT_EQ(h_dl->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), dl_harq_process_handle::status_update::acked); } @@ -840,7 +840,7 @@ TEST_F(single_ue_harq_entity_harq_5bit_tester, when_5_harq_bits_are_nacks_then_a // NACK received. for (unsigned i = 0; i != active_harqs; ++i) { - auto h_dl_ack = this->harq_ent.find_dl_harq(pucch_slot, i); + auto h_dl_ack = this->harq_ent.find_dl_harq_waiting_ack(pucch_slot, i); ASSERT_EQ(h_dl_ack->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process_handle::status_update::nacked); } @@ -911,12 +911,14 @@ TEST_F(multi_ue_harq_manager_test, when_harq_entities_are_nacked_then_they_appea ASSERT_TRUE(cell_harqs.pending_ul_retxs().empty()); ASSERT_EQ(cell_harqs.pending_dl_retxs().begin(), cell_harqs.pending_dl_retxs().end()); - ASSERT_EQ(harq_ent1.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + ASSERT_EQ(harq_ent1.find_dl_harq_waiting_ack(current_slot + k1, 0) + ->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process_handle::status_update::nacked); - ASSERT_EQ(harq_ent1.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); - ASSERT_EQ(harq_ent2.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + ASSERT_EQ(harq_ent1.find_ul_harq_waiting_ack(current_slot + k2)->ul_crc_info(false), 0); + ASSERT_EQ(harq_ent2.find_dl_harq_waiting_ack(current_slot + k1, 0) + ->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process_handle::status_update::nacked); - ASSERT_EQ(harq_ent2.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); + ASSERT_EQ(harq_ent2.find_ul_harq_waiting_ack(current_slot + k2)->ul_crc_info(false), 0); // HARQs are in the list of pending retxs. ASSERT_FALSE(cell_harqs.pending_dl_retxs().empty()); @@ -962,12 +964,14 @@ TEST_F(multi_ue_harq_manager_test, pending_harq_retxs_are_ordered_from_oldest_to ASSERT_TRUE(harq_ent2.alloc_dl_harq(current_slot, k1, max_retxs, 0).has_value()); ASSERT_TRUE(harq_ent1.alloc_ul_harq(current_slot + k2, max_retxs).has_value()); - ASSERT_EQ(harq_ent1.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + ASSERT_EQ(harq_ent1.find_dl_harq_waiting_ack(current_slot + k1, 0) + ->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process_handle::status_update::nacked); - ASSERT_EQ(harq_ent2.find_dl_harq(current_slot + k1, 0)->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), + ASSERT_EQ(harq_ent2.find_dl_harq_waiting_ack(current_slot + k1, 0) + ->dl_ack_info(mac_harq_ack_report_status::nack, std::nullopt), dl_harq_process_handle::status_update::nacked); - ASSERT_EQ(harq_ent2.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); - ASSERT_EQ(harq_ent1.find_ul_harq(current_slot + k2)->ul_crc_info(false), 0); + ASSERT_EQ(harq_ent2.find_ul_harq_waiting_ack(current_slot + k2)->ul_crc_info(false), 0); + ASSERT_EQ(harq_ent1.find_ul_harq_waiting_ack(current_slot + k2)->ul_crc_info(false), 0); unsigned count = 0; for (dl_harq_process_handle h : cell_harqs.pending_dl_retxs()) { @@ -1057,13 +1061,13 @@ TEST_F(single_ntn_ue_harq_process_test, harq_history_is_reachable_after_timeout) ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(0)).has_value()); ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(0)).has_value()); - h_dl = harq_ent.find_dl_harq(uci_slot, 0).value(); - h_ul = harq_ent.find_ul_harq(pusch_slot).value(); + h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot, 0).value(); + h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot).value(); ASSERT_FALSE(h_dl.empty() and h_ul.empty()); ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, pusch_info.tb_size_bytes); - ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_crc()); + ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_ack()); } TEST_F(single_ntn_ue_harq_process_test, when_harq_gets_acked_then_it_reports_the_correct_tbs) @@ -1075,12 +1079,12 @@ TEST_F(single_ntn_ue_harq_process_test, when_harq_gets_acked_then_it_reports_the run_slot(); } - h_ul = harq_ent.find_ul_harq(pusch_slot).value(); - ASSERT_EQ(harq_ent.total_ul_bytes_waiting_crc(), pusch_info.tb_size_bytes); + h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot).value(); + ASSERT_EQ(harq_ent.total_ul_bytes_waiting_ack(), pusch_info.tb_size_bytes); ASSERT_EQ(h_ul.ul_crc_info(true), pusch_info.tb_size_bytes); - ASSERT_EQ(harq_ent.total_ul_bytes_waiting_crc(), 0); + ASSERT_EQ(harq_ent.total_ul_bytes_waiting_ack(), 0); - h_dl = harq_ent.find_dl_harq(uci_slot, 0).value(); + h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot, 0).value(); ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), dl_harq_process_handle::status_update::acked); ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index f91b455849..4cf797bc4e 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -829,7 +829,7 @@ TEST_P(fallback_scheduler_head_scheduling, test_ahead_scheduling_for_srb_allocat // Ack the HARQ processes that are waiting for ACK, otherwise the scheduler runs out of empty HARQs. const unsigned bit_index_1_harq_only = 0U; std::optional dl_harq = - test_ue.get_pcell().harqs.find_dl_harq(current_slot, bit_index_1_harq_only); + test_ue.get_pcell().harqs.find_dl_harq_waiting_ack(current_slot, bit_index_1_harq_only); if (dl_harq.has_value()) { dl_harq->dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt); } @@ -946,7 +946,8 @@ class fallback_scheduler_retx : public base_fallback_tester, public ::testing::T { // Ack the HARQ processes that are waiting for ACK, otherwise the scheduler runs out of empty HARQs. const unsigned bit_index_1_harq_only = 0U; - std::optional dl_harq = test_ue.get_pcell().harqs.find_dl_harq(sl, bit_index_1_harq_only); + std::optional dl_harq = + test_ue.get_pcell().harqs.find_dl_harq_waiting_ack(sl, bit_index_1_harq_only); if (dl_harq.has_value()) { srsran_assert(dl_harq->id() == ongoing_h_id, "HARQ process mismatch"); dl_harq->dl_ack_info(ack_outcome ? mac_harq_ack_report_status::ack : mac_harq_ack_report_status::nack, {}); @@ -1152,7 +1153,8 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public { // Ack the HARQ processes that are waiting for ACK, otherwise the scheduler runs out of empty HARQs. const unsigned bit_index_1_harq_only = 0U; - std::optional dl_harq = test_ue.get_pcell().harqs.find_dl_harq(sl, bit_index_1_harq_only); + std::optional dl_harq = + test_ue.get_pcell().harqs.find_dl_harq_waiting_ack(sl, bit_index_1_harq_only); if (dl_harq.has_value()) { static constexpr double ack_probability = 0.5f; const bool ack = test_rgen::bernoulli(ack_probability); @@ -1445,7 +1447,7 @@ TEST_F(fallback_sched_ue_w_out_pucch_cfg, when_srb0_is_retx_ed_only_pucch_common // NACK the HARQ processes that are waiting for ACK to trigger a retransmissions. const unsigned bit_index_1_harq_only = 0U; std::optional dl_harq = - u.get_pcell().harqs.find_dl_harq(current_slot, bit_index_1_harq_only); + u.get_pcell().harqs.find_dl_harq_waiting_ack(current_slot, bit_index_1_harq_only); if (dl_harq.has_value()) { dl_harq->dl_ack_info(mac_harq_ack_report_status::nack, {}); } From dace8f141b1dfddabddd235f7294bd51bc6510a7 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 30 Aug 2024 19:01:51 +0200 Subject: [PATCH 407/407] sched: remove default ctor of harq_process_handler --- lib/scheduler/cell/cell_harq_manager.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 0aaec54590..af809ba0f5 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -175,7 +175,6 @@ class base_harq_process_handle using harq_impl_type = std::conditional_t; public: - base_harq_process_handle() = default; base_harq_process_handle(harq_pool& pool_, harq_impl_type& h_) : harq_repo(&pool_), impl(&h_) {} du_ue_index_t ue_index() const { return impl->ue_idx; } @@ -340,13 +339,29 @@ class harq_pending_retx_list_impl { } - reference operator++() + iterator& operator++() { ++it; - return value(); + return *this; + } + iterator operator++(int) + { + iterator ret{*this}; + ++it; + return ret; + } + reference operator*() + { + srsran_assert(it != pool->harq_pending_retx_list.end(), "Dereferencing list end()"); + return handle_type{*pool, *it}; + } + pointer operator->() + { + if (it != pool->harq_pending_retx_list.end()) { + return handle_type{*pool, *it}; + } + return std::nullopt; } - reference operator*() { return value(); } - reference value() { return it != pool->harq_pending_retx_list.end() ? handle_type{*pool, *it} : handle_type{}; } bool operator==(const iterator& other) const { return pool == other.pool and it == other.it; } bool operator!=(const iterator& other) const { return !(*this == other); }