From daccdea7966a0d644230784b87e9f2e05cb4ec92 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 12 Jul 2024 14:14:28 +0200 Subject: [PATCH 01/34] cu_cp,rrc: add five-g-s-tmsi converters and unittest --- lib/rrc/ue/rrc_asn1_converters.h | 30 ++++++++++++++++ tests/unittests/rrc/rrc_asn1_helpers_test.cpp | 34 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/rrc/ue/rrc_asn1_converters.h b/lib/rrc/ue/rrc_asn1_converters.h index e4cdf9e27a..554d956b53 100644 --- a/lib/rrc/ue/rrc_asn1_converters.h +++ b/lib/rrc/ue/rrc_asn1_converters.h @@ -10,6 +10,7 @@ #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" @@ -236,6 +237,35 @@ integrity_prot_algorithm_to_rrc_asn1(const security::integrity_algorithm& integr return asn1_integrity_prot_algo; } +inline cu_cp_five_g_s_tmsi number_to_five_g_s_tmsi(uint64_t five_g_s_tmsi_value) +{ + cu_cp_five_g_s_tmsi five_g_s_tmsi; + + // As per TS 23.003 section 2.11 and section 2.10.1 + five_g_s_tmsi.amf_set_id = five_g_s_tmsi_value >> 38U; + five_g_s_tmsi.amf_pointer = (five_g_s_tmsi_value - ((five_g_s_tmsi_value >> 38U) << 38U)) >> 32U; + five_g_s_tmsi.five_g_tmsi = (five_g_s_tmsi_value << 32U) >> 32U; + + return five_g_s_tmsi; +} + +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 number_to_five_g_s_tmsi(five_g_s_tmsi.to_uint64()); +} + +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()); + + return number_to_five_g_s_tmsi(five_g_s_tmsi.to_uint64()); +} + 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; diff --git a/tests/unittests/rrc/rrc_asn1_helpers_test.cpp b/tests/unittests/rrc/rrc_asn1_helpers_test.cpp index 2b1ece9a7f..b8a22d7e59 100644 --- a/tests/unittests/rrc/rrc_asn1_helpers_test.cpp +++ b/tests/unittests/rrc/rrc_asn1_helpers_test.cpp @@ -9,12 +9,46 @@ */ #include "lib/rrc/ue/rrc_asn1_converters.h" +#include "srsran/asn1/asn1_utils.h" #include "srsran/cu_cp/cu_cp_types.h" +#include #include using namespace srsran; using namespace srsran::srs_cu_cp; +/// Test five-g-s-tmsi conversion +TEST(rrc_asn1_helpers_test, test_five_g_s_tmsi_converter_for_valid_five_g_s_tmsi) +{ + // use known a Five-G-S-TMSI + asn1::fixed_bitstring<48> asn1_five_g_s_tmsi; + asn1_five_g_s_tmsi.from_number(278099133963U); + + srs_cu_cp::cu_cp_five_g_s_tmsi five_g_s_tmsi = asn1_to_five_g_s_tmsi(asn1_five_g_s_tmsi); + + ASSERT_EQ(1U, five_g_s_tmsi.amf_set_id); + ASSERT_EQ(0U, five_g_s_tmsi.amf_pointer); + ASSERT_EQ(3221227019U, five_g_s_tmsi.five_g_tmsi); +} + +/// Test five-g-s-tmsi conversion with concatenation +TEST(rrc_asn1_helpers_test, test_five_g_s_tmsi_concatenation_for_valid_five_g_s_tmsi) +{ + // use known Five-G-S-TMSI-Par1 and Five-G-S-TMSI-Part2 + asn1::fixed_bitstring<39> asn1_five_g_s_tmsi_part1; + asn1_five_g_s_tmsi_part1.from_number(278099133963); + + asn1::fixed_bitstring<9> asn1_five_g_s_tmsi_part_2; + asn1_five_g_s_tmsi_part_2.from_number(0); + + srs_cu_cp::cu_cp_five_g_s_tmsi five_g_s_tmsi = + asn1_to_five_g_s_tmsi(asn1_five_g_s_tmsi_part1, asn1_five_g_s_tmsi_part_2); + + ASSERT_EQ(1U, five_g_s_tmsi.amf_set_id); + ASSERT_EQ(0U, five_g_s_tmsi.amf_pointer); + ASSERT_EQ(3221227019U, five_g_s_tmsi.five_g_tmsi); +} + /// Test amf-identifier decoding TEST(rrc_asn1_helpers_test, test_amf_identifier_converter_for_valid_amf_id) { From 18911825e371fea55d4eedf3fa7b4fd069bae45d Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 12 Jul 2024 14:14:35 +0200 Subject: [PATCH 02/34] cu_cp,rrc: fix handling and conversion of five-g-s-tmsi --- lib/rrc/ue/procedures/rrc_setup_procedure.cpp | 32 +++++++++++++------ lib/rrc/ue/rrc_ue_context.h | 3 +- lib/rrc/ue/rrc_ue_message_handlers.cpp | 9 ++---- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp index 7ec998051e..1a5c521674 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp @@ -92,27 +92,39 @@ void rrc_setup_procedure::send_rrc_setup() rrc_ue.on_new_dl_ccch(dl_ccch_msg); } -void rrc_setup_procedure::send_initial_ue_msg(const asn1::rrc_nr::rrc_setup_complete_s& rrc_setup_complete) +void rrc_setup_procedure::send_initial_ue_msg(const asn1::rrc_nr::rrc_setup_complete_s& rrc_setup_complete_msg) { cu_cp_initial_ue_message init_ue_msg = {}; + const auto& rrc_setup_complete = rrc_setup_complete_msg.crit_exts.rrc_setup_complete(); + init_ue_msg.ue_index = context.ue_index; - init_ue_msg.nas_pdu = rrc_setup_complete.crit_exts.rrc_setup_complete().ded_nas_msg.copy(); + init_ue_msg.nas_pdu = rrc_setup_complete.ded_nas_msg.copy(); init_ue_msg.establishment_cause = static_cast(context.connection_cause.value); init_ue_msg.user_location_info.nr_cgi = context.cell.cgi; init_ue_msg.user_location_info.tai.plmn_id = context.cell.cgi.plmn_id; init_ue_msg.user_location_info.tai.tac = context.cell.tac; - cu_cp_five_g_s_tmsi five_g_s_tmsi; - if (context.five_g_tmsi.has_value()) { - five_g_s_tmsi.five_g_tmsi = context.five_g_tmsi.value(); - // amf_pointer and amf_set_id will be set by NGAP - init_ue_msg.five_g_s_tmsi = five_g_s_tmsi; + if (rrc_setup_complete.ng_5_g_s_tmsi_value_present) { + if (rrc_setup_complete.ng_5_g_s_tmsi_value.type() == + asn1::rrc_nr::rrc_setup_complete_ies_s::ng_5_g_s_tmsi_value_c_::types_opts::options::ng_5_g_s_tmsi) { + context.five_g_s_tmsi = asn1_to_five_g_s_tmsi(rrc_setup_complete.ng_5_g_s_tmsi_value.ng_5_g_s_tmsi()); + } else { + if (!context.five_g_s_tmsi_part1.has_value()) { + logger.log_warning("5G-S-TMSI part 1 is missing"); + } else { + context.five_g_s_tmsi = asn1_to_five_g_s_tmsi(context.five_g_s_tmsi_part1.value(), + rrc_setup_complete.ng_5_g_s_tmsi_value.ng_5_g_s_tmsi_part2()); + } + } + } + + if (context.five_g_s_tmsi.has_value()) { + init_ue_msg.five_g_s_tmsi = context.five_g_s_tmsi.value(); } - if (rrc_setup_complete.crit_exts.rrc_setup_complete().registered_amf_present) { - cu_cp_amf_identifier_t amf_id = - asn1_to_amf_identifier(rrc_setup_complete.crit_exts.rrc_setup_complete().registered_amf.amf_id); + if (rrc_setup_complete.registered_amf_present) { + cu_cp_amf_identifier_t amf_id = asn1_to_amf_identifier(rrc_setup_complete.registered_amf.amf_id); init_ue_msg.amf_set_id = amf_id.amf_set_id; // TODO: Handle PLMN ID diff --git a/lib/rrc/ue/rrc_ue_context.h b/lib/rrc/ue/rrc_ue_context.h index b87d7fc4c5..d88fc05de9 100644 --- a/lib/rrc/ue/rrc_ue_context.h +++ b/lib/rrc/ue/rrc_ue_context.h @@ -39,7 +39,8 @@ class rrc_ue_context_t const rrc_ue_cfg_t cfg; rrc_state state = rrc_state::idle; std::optional meas_cfg; - std::optional five_g_tmsi; + std::optional> five_g_s_tmsi_part1; + std::optional five_g_s_tmsi; uint64_t setup_ue_id; asn1::rrc_nr::establishment_cause_opts connection_cause; std::map srbs; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 97d10aefcc..1e042f57b8 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -76,13 +76,8 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request const rrc_setup_request_ies_s& request_ies = request_msg.rrc_setup_request; switch (request_ies.ue_id.type().value) { case init_ue_id_c::types_opts::ng_5_g_s_tmsi_part1: { - context.setup_ue_id = request_ies.ue_id.ng_5_g_s_tmsi_part1().to_number(); - - // As per TS 23.003 section 2.10.1 the last 32Bits of the 5G-S-TMSI are the 5G-TMSI - unsigned shift_bits = - request_ies.ue_id.ng_5_g_s_tmsi_part1().length() - 32; // calculate the number of bits to shift - context.five_g_tmsi = ((request_ies.ue_id.ng_5_g_s_tmsi_part1().to_number() << shift_bits) >> shift_bits); - + context.five_g_s_tmsi_part1 = request_ies.ue_id.ng_5_g_s_tmsi_part1(); + context.setup_ue_id = request_ies.ue_id.ng_5_g_s_tmsi_part1().to_number(); break; } case asn1::rrc_nr::init_ue_id_c::types_opts::random_value: From 5006fda2bc3452ddeb34fc9fcc95fdcbae329079 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 15 Jul 2024 11:57:19 +0200 Subject: [PATCH 03/34] cu_cp,ngap,rrc,f1ap: refactor common type cu_cp_five_g_s_tmsi --- include/srsran/cu_cp/cu_cp_types.h | 23 ++++++++++++++++--- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 4 ++-- lib/ngap/ngap_asn1_converters.h | 17 ++++++++++++++ lib/ngap/ngap_asn1_helpers.h | 10 ++++---- lib/rrc/ue/rrc_asn1_converters.h | 16 ++----------- .../f1ap/common/f1ap_cu_test_messages.cpp | 6 ++--- tests/unittests/ngap/ngap_paging_test.cpp | 14 ++++++----- tests/unittests/rrc/rrc_asn1_helpers_test.cpp | 12 +++++----- 8 files changed, 62 insertions(+), 40 deletions(-) diff --git a/include/srsran/cu_cp/cu_cp_types.h b/include/srsran/cu_cp/cu_cp_types.h index aef758f3c7..f376dda83b 100644 --- a/include/srsran/cu_cp/cu_cp_types.h +++ b/include/srsran/cu_cp/cu_cp_types.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/adt/bounded_bitset.h" #include "srsran/adt/byte_buffer.h" #include "srsran/adt/optional.h" #include "srsran/adt/slotted_array.h" @@ -131,9 +132,25 @@ struct cu_cp_amf_identifier_t { }; struct cu_cp_five_g_s_tmsi { - uint16_t amf_set_id; - uint8_t amf_pointer; - uint32_t five_g_tmsi; + uint16_t get_amf_set_id() const + { + srsran_assert(five_g_s_tmsi.has_value(), "five_g_s_tmsi is not set"); + return five_g_s_tmsi.value().to_uint64() >> 38U; + }; + + uint8_t get_amf_pointer() const + { + srsran_assert(five_g_s_tmsi.has_value(), "five_g_s_tmsi is not set"); + return (five_g_s_tmsi.value().to_uint64() & 0x3f00000000) >> 32U; + }; + + uint32_t get_five_g_tmsi() const + { + srsran_assert(five_g_s_tmsi.has_value(), "five_g_s_tmsi is not set"); + return (five_g_s_tmsi.value().to_uint64() & 0xffffffff); + }; + + std::optional> five_g_s_tmsi; }; struct cu_cp_initial_ue_message { diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 5207af1031..2b98ad38e4 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -561,8 +561,8 @@ f1ap_rrc_recfg_complete_ind_to_asn1(const f1ap_rrc_recfg_complete_ind& rrc_recfg inline uint64_t five_g_s_tmsi_struct_to_number(const cu_cp_five_g_s_tmsi& five_g_s_tmsi) { // 5G-S-TMSI is a 48 bit string consisting of <5G-TMSI (32 bit)> - return ((uint64_t)five_g_s_tmsi.amf_set_id << 38) + ((uint64_t)five_g_s_tmsi.amf_pointer << 32) + - five_g_s_tmsi.five_g_tmsi; + return ((uint64_t)five_g_s_tmsi.get_amf_set_id() << 38) + ((uint64_t)five_g_s_tmsi.get_amf_pointer() << 32) + + five_g_s_tmsi.get_five_g_tmsi(); } /// \brief Convert F1AP ASN.1 to \c cu_cp_tx_bw. diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index 3d9aef8a2b..85f0444b8a 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -836,5 +836,22 @@ inline bool target_to_source_transport_container_to_asn1( return true; } +/// \brief Convert NGAP ASN.1 to \c cu_cp_five_g_s_tmsi. +/// \param[in] asn1_ue_id The ASN.1 type ue paging ID. +/// \return The common type cu_cp_five_g_s_tmsi. +inline cu_cp_five_g_s_tmsi ngap_asn1_to_ue_paging_id(const asn1::ngap::ue_paging_id_c& asn1_ue_id) +{ + srsran_assert(asn1_ue_id.type() == asn1::ngap::ue_paging_id_c::types_opts::five_g_s_tmsi, + "Invalid UE paging ID type"); + + bounded_bitset<48> five_g_s_tmsi(48); + + five_g_s_tmsi.from_uint64(((uint64_t)asn1_ue_id.five_g_s_tmsi().amf_set_id.to_number() << 38U) + + ((uint64_t)asn1_ue_id.five_g_s_tmsi().amf_pointer.to_number() << 32U) + + asn1_ue_id.five_g_s_tmsi().five_g_tmsi.to_number()); + + return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; +} + } // namespace srs_cu_cp } // namespace srsran diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index 078747c15f..a93f4d62fc 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -202,9 +202,9 @@ inline void fill_asn1_initial_ue_message(asn1::ngap::init_ue_msg_s& asn1_ms if (msg.five_g_s_tmsi.has_value()) { // TS 23.003 - 5G-S-TMSI contains AMF Set ID, AMF Pointer and 5G TMSI. asn1_msg->five_g_s_tmsi_present = true; - asn1_msg->five_g_s_tmsi.amf_set_id.from_number(msg.five_g_s_tmsi.value().amf_set_id); - asn1_msg->five_g_s_tmsi.amf_pointer.from_number(msg.five_g_s_tmsi.value().amf_pointer); - asn1_msg->five_g_s_tmsi.five_g_tmsi.from_number(msg.five_g_s_tmsi.value().five_g_tmsi); + asn1_msg->five_g_s_tmsi.amf_set_id.from_number(msg.five_g_s_tmsi.value().get_amf_set_id()); + asn1_msg->five_g_s_tmsi.amf_pointer.from_number(msg.five_g_s_tmsi.value().get_amf_pointer()); + asn1_msg->five_g_s_tmsi.five_g_tmsi.from_number(msg.five_g_s_tmsi.value().get_five_g_tmsi()); } if (msg.amf_set_id.has_value()) { @@ -854,9 +854,7 @@ inline void fill_asn1_ue_context_release_complete(asn1::ngap::ue_context_release inline void fill_cu_cp_paging_message(cu_cp_paging_message& paging, const asn1::ngap::paging_s& asn1_paging) { // add ue paging id - paging.ue_paging_id.amf_set_id = asn1_paging->ue_paging_id.five_g_s_tmsi().amf_set_id.to_number(); - paging.ue_paging_id.amf_pointer = asn1_paging->ue_paging_id.five_g_s_tmsi().amf_pointer.to_number(); - paging.ue_paging_id.five_g_tmsi = asn1_paging->ue_paging_id.five_g_s_tmsi().five_g_tmsi.to_number(); + paging.ue_paging_id = ngap_asn1_to_ue_paging_id(asn1_paging->ue_paging_id); // add paging drx if (asn1_paging->paging_drx_present) { diff --git a/lib/rrc/ue/rrc_asn1_converters.h b/lib/rrc/ue/rrc_asn1_converters.h index 554d956b53..c2063bb12f 100644 --- a/lib/rrc/ue/rrc_asn1_converters.h +++ b/lib/rrc/ue/rrc_asn1_converters.h @@ -237,24 +237,12 @@ integrity_prot_algorithm_to_rrc_asn1(const security::integrity_algorithm& integr return asn1_integrity_prot_algo; } -inline cu_cp_five_g_s_tmsi number_to_five_g_s_tmsi(uint64_t five_g_s_tmsi_value) -{ - cu_cp_five_g_s_tmsi five_g_s_tmsi; - - // As per TS 23.003 section 2.11 and section 2.10.1 - five_g_s_tmsi.amf_set_id = five_g_s_tmsi_value >> 38U; - five_g_s_tmsi.amf_pointer = (five_g_s_tmsi_value - ((five_g_s_tmsi_value >> 38U) << 38U)) >> 32U; - five_g_s_tmsi.five_g_tmsi = (five_g_s_tmsi_value << 32U) >> 32U; - - return five_g_s_tmsi; -} - 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 number_to_five_g_s_tmsi(five_g_s_tmsi.to_uint64()); + return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; } inline cu_cp_five_g_s_tmsi asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<39>& asn1_five_g_s_tmsi_part1, @@ -263,7 +251,7 @@ inline cu_cp_five_g_s_tmsi asn1_to_five_g_s_tmsi(const asn1::fixed_bitstring<39> 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 number_to_five_g_s_tmsi(five_g_s_tmsi.to_uint64()); + return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; } inline cu_cp_amf_identifier_t asn1_to_amf_identifier(const asn1::fixed_bitstring<24>& asn1_amf_id) diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index a2bb5c85c8..69491c4603 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -446,9 +446,9 @@ cu_cp_paging_message srsran::srs_cu_cp::generate_paging_message() cu_cp_paging_message paging_msg; // add ue paging id - paging_msg.ue_paging_id.amf_set_id = 1; - paging_msg.ue_paging_id.amf_pointer = 0; - paging_msg.ue_paging_id.five_g_tmsi = 4211117727; + bounded_bitset<48> five_g_s_tmsi(48); + five_g_s_tmsi.from_uint64(((uint64_t)1U << 38U) + ((uint64_t)0U << 32U) + 4211117727); + paging_msg.ue_paging_id = cu_cp_five_g_s_tmsi{five_g_s_tmsi}; // add paging drx paging_msg.paging_drx = 64; diff --git a/tests/unittests/ngap/ngap_paging_test.cpp b/tests/unittests/ngap/ngap_paging_test.cpp index 2a109673a1..521625b8fa 100644 --- a/tests/unittests/ngap/ngap_paging_test.cpp +++ b/tests/unittests/ngap/ngap_paging_test.cpp @@ -20,17 +20,19 @@ 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.amf_set_id != 1) { - test_logger.error("AMF Set ID mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.amf_set_id, 1); + if (cu_cp_paging_notifier.last_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); return false; } - if (cu_cp_paging_notifier.last_msg.ue_paging_id.amf_pointer != 0) { - test_logger.error("AMF Pointer mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.amf_pointer, 0); + if (cu_cp_paging_notifier.last_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); return false; } - if (cu_cp_paging_notifier.last_msg.ue_paging_id.five_g_tmsi != 4211117727) { + if (cu_cp_paging_notifier.last_msg.ue_paging_id.get_five_g_tmsi() != 4211117727) { test_logger.error( - "FiveG TMSI mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.five_g_tmsi, 4211117727); + "FiveG TMSI mismatch {} != {}", cu_cp_paging_notifier.last_msg.ue_paging_id.get_five_g_tmsi(), 4211117727); return false; } diff --git a/tests/unittests/rrc/rrc_asn1_helpers_test.cpp b/tests/unittests/rrc/rrc_asn1_helpers_test.cpp index b8a22d7e59..ebf09861c0 100644 --- a/tests/unittests/rrc/rrc_asn1_helpers_test.cpp +++ b/tests/unittests/rrc/rrc_asn1_helpers_test.cpp @@ -26,9 +26,9 @@ TEST(rrc_asn1_helpers_test, test_five_g_s_tmsi_converter_for_valid_five_g_s_tmsi srs_cu_cp::cu_cp_five_g_s_tmsi five_g_s_tmsi = asn1_to_five_g_s_tmsi(asn1_five_g_s_tmsi); - ASSERT_EQ(1U, five_g_s_tmsi.amf_set_id); - ASSERT_EQ(0U, five_g_s_tmsi.amf_pointer); - ASSERT_EQ(3221227019U, five_g_s_tmsi.five_g_tmsi); + ASSERT_EQ(1U, five_g_s_tmsi.get_amf_set_id()); + ASSERT_EQ(0U, five_g_s_tmsi.get_amf_pointer()); + ASSERT_EQ(3221227019U, five_g_s_tmsi.get_five_g_tmsi()); } /// Test five-g-s-tmsi conversion with concatenation @@ -44,9 +44,9 @@ TEST(rrc_asn1_helpers_test, test_five_g_s_tmsi_concatenation_for_valid_five_g_s_ srs_cu_cp::cu_cp_five_g_s_tmsi five_g_s_tmsi = asn1_to_five_g_s_tmsi(asn1_five_g_s_tmsi_part1, asn1_five_g_s_tmsi_part_2); - ASSERT_EQ(1U, five_g_s_tmsi.amf_set_id); - ASSERT_EQ(0U, five_g_s_tmsi.amf_pointer); - ASSERT_EQ(3221227019U, five_g_s_tmsi.five_g_tmsi); + ASSERT_EQ(1U, five_g_s_tmsi.get_amf_set_id()); + ASSERT_EQ(0U, five_g_s_tmsi.get_amf_pointer()); + ASSERT_EQ(3221227019U, five_g_s_tmsi.get_five_g_tmsi()); } /// Test amf-identifier decoding From 157e804534db8e3a1fbde462821bf4e9a2e61f3f Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 15 Jul 2024 17:47:23 +0200 Subject: [PATCH 04/34] cu_cp,rrc: make setup ue id a variant --- lib/rrc/ue/procedures/rrc_setup_procedure.cpp | 5 ++-- lib/rrc/ue/rrc_ue_context.h | 24 +++++++++---------- lib/rrc/ue/rrc_ue_message_handlers.cpp | 3 +-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp index 1a5c521674..38671fc81b 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp @@ -11,6 +11,7 @@ #include "rrc_setup_procedure.h" #include "../rrc_asn1_helpers.h" #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" +#include using namespace srsran; using namespace srsran::srs_cu_cp; @@ -110,10 +111,10 @@ void rrc_setup_procedure::send_initial_ue_msg(const asn1::rrc_nr::rrc_setup_comp asn1::rrc_nr::rrc_setup_complete_ies_s::ng_5_g_s_tmsi_value_c_::types_opts::options::ng_5_g_s_tmsi) { context.five_g_s_tmsi = asn1_to_five_g_s_tmsi(rrc_setup_complete.ng_5_g_s_tmsi_value.ng_5_g_s_tmsi()); } else { - if (!context.five_g_s_tmsi_part1.has_value()) { + if (!std::holds_alternative>(context.setup_ue_id)) { logger.log_warning("5G-S-TMSI part 1 is missing"); } else { - context.five_g_s_tmsi = asn1_to_five_g_s_tmsi(context.five_g_s_tmsi_part1.value(), + context.five_g_s_tmsi = asn1_to_five_g_s_tmsi(std::get>(context.setup_ue_id), rrc_setup_complete.ng_5_g_s_tmsi_value.ng_5_g_s_tmsi_part2()); } } diff --git a/lib/rrc/ue/rrc_ue_context.h b/lib/rrc/ue/rrc_ue_context.h index d88fc05de9..c750ba840c 100644 --- a/lib/rrc/ue/rrc_ue_context.h +++ b/lib/rrc/ue/rrc_ue_context.h @@ -33,18 +33,18 @@ class rrc_ue_context_t const rrc_ue_cfg_t& cfg_, std::optional rrc_context_); - const ue_index_t ue_index; // UE index assigned by the DU processor - const rnti_t c_rnti; // current C-RNTI - const rrc_cell_context cell; // current cell - const rrc_ue_cfg_t cfg; - rrc_state state = rrc_state::idle; - std::optional meas_cfg; - std::optional> five_g_s_tmsi_part1; - std::optional five_g_s_tmsi; - uint64_t setup_ue_id; - asn1::rrc_nr::establishment_cause_opts connection_cause; - std::map srbs; - std::optional capabilities; + const ue_index_t ue_index; // UE index assigned by the DU processor + const rnti_t c_rnti; // current C-RNTI + const rrc_cell_context cell; // current cell + const rrc_ue_cfg_t cfg; + rrc_state state = rrc_state::idle; + std::optional 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; 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 1e042f57b8..1aedc5a413 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -76,8 +76,7 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request const rrc_setup_request_ies_s& request_ies = request_msg.rrc_setup_request; switch (request_ies.ue_id.type().value) { case init_ue_id_c::types_opts::ng_5_g_s_tmsi_part1: { - context.five_g_s_tmsi_part1 = request_ies.ue_id.ng_5_g_s_tmsi_part1(); - context.setup_ue_id = request_ies.ue_id.ng_5_g_s_tmsi_part1().to_number(); + context.setup_ue_id = request_ies.ue_id.ng_5_g_s_tmsi_part1(); break; } case asn1::rrc_nr::init_ue_id_c::types_opts::random_value: From 851d3a1f43ae7a3fa0da4735a22404327a41f4ce Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 16 Jul 2024 11:19:18 +0200 Subject: [PATCH 05/34] phy: remove unused function --- .../generic_functions/precoding/channel_precoder_test.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp b/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp index 42b8b92d01..ad2432761b 100644 --- a/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp +++ b/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp @@ -40,12 +40,6 @@ static std::ostream& operator<<(std::ostream& os, span data) return os; } -static std::ostream& operator<<(std::ostream& os, span data) -{ - fmt::print(os, "{}", data); - return os; -} - 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) { From 959a6856e67823207cf7d177001af4a099589283 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 16 Jul 2024 08:04:35 +0100 Subject: [PATCH 06/34] cu_up: fix test mode --- lib/cu_up/cu_up_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cu_up/cu_up_impl.cpp b/lib/cu_up/cu_up_impl.cpp index 97a4fa9d07..6e330c69f2 100644 --- a/lib/cu_up/cu_up_impl.cpp +++ b/lib/cu_up/cu_up_impl.cpp @@ -41,7 +41,7 @@ cu_up::cu_up(const cu_up_configuration& config_) : cfg(config_), main_ctrl_loop( // Create GTP-U demux gtpu_demux_creation_request demux_msg = {}; demux_msg.cfg.warn_on_drop = cfg.n3_cfg.warn_on_drop; - demux_msg.cfg.test_mode = true; + demux_msg.cfg.test_mode = cfg.test_mode_cfg.enabled; demux_msg.gtpu_pcap = cfg.gtpu_pcap; ngu_demux = create_gtpu_demux(demux_msg); From 567437d1aec7285d1f0d0ed6a301684249253e36 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 12 Jul 2024 10:28:21 +0200 Subject: [PATCH 07/34] e1ap: implement E1 SCTP Gateway --- .../e1ap/gateways/e1_network_client_factory.h | 33 ++++ .../e1ap/gateways/e1_network_server_factory.h | 36 ++++ lib/e1ap/gateways/CMakeLists.txt | 5 +- .../gateways/e1_network_client_factory.cpp | 158 ++++++++++++++++++ .../gateways/e1_network_server_factory.cpp | 153 +++++++++++++++++ 5 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 include/srsran/e1ap/gateways/e1_network_client_factory.h create mode 100644 include/srsran/e1ap/gateways/e1_network_server_factory.h create mode 100644 lib/e1ap/gateways/e1_network_client_factory.cpp create mode 100644 lib/e1ap/gateways/e1_network_server_factory.cpp diff --git a/include/srsran/e1ap/gateways/e1_network_client_factory.h b/include/srsran/e1ap/gateways/e1_network_client_factory.h new file mode 100644 index 0000000000..f0d7ee3506 --- /dev/null +++ b/include/srsran/e1ap/gateways/e1_network_client_factory.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 + +#include "srsran/e1ap/gateways/e1_connection_client.h" +#include "srsran/gateways/sctp_network_gateway.h" + +namespace srsran { + +class dlt_pcap; +class io_broker; + +struct e1_du_sctp_gateway_config { + /// SCTP configuration. + sctp_network_connector_config sctp; + /// IO broker responsible for handling SCTP Rx data and notifications. + io_broker& broker; + /// PCAP writer for the E1AP messages. + dlt_pcap& pcap; +}; + +/// \brief Create an E1 gateway connector that the CU-UP can use to connect to the CU-CP. +std::unique_ptr create_e1_gateway_client(const e1_du_sctp_gateway_config& params); + +} // namespace srsran diff --git a/include/srsran/e1ap/gateways/e1_network_server_factory.h b/include/srsran/e1ap/gateways/e1_network_server_factory.h new file mode 100644 index 0000000000..51e7681fff --- /dev/null +++ b/include/srsran/e1ap/gateways/e1_network_server_factory.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/cu_cp/cu_cp_e1_handler.h" +#include "srsran/e1ap/gateways/e1_connection_server.h" +#include "srsran/gateways/sctp_network_gateway.h" + +namespace srsran { + +class dlt_pcap; +class io_broker; + +/// Configuration of an SCTP-based E1 Gateway. +struct e1_cu_sctp_gateway_config { + /// SCTP configuration. + sctp_network_gateway_config sctp; + /// IO broker responsible for handling SCTP Rx data and notifications. + io_broker& broker; + /// PCAP writer for the E1AP messages. + dlt_pcap& pcap; +}; + +/// Creates an E1 Gateway server that listens for incoming SCTP connections, packs/unpacks E1AP PDUs and forwards +/// them to the GW/CU-CP E1AP handler. +std::unique_ptr create_e1_gateway_server(const e1_cu_sctp_gateway_config& params); + +} // namespace srsran diff --git a/lib/e1ap/gateways/CMakeLists.txt b/lib/e1ap/gateways/CMakeLists.txt index 8ad4a55a44..bd4525f8f0 100644 --- a/lib/e1ap/gateways/CMakeLists.txt +++ b/lib/e1ap/gateways/CMakeLists.txt @@ -6,5 +6,8 @@ # the distribution. # -add_library(srsran_e1_gateway e1_local_connector_factory.cpp) +add_library(srsran_e1_gateway + e1_local_connector_factory.cpp + e1_network_client_factory.cpp + e1_network_server_factory.cpp) target_link_libraries(srsran_e1_gateway srsran_support srsran_e1ap_common e1ap_asn1) diff --git a/lib/e1ap/gateways/e1_network_client_factory.cpp b/lib/e1ap/gateways/e1_network_client_factory.cpp new file mode 100644 index 0000000000..a1991fc3e2 --- /dev/null +++ b/lib/e1ap/gateways/e1_network_client_factory.cpp @@ -0,0 +1,158 @@ +/* + * + * 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/e1ap/gateways/e1_network_client_factory.h" +#include "srsran/asn1/e1ap/e1ap.h" +#include "srsran/e1ap/common/e1ap_message.h" +#include "srsran/gateways/sctp_network_client_factory.h" +#include "srsran/pcap/dlt_pcap.h" +#include "srsran/support/io/io_broker.h" + +using namespace srsran; + +namespace { + +/// \brief Notifier for converting packed E1AP PDUs coming from the E1 GW into unpacked E1AP PDUs and forward them to +/// the CU-UP. +class sctp_to_e1_pdu_notifier final : public sctp_association_sdu_notifier +{ +public: + sctp_to_e1_pdu_notifier(std::unique_ptr du_rx_pdu_notifier_, + dlt_pcap& pcap_writer_, + srslog::basic_logger& logger_) : + du_rx_pdu_notifier(std::move(du_rx_pdu_notifier_)), pcap_writer(pcap_writer_), logger(logger_) + { + } + + bool on_new_sdu(byte_buffer sdu) override + { + // Unpack E1AP PDU. + asn1::cbit_ref bref(sdu); + e1ap_message msg; + if (msg.pdu.unpack(bref) != asn1::SRSASN_SUCCESS) { + logger.error("Couldn't unpack E1AP PDU"); + return false; + } + + // Forward Rx PDU to pcap, if enabled. + if (pcap_writer.is_write_enabled()) { + pcap_writer.push_pdu(sdu.copy()); + } + + // Forward unpacked Rx PDU to the CU-UP. + du_rx_pdu_notifier->on_new_message(msg); + + return true; + } + +private: + std::unique_ptr du_rx_pdu_notifier; + dlt_pcap& pcap_writer; + srslog::basic_logger& logger; +}; + +/// \brief Notifier for converting unpacked E1AP PDUs coming from the CU-UP into packed E1AP PDUs and forward them to +/// the F1C-GW. +class e1_to_sctp_pdu_notifier final : public e1ap_message_notifier +{ +public: + e1_to_sctp_pdu_notifier(std::unique_ptr sctp_rx_pdu_notifier_, + dlt_pcap& pcap_writer_, + srslog::basic_logger& logger_) : + sctp_rx_pdu_notifier(std::move(sctp_rx_pdu_notifier_)), pcap_writer(pcap_writer_), logger(logger_) + { + } + + void on_new_message(const e1ap_message& msg) override + { + // pack E1AP PDU into SCTP SDU. + byte_buffer tx_sdu{byte_buffer::fallback_allocation_tag{}}; + asn1::bit_ref bref(tx_sdu); + if (msg.pdu.pack(bref) != asn1::SRSASN_SUCCESS) { + logger.error("Failed to pack E1AP PDU"); + return; + } + + // Push Tx PDU to pcap. + if (pcap_writer.is_write_enabled()) { + pcap_writer.push_pdu(tx_sdu.copy()); + } + + // Forward packed Tx PDU to SCTP gateway. + sctp_rx_pdu_notifier->on_new_sdu(std::move(tx_sdu)); + } + +private: + std::unique_ptr sctp_rx_pdu_notifier; + dlt_pcap& pcap_writer; + srslog::basic_logger& logger; +}; + +class e1_sctp_gateway_client final : public srs_cu_up::e1_connection_client +{ +public: + e1_sctp_gateway_client(const e1_du_sctp_gateway_config& params) : + pcap_writer(params.pcap), broker(params.broker), sctp_params(params.sctp) + { + // Create SCTP network adapter. + sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker}); + report_error_if_not(sctp_gateway != nullptr, "Failed to create SCTP gateway client.\n"); + } + + std::unique_ptr + handle_cu_up_connection_request(std::unique_ptr cu_up_rx_pdu_notifier) override + { + srsran_assert(cu_up_rx_pdu_notifier != nullptr, "CU-UP Rx PDU notifier is null"); + + logger.debug( + "Establishing TNL connection to CU-CP ({}:{})...", sctp_params.connect_address, sctp_params.connect_port); + std::unique_ptr sctp_sender = sctp_gateway->connect_to( + "CU-CP", + sctp_params.connect_address, + sctp_params.connect_port, + std::make_unique(std::move(cu_up_rx_pdu_notifier), pcap_writer, logger)); + if (sctp_sender == nullptr) { + logger.error("Failed to establish E1 TNL connection to CU-CP on {}:{}.\n", + sctp_params.connect_address, + sctp_params.connect_port); + return nullptr; + } + logger.info("{}: TNL connection to {} on {}:{} accepted", + sctp_params.if_name, + sctp_params.dest_name, + sctp_params.connect_address, + sctp_params.connect_port); + fmt::print("{}: Connection to {} on {}:{} completed\n", + sctp_params.if_name, + sctp_params.dest_name, + sctp_params.connect_address, + sctp_params.connect_port); + + // Return the Tx PDU notifier to the CU-UP. + return std::make_unique(std::move(sctp_sender), pcap_writer, logger); + } + +private: + dlt_pcap& pcap_writer; + io_broker& broker; + srsran::sctp_network_connector_config sctp_params; + srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-UP-E1"); + + // SCTP network gateway + std::unique_ptr sctp_gateway; +}; + +} // namespace + +std::unique_ptr +srsran::create_e1_gateway_client(const e1_du_sctp_gateway_config& params) +{ + return std::make_unique(params); +} diff --git a/lib/e1ap/gateways/e1_network_server_factory.cpp b/lib/e1ap/gateways/e1_network_server_factory.cpp new file mode 100644 index 0000000000..07e290da14 --- /dev/null +++ b/lib/e1ap/gateways/e1_network_server_factory.cpp @@ -0,0 +1,153 @@ +/* + * + * 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/e1ap/gateways/e1_network_server_factory.h" +#include "srsran/asn1/e1ap/e1ap.h" +#include "srsran/e1ap/common/e1ap_message.h" +#include "srsran/gateways/sctp_network_server_factory.h" +#include "srsran/pcap/dlt_pcap.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; + +namespace { + +/// Notifier passed to the CU-CP, which the CU-CP will use to send E1AP Tx PDUs. +class e1_to_gw_pdu_notifier final : public e1ap_message_notifier +{ +public: + e1_to_gw_pdu_notifier(std::unique_ptr sctp_sender_, + dlt_pcap& pcap_writer_, + srslog::basic_logger& logger_) : + sctp_sender(std::move(sctp_sender_)), pcap_writer(pcap_writer_), logger(logger_) + { + } + + /// Handle unpacked Tx E1AP PDU by packing and forwarding it into the SCTP GW. + void on_new_message(const e1ap_message& msg) override + { + // pack E1AP PDU into SCTP SDU. + byte_buffer tx_sdu{byte_buffer::fallback_allocation_tag{}}; + asn1::bit_ref bref(tx_sdu); + if (msg.pdu.pack(bref) != asn1::SRSASN_SUCCESS) { + logger.error("Failed to pack E1AP PDU"); + return; + } + + // Push Tx PDU to pcap. + if (pcap_writer.is_write_enabled()) { + pcap_writer.push_pdu(tx_sdu.copy()); + } + + // Forward packed E1AP Tx PDU to SCTP gateway. + sctp_sender->on_new_sdu(std::move(tx_sdu)); + } + +private: + std::unique_ptr sctp_sender; + dlt_pcap& pcap_writer; + srslog::basic_logger& logger; +}; + +/// Notifier passed to the SCTP GW, which the GW will use to forward E1AP Rx PDUs to the CU-CP. +class gw_to_e1_pdu_notifier final : public sctp_association_sdu_notifier +{ +public: + gw_to_e1_pdu_notifier(std::unique_ptr e1ap_notifier_, + dlt_pcap& pcap_writer_, + srslog::basic_logger& logger_) : + e1ap_notifier(std::move(e1ap_notifier_)), pcap_writer(pcap_writer_), logger(logger_) + { + } + + bool on_new_sdu(byte_buffer sdu) override + { + // Unpack SCTP SDU into E1AP PDU. + asn1::cbit_ref bref(sdu); + e1ap_message msg; + if (msg.pdu.unpack(bref) != asn1::SRSASN_SUCCESS) { + logger.error("Couldn't unpack E1AP PDU"); + return false; + } + + // Forward SCTP Rx SDU to pcap, if enabled. + if (pcap_writer.is_write_enabled()) { + pcap_writer.push_pdu(sdu.copy()); + } + + // Forward unpacked Rx PDU to the CU-CP. + e1ap_notifier->on_new_message(msg); + + return true; + } + +private: + std::unique_ptr e1ap_notifier; + dlt_pcap& pcap_writer; + srslog::basic_logger& logger; +}; + +/// Adapter of the SCTP server to the E1 interface of the CU-CP. +class e1_sctp_server final : public srs_cu_cp::e1_connection_server, public sctp_network_association_factory +{ +public: + e1_sctp_server(const e1_cu_sctp_gateway_config& params_) : params(params_) + { + // Create SCTP server. + sctp_server = create_sctp_network_server(sctp_network_server_config{params.sctp, params.broker, *this}); + report_error_if_not(sctp_server != nullptr, "Failed to create SCTP server"); + } + + void attach_cu_cp(srs_cu_cp::cu_cp_e1_handler& cu_e1_handler_) override + { + cu_e1_handler = &cu_e1_handler_; + + // Start listening for new CU-UP SCTP connections. + bool result = sctp_server->listen(); + report_error_if_not(result, "Failed to start SCTP server.\n"); + fmt::print("{}: Listening for new connections on {}:{}...\n", + params.sctp.if_name, + params.sctp.bind_address, + params.sctp.bind_port); + } + + std::optional get_listen_port() const override { return sctp_server->get_listen_port(); } + + std::unique_ptr + create(std::unique_ptr sctp_send_notifier) override + { + // Create an unpacked E1AP PDU notifier and pass it to the CU-CP. + auto e1_sender = std::make_unique(std::move(sctp_send_notifier), params.pcap, logger); + + std::unique_ptr e1_receiver = + cu_e1_handler->handle_new_cu_up_connection(std::move(e1_sender)); + + // Wrap the received E1AP Rx PDU notifier in an SCTP notifier and return it. + if (e1_receiver == nullptr) { + return nullptr; + } + + return std::make_unique(std::move(e1_receiver), params.pcap, logger); + } + +private: + const e1_cu_sctp_gateway_config params; + srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP-E1"); + srs_cu_cp::cu_cp_e1_handler* cu_e1_handler = nullptr; + + std::unique_ptr sctp_server; +}; + +} // namespace + +std::unique_ptr srsran::create_e1_gateway_server(const e1_cu_sctp_gateway_config& cfg) +{ + return std::make_unique(cfg); +} From e21b0c581e31f621232c4a2c9a3f12e285e3fc5a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 12 Jul 2024 11:22:45 +0200 Subject: [PATCH 08/34] e1ap: implement E1 SCTP Gateway unit test --- .../gateways/e1_local_connector_factory.h | 13 + .../srsran/gateways/sctp_network_gateway.h | 1 + lib/e1ap/gateways/CMakeLists.txt | 2 +- .../gateways/e1_local_connector_factory.cpp | 57 ++++ tests/unittests/e1ap/CMakeLists.txt | 1 + tests/unittests/e1ap/gateways/CMakeLists.txt | 21 ++ .../e1ap/gateways/e1_gateway_test.cpp | 293 ++++++++++++++++++ 7 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 tests/unittests/e1ap/gateways/CMakeLists.txt create mode 100644 tests/unittests/e1ap/gateways/e1_gateway_test.cpp diff --git a/include/srsran/e1ap/gateways/e1_local_connector_factory.h b/include/srsran/e1ap/gateways/e1_local_connector_factory.h index bf3398dec2..f48c05fc02 100644 --- a/include/srsran/e1ap/gateways/e1_local_connector_factory.h +++ b/include/srsran/e1ap/gateways/e1_local_connector_factory.h @@ -16,6 +16,7 @@ namespace srsran { class dlt_pcap; +class io_broker; class e1_local_connector : public srs_cu_up::e1_connection_client, public srs_cu_cp::e1_connection_server {}; @@ -29,4 +30,16 @@ struct e1_local_connector_config { /// E1AP PDUs or any socket send/recv. std::unique_ptr create_e1_local_connector(const e1_local_connector_config& cfg); +struct e1_local_sctp_connector_config { + /// PCAP writer for the E1AP messages. + dlt_pcap& pcap; + /// IO broker to handle the SCTP Rx data and notifications. + io_broker& broker; +}; + +/// Creates an E1 local connector using an SCTP socket as channel. +/// +/// Note: This class is useful for testing. +std::unique_ptr create_e1_local_connector(const e1_local_sctp_connector_config& cfg); + } // namespace srsran \ No newline at end of file diff --git a/include/srsran/gateways/sctp_network_gateway.h b/include/srsran/gateways/sctp_network_gateway.h index 19c70e22ae..b5e52f8a42 100644 --- a/include/srsran/gateways/sctp_network_gateway.h +++ b/include/srsran/gateways/sctp_network_gateway.h @@ -18,6 +18,7 @@ namespace srsran { constexpr uint16_t NGAP_PPID = 60; // NGAP PPID, see TS 38.412, section 7. constexpr uint16_t F1AP_PPID = 62; // F1AP PPID, see TS 38.472, section 7. +constexpr uint16_t E1AP_PPID = 64; // E1AP PPID, see TS 37.482, section 7. constexpr uint16_t E2_CP_PPID = 70; // E2-CP PPID assigned by IANA constexpr uint16_t E2_UP_PPID = 71; // E2-UP PPID assigned by IANA constexpr uint16_t E2_DU_PPID = 72; // E2-DU PPID assigned by IANA diff --git a/lib/e1ap/gateways/CMakeLists.txt b/lib/e1ap/gateways/CMakeLists.txt index bd4525f8f0..05a9e2af19 100644 --- a/lib/e1ap/gateways/CMakeLists.txt +++ b/lib/e1ap/gateways/CMakeLists.txt @@ -10,4 +10,4 @@ add_library(srsran_e1_gateway e1_local_connector_factory.cpp e1_network_client_factory.cpp e1_network_server_factory.cpp) -target_link_libraries(srsran_e1_gateway srsran_support srsran_e1ap_common e1ap_asn1) +target_link_libraries(srsran_e1_gateway srsran_support srsran_e1ap_common e1ap_asn1 srsran_pcap) diff --git a/lib/e1ap/gateways/e1_local_connector_factory.cpp b/lib/e1ap/gateways/e1_local_connector_factory.cpp index 8f6ef8d17c..6749fa46fc 100644 --- a/lib/e1ap/gateways/e1_local_connector_factory.cpp +++ b/lib/e1ap/gateways/e1_local_connector_factory.cpp @@ -11,6 +11,8 @@ #include "srsran/e1ap/gateways/e1_local_connector_factory.h" #include "srsran/cu_cp/cu_cp_e1_handler.h" #include "srsran/e1ap/common/e1ap_message.h" +#include "srsran/e1ap/gateways/e1_network_client_factory.h" +#include "srsran/e1ap/gateways/e1_network_server_factory.h" #include "srsran/pcap/dlt_pcap.h" using namespace srsran; @@ -87,9 +89,64 @@ class e1_local_connector_impl final : public e1_local_connector srs_cu_cp::cu_cp_e1_handler* cu_cp_e1_mng = nullptr; }; +/// Implementation of a CU-UP and CU-CP E1 SCTP-based gateway for the case that the DU and CU-CP are co-located. +/// +/// Note: This class should only be used for testing purposes. +class e1_sctp_connector_impl final : public e1_local_connector +{ +public: + e1_sctp_connector_impl(const e1_local_sctp_connector_config& cfg) : broker(cfg.broker), pcap_writer(cfg.pcap) + { + // Create SCTP server. + sctp_network_gateway_config sctp; + sctp.if_name = "E1"; + sctp.ppid = E1AP_PPID; + sctp.bind_address = "127.0.0.1"; + // Use any bind port available. + sctp.bind_port = 0; + server = create_e1_gateway_server(e1_cu_sctp_gateway_config{sctp, broker, pcap_writer}); + } + + void attach_cu_cp(srs_cu_cp::cu_cp_e1_handler& cu_e1_handler_) override + { + server->attach_cu_cp(cu_e1_handler_); + + // Create SCTP client. + sctp_network_connector_config sctp_client; + sctp_client.if_name = "E1"; + sctp_client.dest_name = "CU-CP"; + sctp_client.connect_address = "127.0.0.1"; + sctp_client.connect_port = server->get_listen_port().value(); + sctp_client.ppid = E1AP_PPID; + // Note: We only need to save the PCAPs in one side of the connection. + client = create_e1_gateway_client(e1_du_sctp_gateway_config{sctp_client, broker, *null_pcap_writer}); + } + + std::optional get_listen_port() const override { return server->get_listen_port(); } + + std::unique_ptr + handle_cu_up_connection_request(std::unique_ptr cu_up_rx_pdu_notifier) override + { + // Connect client to server automatically. + return client->handle_cu_up_connection_request(std::move(cu_up_rx_pdu_notifier)); + } + +private: + io_broker& broker; + dlt_pcap& pcap_writer; + std::unique_ptr null_pcap_writer = create_null_dlt_pcap(); + std::unique_ptr server; + std::unique_ptr client; +}; + } // namespace std::unique_ptr srsran::create_e1_local_connector(const e1_local_connector_config& cfg) { return std::make_unique(cfg); } + +std::unique_ptr srsran::create_e1_local_connector(const e1_local_sctp_connector_config& cfg) +{ + return std::make_unique(cfg); +} diff --git a/tests/unittests/e1ap/CMakeLists.txt b/tests/unittests/e1ap/CMakeLists.txt index e6b01d9241..0e4dd39fd3 100644 --- a/tests/unittests/e1ap/CMakeLists.txt +++ b/tests/unittests/e1ap/CMakeLists.txt @@ -13,3 +13,4 @@ include_directories(../../..) add_subdirectory(common) add_subdirectory(cu_cp) add_subdirectory(cu_up) +add_subdirectory(gateways) diff --git a/tests/unittests/e1ap/gateways/CMakeLists.txt b/tests/unittests/e1ap/gateways/CMakeLists.txt new file mode 100644 index 0000000000..d3f3c024b3 --- /dev/null +++ b/tests/unittests/e1ap/gateways/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# 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(e1_gateway_test e1_gateway_test.cpp) +target_link_libraries(e1_gateway_test + srsran_e1_gateway + srsran_gateway + e1ap_test_helpers + srsran_e1ap_common + srsran_support + srsran_network + srslog + e1ap_asn1 + gtest + gtest_main) +add_test(e1_gateway_test e1_gateway_test) diff --git a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp new file mode 100644 index 0000000000..a3ddf222f9 --- /dev/null +++ b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp @@ -0,0 +1,293 @@ +/* + * + * 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/adt/blocking_queue.h" +#include "srsran/asn1/e1ap/common.h" +#include "srsran/asn1/e1ap/e1ap_pdu_contents.h" +#include "srsran/cu_cp/cu_cp_e1_handler.h" +#include "srsran/e1ap/common/e1ap_message.h" +#include "srsran/e1ap/gateways/e1_local_connector_factory.h" +#include "srsran/pcap/dlt_pcap.h" +#include "srsran/support/io/io_broker_factory.h" +#include +#include + +using namespace srsran; + +class dummy_dlt_pcap final : public dlt_pcap +{ +public: + bool enabled = false; + bool closed = false; + blocking_queue last_sdus{16}; + + void close() override { closed = true; } + bool is_write_enabled() const override { return enabled; } + void push_pdu(const_span pdu) override { last_sdus.push_blocking(byte_buffer::create(pdu).value()); } + virtual void push_pdu(byte_buffer pdu) override { last_sdus.push_blocking(std::move(pdu)); } +}; + +class e1_link : public srs_cu_cp::cu_cp_e1_handler +{ +public: + class rx_pdu_notifier : public e1ap_message_notifier + { + public: + rx_pdu_notifier(const std::string& name_, + blocking_queue& rx_pdus_, + std::promise eof_received_) : + name(name_), rx_pdus(rx_pdus_), eof_received(std::move(eof_received_)) + { + } + ~rx_pdu_notifier() override + { + eof_received.set_value(); + logger.info("{}: RX PDU notifier destroyed", name); + } + + void on_new_message(const e1ap_message& msg) override { rx_pdus.push_blocking(msg); } + + const std::string name; + blocking_queue& rx_pdus; + std::promise eof_received; + srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); + }; + + e1_link(bool use_sctp, bool pcap_enabled) + { + pcap.enabled = pcap_enabled; + + if (use_sctp) { + broker = create_io_broker(io_broker_type::epoll); + connector = create_e1_local_connector(e1_local_sctp_connector_config{pcap, *broker}); + } else { + connector = create_e1_local_connector(e1_local_connector_config{pcap}); + } + + connector->attach_cu_cp(*this); + + // Connect client to server. + connect_client(); + } + + std::unique_ptr + handle_new_cu_up_connection(std::unique_ptr e1ap_tx_pdu_notifier) override + { + // Note: May be called from io broker thread. + cu_cp_tx_pdu_notifier = std::move(e1ap_tx_pdu_notifier); + std::promise eof_signal; + cu_gw_assoc_close_signaled = eof_signal.get_future(); + + logger.info("CU-CP handled new DU connection"); + connection_complete_signal.set_value(); + + return std::make_unique("CU-CP", cu_rx_pdus, std::move(eof_signal)); + } + + void handle_cu_up_remove_request(srs_cu_cp::cu_up_index_t cu_up_index) override {} + + srs_cu_cp::cu_up_e1_handler& get_cu_up(srs_cu_cp::cu_up_index_t cu_up_index) override + { + class dummy_cu_up_e1_handler : public srs_cu_cp::cu_up_e1_handler, public e1ap_message_handler + { + public: + e1ap_message_handler& get_message_handler() override { return *this; } + void handle_message(const e1ap_message& msg) override {} + }; + static dummy_cu_up_e1_handler dummy; + return dummy; + } + + std::unique_ptr broker; + dummy_dlt_pcap pcap; + std::unique_ptr connector; + srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); + + blocking_queue cu_rx_pdus{128}; + blocking_queue du_rx_pdus{128}; + + std::future cu_gw_assoc_close_signaled; + std::future du_gw_assoc_close_signaled; + std::unique_ptr cu_cp_tx_pdu_notifier; + std::unique_ptr du_tx_pdu_notifier; + +protected: + void connect_client() + { + // Connect client to server. + std::promise eof_signal; + du_gw_assoc_close_signaled = eof_signal.get_future(); + du_tx_pdu_notifier = connector->handle_cu_up_connection_request( + std::make_unique("CU-UP", du_rx_pdus, std::move(eof_signal))); + + // Wait for server to receive connection. + std::future connection_completed = connection_complete_signal.get_future(); + connection_completed.wait(); + logger.info("CU-UP connection to CU-CP is complete"); + } + + std::promise connection_complete_signal; +}; + +class e1_gateway_link_test : public ::testing::TestWithParam +{ +protected: + e1_gateway_link_test() + { + srslog::init(); + logger.set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("SCTP-GW").set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("CU-CP-E1").set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("CU-UP-E1").set_level(srslog::basic_levels::debug); + } + ~e1_gateway_link_test() override { srslog::flush(); } + + void create_link(bool pcap_enabled = false) + { + bool use_sctp = GetParam(); + link = std::make_unique(use_sctp, pcap_enabled); + } + + void send_to_cu_up(const e1ap_message& msg) { link->cu_cp_tx_pdu_notifier->on_new_message(msg); } + + void send_to_cu_cp(const e1ap_message& msg) { link->du_tx_pdu_notifier->on_new_message(msg); } + + bool pop_cu_rx_pdu(e1ap_message& msg) + { + bool res; + msg = link->cu_rx_pdus.pop_blocking(&res); + return res; + } + + bool pop_du_rx_pdu(e1ap_message& msg) + { + bool res; + msg = link->du_rx_pdus.pop_blocking(&res); + return res; + } + + srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); + std::unique_ptr link; +}; + +static e1ap_message create_test_message() +{ + e1ap_message msg; + msg.pdu.set_init_msg().load_info_obj(ASN1_E1AP_ID_BEARER_CONTEXT_MOD); + asn1::e1ap::bearer_context_mod_request_s& bearer_mod = msg.pdu.init_msg().value.bearer_context_mod_request(); + bearer_mod->gnb_cu_cp_ue_e1ap_id = 0; + bearer_mod->gnb_cu_up_ue_e1ap_id = 1; + return msg; +} + +static byte_buffer pack(const e1ap_message& msg) +{ + byte_buffer pdu; + { + asn1::bit_ref bref{pdu}; + report_fatal_error_if_not(msg.pdu.pack(bref) == asn1::SRSASN_SUCCESS, "Failed to pack E1AP PDU"); + } + return pdu; +} + +static bool is_equal(const e1ap_message& lhs, const e1ap_message& rhs) +{ + byte_buffer lhs_pdu = pack(lhs); + byte_buffer rhs_pdu = pack(rhs); + return lhs_pdu == rhs_pdu; +} + +TEST_P(e1_gateway_link_test, when_du_sends_msg_then_cu_receives_msg) +{ + create_link(); + + e1ap_message orig_msg = create_test_message(); + send_to_cu_cp(orig_msg); + + e1ap_message dest_msg; + ASSERT_TRUE(pop_cu_rx_pdu(dest_msg)); + ASSERT_TRUE(is_equal(orig_msg, dest_msg)); +} + +TEST_P(e1_gateway_link_test, when_cu_sends_msg_then_du_receives_msg) +{ + create_link(); + + e1ap_message orig_msg = create_test_message(); + send_to_cu_up(orig_msg); + + e1ap_message dest_msg; + ASSERT_TRUE(pop_du_rx_pdu(dest_msg)); + ASSERT_TRUE(is_equal(orig_msg, dest_msg)); +} + +TEST_P(e1_gateway_link_test, when_pcap_writer_disabled_then_no_pcap_is_written) +{ + create_link(false); + + e1ap_message orig_msg = create_test_message(); + send_to_cu_up(orig_msg); + e1ap_message dest_msg; + ASSERT_TRUE(pop_du_rx_pdu(dest_msg)); + byte_buffer sdu; + ASSERT_FALSE(link->pcap.last_sdus.try_pop(sdu)); + + send_to_cu_cp(orig_msg); + ASSERT_TRUE(pop_cu_rx_pdu(dest_msg)); + ASSERT_FALSE(link->pcap.last_sdus.try_pop(sdu)); +} + +TEST_P(e1_gateway_link_test, when_pcap_writer_enabled_then_pcap_is_written) +{ + create_link(true); + + e1ap_message orig_msg = create_test_message(); + + send_to_cu_up(orig_msg); + e1ap_message dest_msg; + ASSERT_TRUE(pop_du_rx_pdu(dest_msg)); + bool popped = false; + byte_buffer sdu = link->pcap.last_sdus.pop_blocking(&popped); + ASSERT_TRUE(popped); + ASSERT_FALSE(link->pcap.last_sdus.try_pop(sdu)); + + send_to_cu_cp(orig_msg); + ASSERT_TRUE(pop_cu_rx_pdu(dest_msg)); + popped = false; + sdu = link->pcap.last_sdus.pop_blocking(&popped); + ASSERT_TRUE(popped); + ASSERT_FALSE(link->pcap.last_sdus.try_pop(sdu)); +} + +TEST_P(e1_gateway_link_test, when_cu_tx_pdu_notifier_is_closed_then_connection_closes) +{ + create_link(); + + // The CU-CP resets its E1 Tx notifier. + logger.info("Closing CU-CP Tx path..."); + link->cu_cp_tx_pdu_notifier.reset(); + + // Wait for GW to report to DU that the association is closed. + link->du_gw_assoc_close_signaled.wait(); +} + +TEST_P(e1_gateway_link_test, when_cu_up_tx_pdu_notifier_is_closed_then_connection_closes) +{ + create_link(); + + // The CU-UP resets its E1 Tx notifier. + logger.info("Closing CU-UP Tx path..."); + link->du_tx_pdu_notifier.reset(); + + // Wait for GW to report to CU that the association is closed. + link->cu_gw_assoc_close_signaled.wait(); +} + +INSTANTIATE_TEST_SUITE_P(e1_gateway_link_tests, e1_gateway_link_test, ::testing::Values(true, false)); From 1f87bf892c1c0cb731e21e6961fc7a05442aadd2 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 12 Jul 2024 16:07:56 +0200 Subject: [PATCH 09/34] e1ap: implement cu-up connection manager --- include/srsran/cu_cp/cu_cp_e1_handler.h | 7 - lib/cu_cp/CMakeLists.txt | 1 + .../cu_cp_controller/cu_cp_controller.cpp | 23 +- lib/cu_cp/cu_cp_controller/cu_cp_controller.h | 32 +-- .../cu_up_connection_manager.cpp | 236 ++++++++++++++++++ .../cu_up_connection_manager.h | 67 +++++ lib/cu_cp/cu_cp_impl.h | 2 +- .../cu_up_processor_repository.cpp | 100 ++------ .../cu_up_processor_repository.h | 23 +- tests/unittests/cu_cp/cu_cp_test.cpp | 10 +- tests/unittests/cu_cp/cu_cp_test_helpers.cpp | 17 +- .../inter_du_handover_routine_test.cpp | 15 +- .../e1ap/cu_cp/e1ap_cu_cp_test_helpers.h | 2 + .../e1ap/gateways/e1_gateway_test.cpp | 14 -- 14 files changed, 377 insertions(+), 172 deletions(-) create mode 100644 lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp create mode 100644 lib/cu_cp/cu_cp_controller/cu_up_connection_manager.h diff --git a/include/srsran/cu_cp/cu_cp_e1_handler.h b/include/srsran/cu_cp/cu_cp_e1_handler.h index 9d0159b068..2f641be6a5 100644 --- a/include/srsran/cu_cp/cu_cp_e1_handler.h +++ b/include/srsran/cu_cp/cu_cp_e1_handler.h @@ -42,13 +42,6 @@ class cu_cp_e1_handler /// the caller lets the returned object go out of scope, the CU-UP connection will be closed. virtual std::unique_ptr handle_new_cu_up_connection(std::unique_ptr e1ap_tx_pdu_notifier) = 0; - - /// \brief Handles a remove request. The corresponding CU-UP processor object will be removed. - /// \param[in] cu_up_index The index of the CU-UP processor object to delete. - virtual void handle_cu_up_remove_request(cu_up_index_t cu_up_index) = 0; - - /// \brief Get handler to a CU-UP connected to the CU-CP. - virtual cu_up_e1_handler& get_cu_up(cu_up_index_t cu_up_index) = 0; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index 39c845343c..e3213effef 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -17,6 +17,7 @@ set(SOURCES cu_cp_controller/cu_cp_controller.cpp cu_cp_controller/amf_connection_manager.cpp cu_cp_controller/du_connection_manager.cpp + cu_cp_controller/cu_up_connection_manager.cpp cu_up_processor/cu_up_processor_impl.cpp cu_up_processor/cu_up_processor_factory.cpp cu_up_processor/cu_up_processor_repository.cpp 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 2cb0b1426b..93d2134750 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp @@ -17,21 +17,21 @@ 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_, - ue_manager& ue_mng_, - ngap_connection_manager& ngap_conn_mng_, - const cu_up_processor_repository& cu_ups_, - du_processor_repository& dus_, - task_executor& ctrl_exec_) : +cu_cp_controller::cu_cp_controller(const cu_cp_configuration& config_, + cu_cp_routine_manager& routine_manager_, + 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_), - cu_ups(cu_ups_), routine_mng(routine_manager_), 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_) + 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_) { (void)ue_mng; } @@ -49,6 +49,9 @@ void cu_cp_controller::stop() // Stop and delete DU connections. du_mng.stop(); + // Stop and delete CU-UP connections. + cu_up_mng.stop(); + // Stop AMF connection. while (not ctrl_exec.defer([this]() { stop_impl(); })) { logger.warning("Failed to dispatch CU-CP stop task. Retrying..."); @@ -98,7 +101,7 @@ bool cu_cp_controller::request_ue_setup() const return false; } - if (cu_ups.get_nof_cu_ups() == 0) { + if (cu_up_mng.nof_cu_ups() == 0) { return false; } 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 4b12ce2cfd..0a7cfab042 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h @@ -11,6 +11,7 @@ #pragma once #include "amf_connection_manager.h" +#include "cu_up_connection_manager.h" #include "du_connection_manager.h" #include "node_connection_notifier.h" #include "srsran/cu_cp/cu_cp_configuration.h" @@ -33,13 +34,13 @@ class ue_manager; class cu_cp_controller { public: - cu_cp_controller(const cu_cp_configuration& config_, - cu_cp_routine_manager& routine_manager_, - ue_manager& ue_mng_, - ngap_connection_manager& ngap_conn_mng_, - const cu_up_processor_repository& cu_ups_, - du_processor_repository& dus_, - task_executor& ctrl_exec); + cu_cp_controller(const cu_cp_configuration& config_, + cu_cp_routine_manager& routine_manager_, + ue_manager& ue_mng_, + ngap_connection_manager& ngap_conn_mng_, + cu_up_processor_repository& cu_ups_, + du_processor_repository& dus_, + task_executor& ctrl_exec); void stop(); @@ -51,19 +52,20 @@ class cu_cp_controller bool request_ue_setup() const; cu_cp_f1c_handler& get_f1c_handler() { return du_mng; } + cu_cp_e1_handler& get_e1_handler() { return cu_up_mng; } private: void stop_impl(); - const cu_cp_configuration& cfg; - ue_manager& ue_mng; - const cu_up_processor_repository& cu_ups; - cu_cp_routine_manager& routine_mng; - task_executor& ctrl_exec; - srslog::basic_logger& logger; + const cu_cp_configuration& cfg; + ue_manager& ue_mng; + cu_cp_routine_manager& routine_mng; + task_executor& ctrl_exec; + srslog::basic_logger& logger; - amf_connection_manager amf_mng; - du_connection_manager du_mng; + amf_connection_manager amf_mng; + du_connection_manager du_mng; + cu_up_connection_manager cu_up_mng; std::mutex mutex; std::condition_variable cvar; diff --git a/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp b/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp new file mode 100644 index 0000000000..cd3cd92ff1 --- /dev/null +++ b/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp @@ -0,0 +1,236 @@ +/* + * + * 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_up_connection_manager.h" +#include "../cu_up_processor/cu_up_processor_repository.h" +#include "common_task_scheduler.h" +#include "srsran/e1ap/common/e1ap_message.h" +#include "srsran/support/executors/sync_task_executor.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +/// Context of a CU-UP connection which is shared between the cu_up_connection_manager and the e1ap_message_notifier. +class cu_up_connection_manager::shared_cu_up_connection_context +{ +public: + shared_cu_up_connection_context(cu_up_connection_manager& parent_) : parent(parent_) {} + shared_cu_up_connection_context(const shared_cu_up_connection_context&) = delete; + shared_cu_up_connection_context(shared_cu_up_connection_context&&) = delete; + shared_cu_up_connection_context& operator=(const shared_cu_up_connection_context&) = delete; + shared_cu_up_connection_context& operator=(shared_cu_up_connection_context&&) = delete; + ~shared_cu_up_connection_context() { disconnect(); } + + /// Assign a CU-UP repository index to the context. This is called when the CU-UP repository is actually created. + void connect_cu_up(cu_up_index_t cu_up_idx_) + { + cu_up_idx = cu_up_idx_; + msg_handler = &parent.cu_ups.get_cu_up(cu_up_idx).get_message_handler(); + } + + /// Determines whether a CU-UP repository has been created for this connection. + bool connected() const { return msg_handler != nullptr; } + + /// Deletes the associated CU-UP repository, if it exists. + void disconnect() + { + if (not connected()) { + // CU-UP was never allocated or was already removed. + return; + } + + // Notify CU-UP that the connection is closed. + parent.handle_e1_gw_connection_closed(cu_up_idx); + + cu_up_idx = cu_up_index_t::invalid; + msg_handler = nullptr; + } + + /// Handle E1AP message coming from the CU-UP. + void handle_message(const e1ap_message& msg) + { + if (not connected()) { + parent.logger.warning("Discarding CU-UP E1AP message. Cause: CU-UP connection has been closed."); + } + + // Forward message. + msg_handler->handle_message(msg); + } + +private: + cu_up_connection_manager& parent; + cu_up_index_t cu_up_idx = cu_up_index_t::invalid; + e1ap_message_handler* msg_handler = nullptr; +}; + +/// Notifier used to forward Rx E1AP messages from the E1 GW to CU-CP in a thread safe manner. +class cu_up_connection_manager::e1_gw_to_cu_cp_pdu_adapter final : public e1ap_message_notifier +{ +public: + e1_gw_to_cu_cp_pdu_adapter(cu_up_connection_manager& parent_, + std::shared_ptr ctxt_) : + parent(parent_), ctxt(std::move(ctxt_)) + { + // Increment number of CU-UP connections. + parent.cu_up_count.fetch_add(1, std::memory_order_release); + } + + ~e1_gw_to_cu_cp_pdu_adapter() override + { + // Decrement the number of active CU-UP connections. + parent.cu_up_count.fetch_sub(1, std::memory_order_release); + + // Defer destruction of context to CU-CP execution context. + // Note: We make a copy of the shared_ptr of the context to extend its lifetime to when the defer callback actually + // gets executed. + // Note: We don't use move because the defer may fail. + while (not parent.cu_cp_exec.defer([ctxt_cpy = ctxt]() { ctxt_cpy->disconnect(); })) { + parent.logger.error("Failed to schedule CU-UP removal task. Retrying..."); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + + void on_new_message(const e1ap_message& msg) override + { + // Dispatch the E1AP Rx message handling to the CU-CP executor. + while (not parent.cu_cp_exec.execute([this, msg]() { ctxt->handle_message(msg); })) { + parent.logger.error("Failed to dispatch E1AP message to CU-CP. Retrying..."); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + +private: + cu_up_connection_manager& parent; + std::shared_ptr ctxt; +}; + +cu_up_connection_manager::cu_up_connection_manager(unsigned max_nof_cu_ups_, + cu_up_processor_repository& cu_ups_, + task_executor& cu_cp_exec_, + common_task_scheduler& common_task_sched_) : + max_nof_cu_ups(max_nof_cu_ups_), + cu_ups(cu_ups_), + cu_cp_exec(cu_cp_exec_), + common_task_sched(common_task_sched_), + logger(srslog::fetch_basic_logger("CU-CP")) +{ +} + +std::unique_ptr +cu_up_connection_manager::handle_new_cu_up_connection(std::unique_ptr e1ap_tx_pdu_notifier) +{ + // Note: This function may be called from a different execution context than the CU-CP. + + if (stopped.load(std::memory_order_acquire)) { + // CU-CP is in the process of being stopped. + return nullptr; + } + + // Verify that there is space for new CU-UP connection. + if (cu_up_count.load(std::memory_order_acquire) >= max_nof_cu_ups) { + logger.warning("Rejecting new CU-UP connection. Cause: Maximum number of CU-UPs {} reached.", max_nof_cu_ups); + return nullptr; + } + + // We create a "detached" notifier, that has no associated CU-UP processor yet. + auto shared_ctxt = std::make_shared(*this); + auto rx_pdu_notifier = std::make_unique(*this, shared_ctxt); + + // We dispatch the task to allocate a CU-UP processor and "attach" it to the notifier + while (not cu_cp_exec.execute([this, shared_ctxt, sender_notifier = std::move(e1ap_tx_pdu_notifier)]() mutable { + // Create a new CU-UP processor. + cu_up_index_t cu_up_index = cu_ups.add_cu_up(std::move(sender_notifier)); + if (cu_up_index == cu_up_index_t::invalid) { + logger.warning("Rejecting new CU-UP TNL connection. Cause: Failed to create a new CU-UP."); + return; + } + + // Register the allocated CU-UP processor index in the CU-UP connection context. + shared_ctxt->connect_cu_up(cu_up_index); + + if (not cu_up_connections.insert(std::make_pair(cu_up_index, std::move(shared_ctxt))).second) { + logger.error("Failed to store new CU-UP connection {}", cu_up_index); + return; + } + + logger.info("Added TNL connection to CU-UP {}", cu_up_index); + })) { + logger.debug("Failed to dispatch CU-CP CU-UP connection task. Retrying..."); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + return rx_pdu_notifier; +} + +void cu_up_connection_manager::handle_e1_gw_connection_closed(cu_up_index_t cu_up_idx) +{ + // Note: Called from within CU-CP execution context. + + common_task_sched.schedule_async_task(launch_async([this, cu_up_idx](coro_context>& ctx) { + CORO_BEGIN(ctx); + if (cu_up_connections.find(cu_up_idx) == cu_up_connections.end()) { + // CU-UP was already removed. + CORO_EARLY_RETURN(); + } + + // Await for clean removal of the CU-UP from the CU-UP repository. + CORO_AWAIT(cu_ups.remove_cu_up(cu_up_idx)); + + // Mark the connection as closed. + cu_up_connections.erase(cu_up_idx); + + // Flag that all CU-UPs got removed. + if (stopped and cu_up_connections.empty()) { + std::unique_lock lock(stop_mutex); + stop_completed = true; + stop_cvar.notify_one(); + } + + CORO_RETURN(); + })); +} + +void cu_up_connection_manager::stop() +{ + // Note: Called from outside of the CU-CP execution context. + stop_completed = false; + stopped = true; + + while (not cu_cp_exec.execute([this]() mutable { + if (cu_up_connections.empty()) { + // No CU-UPs connected. Notify completion. + std::unique_lock lock(stop_mutex); + stop_completed = true; + stop_cvar.notify_one(); + return; + } + + // For each created CU-UP connection context, launch the deletion routine. + std::vector cu_up_idxs; + cu_up_idxs.reserve(cu_up_connections.size()); + for (const auto& [cu_up_idx, ctxt] : cu_up_connections) { + cu_up_idxs.push_back(cu_up_idx); + } + for (cu_up_index_t cu_up_idx : cu_up_idxs) { + // Disconnect CU-UP notifier. + cu_up_connections[cu_up_idx]->disconnect(); + } + })) { + logger.debug("Failed to dispatch CU-CP CU-UP disconnection task. Retrying..."); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + // Wait for CU-UP stop to complete. + { + std::unique_lock lock(stop_mutex); + stop_cvar.wait(lock, [this] { return stop_completed; }); + } +} diff --git a/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.h b/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.h new file mode 100644 index 0000000000..179186c55a --- /dev/null +++ b/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.h @@ -0,0 +1,67 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/cu_cp/cu_cp_e1_handler.h" +#include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/support/executors/task_executor.h" +#include + +namespace srsran { +namespace srs_cu_cp { + +class cu_up_processor_repository; +class common_task_scheduler; + +/// \brief This class is responsible for allocating the resources in the CU-CP required to handle the establishment +/// or drop of E1 GW connections. +/// +/// This class acts as a facade, hiding the details associated with the dispatching of E1 GW events to the +/// the CU-CP through the appropriate task executors. +class cu_up_connection_manager : public cu_cp_e1_handler +{ +public: + cu_up_connection_manager(unsigned max_nof_cu_ups, + cu_up_processor_repository& cus_up_, + task_executor& cu_cp_exec_, + common_task_scheduler& common_task_sched_); + + std::unique_ptr + handle_new_cu_up_connection(std::unique_ptr e1ap_tx_pdu_notifier) override; + + void stop(); + + size_t nof_cu_ups() const { return cu_up_count.load(std::memory_order_relaxed); } + +private: + class shared_cu_up_connection_context; + class e1_gw_to_cu_cp_pdu_adapter; + + // Called by the E1 GW when it disconnects its PDU notifier endpoint. + void handle_e1_gw_connection_closed(cu_up_index_t cu_up_index); + + const unsigned max_nof_cu_ups; + cu_up_processor_repository& cu_ups; + task_executor& cu_cp_exec; + common_task_scheduler& common_task_sched; + srslog::basic_logger& logger; + + std::map> cu_up_connections; + std::atomic cu_up_count{0}; + + std::atomic stopped{false}; + std::mutex stop_mutex; + std::condition_variable stop_cvar; + bool stop_completed = false; +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 198c9a53bc..65577d41f0 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -111,7 +111,7 @@ class cu_cp_impl final : public cu_cp, // cu_cp public interface cu_cp_f1c_handler& get_f1c_handler() override { return controller->get_f1c_handler(); } - cu_cp_e1_handler& get_e1_handler() override { return cu_up_db; } + cu_cp_e1_handler& get_e1_handler() override { return controller->get_e1_handler(); } cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() override { return *this; } cu_cp_ng_handler& get_ng_handler() override { return *this; } cu_cp_ngap_handler& get_cu_cp_ngap_handler() override { return *this; } diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp index b0691c0704..a4396f11b5 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp @@ -17,39 +17,6 @@ using namespace srsran; using namespace srs_cu_cp; -namespace { - -class e1ap_rx_pdu_notifier final : public e1ap_message_notifier -{ -public: - e1ap_rx_pdu_notifier(cu_cp_e1_handler& parent_, cu_up_index_t cu_up_index_) : - parent(&parent_), - cu_up_index(cu_up_index_), - cached_msg_handler(parent->get_cu_up(cu_up_index).get_message_handler()) - { - } - e1ap_rx_pdu_notifier(const e1ap_rx_pdu_notifier&) = delete; - e1ap_rx_pdu_notifier(e1ap_rx_pdu_notifier&&) = delete; - e1ap_rx_pdu_notifier& operator=(const e1ap_rx_pdu_notifier&) = delete; - e1ap_rx_pdu_notifier& operator=(e1ap_rx_pdu_notifier&&) = delete; - - ~e1ap_rx_pdu_notifier() - { - if (parent != nullptr) { - parent->handle_cu_up_remove_request(cu_up_index); - } - } - - void on_new_message(const e1ap_message& msg) override { cached_msg_handler.handle_message(msg); } - -private: - cu_cp_e1_handler* parent; - cu_up_index_t cu_up_index; - e1ap_message_handler& cached_msg_handler; -}; - -} // namespace - cu_up_processor_repository::cu_up_processor_repository(cu_up_repository_config cfg_) : cfg(cfg_), logger(cfg.logger), @@ -60,26 +27,6 @@ cu_up_processor_repository::cu_up_processor_repository(cu_up_repository_config c { } -std::unique_ptr -cu_up_processor_repository::handle_new_cu_up_connection(std::unique_ptr e1ap_tx_pdu_notifier) -{ - cu_up_index_t cu_up_index = add_cu_up(std::move(e1ap_tx_pdu_notifier)); - if (cu_up_index == cu_up_index_t::invalid) { - logger.warning("Rejecting new CU-UP connection. Cause: Failed to create a new CU-UP"); - return nullptr; - } - - logger.info("Added CU-UP {}", cu_up_index); - - return std::make_unique(*this, cu_up_index); -} - -void cu_up_processor_repository::handle_cu_up_remove_request(cu_up_index_t cu_up_index) -{ - logger.debug("Removing CU-UP {}...", cu_up_index); - remove_cu_up(cu_up_index); -} - cu_up_index_t cu_up_processor_repository::add_cu_up(std::unique_ptr e1ap_tx_pdu_notifier) { cu_up_index_t cu_up_index = allocate_cu_up_index(); @@ -125,33 +72,30 @@ cu_up_index_t cu_up_processor_repository::allocate_cu_up_index() return cu_up_index_t::invalid; } -void cu_up_processor_repository::remove_cu_up(cu_up_index_t cu_up_index) +async_task cu_up_processor_repository::remove_cu_up(cu_up_index_t cu_up_index) { - // Note: The caller of this function can be a CU-UP procedure. Thus, we have to wait for the procedure to finish - // before safely removing the DU. This is achieved via a scheduled async task - srsran_assert(cu_up_index != cu_up_index_t::invalid, "Invalid cu_up_index={}", cu_up_index); - logger.debug("Scheduling cu_up_index={} deletion", cu_up_index); - - // Schedule CU-UP removal task - cu_up_task_sched.handle_cu_up_async_task( - cu_up_index, launch_async([this, cu_up_index](coro_context>& ctx) { - CORO_BEGIN(ctx); - auto du_it = cu_up_db.find(cu_up_index); - if (du_it == cu_up_db.end()) { - logger.warning("Remove CU-UP called for inexistent cu_up_index={}", cu_up_index); - CORO_EARLY_RETURN(); - } - - // Remove DU - // TODO - removed_cu_up_db.insert(std::make_pair(cu_up_index, std::move(cu_up_db.at(cu_up_index)))); - cu_up_db.erase(cu_up_index); - - logger.info("Removed CU-UP {}", cu_up_index); - - CORO_RETURN(); - })); + logger.debug("Removing CU-UP {}...", cu_up_index); + + return launch_async([this, cu_up_index](coro_context>& ctx) { + CORO_BEGIN(ctx); + + // Remove CU-UP + if (cu_up_db.find(cu_up_index) == cu_up_db.end()) { + logger.warning("Remove CU-UP called for non-existent cu_up_index={}", cu_up_index); + return; + } + + // Stop CU-UP activity, eliminating pending transactions for the CU-UP and respective UEs. + // TODO + removed_cu_up_db.insert(std::make_pair(cu_up_index, std::move(cu_up_db.at(cu_up_index)))); + cu_up_db.erase(cu_up_index); + + // Remove DU + logger.info("Removed CU-UP {}", cu_up_index); + + CORO_RETURN(); + }); } cu_up_e1_handler& cu_up_processor_repository::get_cu_up(cu_up_index_t cu_up_index) diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h index ca29fc433d..56e4705630 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h @@ -27,19 +27,22 @@ struct cu_up_repository_config { srslog::basic_logger& logger; }; -class cu_up_processor_repository : public cu_cp_e1_handler +class cu_up_processor_repository { public: explicit cu_up_processor_repository(cu_up_repository_config cfg_); - // CU-UP interface - std::unique_ptr - handle_new_cu_up_connection(std::unique_ptr e1ap_tx_pdu_notifier) override; - void handle_cu_up_remove_request(cu_up_index_t cu_up_index) override; + /// \brief Adds a CU-UP processor object to the CU-CP. + /// \return The CU-UP index of the added CU-UP processor object. + cu_up_index_t add_cu_up(std::unique_ptr e1ap_tx_pdu_notifier); + + /// \brief Removes the specified CU-UP processor object from the CU-CP. + /// \param[in] cu_up_index The index of the CU-UP processor to delete. + async_task remove_cu_up(cu_up_index_t cu_up_index); size_t get_nof_cu_ups() const { return cu_up_db.size(); } - cu_up_e1_handler& get_cu_up(cu_up_index_t cu_up_index) override; + cu_up_e1_handler& get_cu_up(cu_up_index_t cu_up_index); /// \brief Find a CU-UP object. /// \param[in] cu_up_index The index of the CU-UP processor object. @@ -58,14 +61,6 @@ class cu_up_processor_repository : public cu_cp_e1_handler e1ap_message_handler& get_message_handler() override; }; - /// \brief Adds a CU-UP processor object to the CU-CP. - /// \return The CU-UP index of the added CU-UP processor object. - cu_up_index_t add_cu_up(std::unique_ptr e1ap_tx_pdu_notifier); - - /// \brief Removes the specified CU-UP processor object from the CU-CP. - /// \param[in] cu_up_index The index of the CU-UP processor to delete. - void remove_cu_up(cu_up_index_t cu_up_index); - /// \brief Get the next available index from the CU-UP processor database. /// \return The CU-UP index. cu_up_index_t allocate_cu_up_index(); diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index 5fd8fc1cda..ff806db329 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -507,10 +507,7 @@ TEST_F(cu_cp_test, when_handover_request_received_then_handover_notify_is_sent) // 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)); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_ctxt_setup_resp); + 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); @@ -532,10 +529,7 @@ TEST_F(cu_cp_test, when_handover_request_received_then_handover_notify_is_sent) // 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)); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_ctxt_mod_resp); + 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); diff --git a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp index 0222342f1d..1a369cde39 100644 --- a/tests/unittests/cu_cp/cu_cp_test_helpers.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_helpers.cpp @@ -267,7 +267,7 @@ void cu_cp_test::test_e1ap_attach() // Pass E1SetupRequest to the CU-CP e1ap_message e1setup_msg = generate_valid_cu_up_e1_setup_request(); - cu_cp_obj->get_e1_handler().get_cu_up(uint_to_cu_up_index(0)).get_message_handler().handle_message(e1setup_msg); + 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) @@ -314,10 +314,7 @@ void cu_cp_test::add_pdu_sessions(std::vector psis, // 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); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_context_setup_resp); + 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); @@ -326,10 +323,7 @@ void cu_cp_test::add_pdu_sessions(std::vector psis, // 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); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_context_mod_resp); + 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 @@ -358,10 +352,7 @@ void cu_cp_test::add_pdu_sessions(std::vector psis, // 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); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_context_mod_resp); + 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); 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 index d013d61a80..b2c0a76d6e 100644 --- a/tests/unittests/cu_cp/mobility/inter_du_handover_routine_test.cpp +++ b/tests/unittests/cu_cp/mobility/inter_du_handover_routine_test.cpp @@ -104,10 +104,7 @@ class inter_du_handover_routine_test : public mobility_test { 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)); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_context_modification_fail); + e1ap_gw.get_cu_up(0).on_new_message(bearer_context_modification_fail); } /// \brief Inject Bearer Context Modification Response. @@ -115,10 +112,7 @@ class inter_du_handover_routine_test : public mobility_test { 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)); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_context_modification_resp); + e1ap_gw.get_cu_up(0).on_new_message(bearer_context_modification_resp); } /// \brief Inject Bearer Context Release Complete. @@ -126,10 +120,7 @@ class inter_du_handover_routine_test : public mobility_test { 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)); - cu_cp_obj->get_e1_handler() - .get_cu_up(uint_to_cu_up_index(0)) - .get_message_handler() - .handle_message(bearer_context_release_complete); + e1ap_gw.get_cu_up(0).on_new_message(bearer_context_release_complete); } /// \brief Inject UE Context Modification Response. diff --git a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h index 644efec756..4af8a6d903 100644 --- a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h +++ b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h @@ -83,6 +83,8 @@ class dummy_cu_cp_e1ap_gateway cu_up_tx_notifiers.erase(cu_up_tx_notifiers.begin() + connection_idx); } + e1ap_message_notifier& get_cu_up(size_t connection_idx) { return *cu_up_tx_notifiers.at(connection_idx); } + span last_rx_pdus(size_t connection_idx) const { return local_e1ap_gw.get_last_cu_cp_rx_pdus(connection_idx); diff --git a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp index a3ddf222f9..307861f7d4 100644 --- a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp +++ b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp @@ -91,20 +91,6 @@ class e1_link : public srs_cu_cp::cu_cp_e1_handler return std::make_unique("CU-CP", cu_rx_pdus, std::move(eof_signal)); } - void handle_cu_up_remove_request(srs_cu_cp::cu_up_index_t cu_up_index) override {} - - srs_cu_cp::cu_up_e1_handler& get_cu_up(srs_cu_cp::cu_up_index_t cu_up_index) override - { - class dummy_cu_up_e1_handler : public srs_cu_cp::cu_up_e1_handler, public e1ap_message_handler - { - public: - e1ap_message_handler& get_message_handler() override { return *this; } - void handle_message(const e1ap_message& msg) override {} - }; - static dummy_cu_up_e1_handler dummy; - return dummy; - } - std::unique_ptr broker; dummy_dlt_pcap pcap; std::unique_ptr connector; From 6663e05120f99a94ab8dbaaea341f1ae63c11f79 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 10:07:18 +0200 Subject: [PATCH 10/34] e1ap: fix names of e1 gateways --- .../gateways/e1_local_connector_factory.h | 2 + .../e1ap/gateways/e1_network_client_factory.h | 5 ++- .../e1ap/gateways/e1_network_server_factory.h | 6 +-- .../cu_up_processor_repository.cpp | 4 +- .../gateways/e1_local_connector_factory.cpp | 10 ++--- .../gateways/e1_network_client_factory.cpp | 12 +++--- .../gateways/e1_network_server_factory.cpp | 11 ++--- .../e1ap/gateways/e1_gateway_test.cpp | 40 +++++++++---------- 8 files changed, 48 insertions(+), 42 deletions(-) diff --git a/include/srsran/e1ap/gateways/e1_local_connector_factory.h b/include/srsran/e1ap/gateways/e1_local_connector_factory.h index f48c05fc02..830dcb1f79 100644 --- a/include/srsran/e1ap/gateways/e1_local_connector_factory.h +++ b/include/srsran/e1ap/gateways/e1_local_connector_factory.h @@ -35,6 +35,8 @@ struct e1_local_sctp_connector_config { dlt_pcap& pcap; /// IO broker to handle the SCTP Rx data and notifications. io_broker& broker; + /// Port to bind the SCTP socket. + int bind_port = 0; }; /// Creates an E1 local connector using an SCTP socket as channel. diff --git a/include/srsran/e1ap/gateways/e1_network_client_factory.h b/include/srsran/e1ap/gateways/e1_network_client_factory.h index f0d7ee3506..fc85fb93a9 100644 --- a/include/srsran/e1ap/gateways/e1_network_client_factory.h +++ b/include/srsran/e1ap/gateways/e1_network_client_factory.h @@ -18,7 +18,8 @@ namespace srsran { class dlt_pcap; class io_broker; -struct e1_du_sctp_gateway_config { +/// Configuration of an SCTP-based E1 Gateway in the CU-UP. +struct e1_cu_up_sctp_gateway_config { /// SCTP configuration. sctp_network_connector_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. @@ -28,6 +29,6 @@ struct e1_du_sctp_gateway_config { }; /// \brief Create an E1 gateway connector that the CU-UP can use to connect to the CU-CP. -std::unique_ptr create_e1_gateway_client(const e1_du_sctp_gateway_config& params); +std::unique_ptr create_e1_gateway_client(const e1_cu_up_sctp_gateway_config& params); } // namespace srsran diff --git a/include/srsran/e1ap/gateways/e1_network_server_factory.h b/include/srsran/e1ap/gateways/e1_network_server_factory.h index 51e7681fff..059842f8a9 100644 --- a/include/srsran/e1ap/gateways/e1_network_server_factory.h +++ b/include/srsran/e1ap/gateways/e1_network_server_factory.h @@ -19,8 +19,8 @@ namespace srsran { class dlt_pcap; class io_broker; -/// Configuration of an SCTP-based E1 Gateway. -struct e1_cu_sctp_gateway_config { +/// Configuration of an SCTP-based E1 Gateway in the CU-CP. +struct e1_cu_cp_sctp_gateway_config { /// SCTP configuration. sctp_network_gateway_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. @@ -31,6 +31,6 @@ struct e1_cu_sctp_gateway_config { /// Creates an E1 Gateway server that listens for incoming SCTP connections, packs/unpacks E1AP PDUs and forwards /// them to the GW/CU-CP E1AP handler. -std::unique_ptr create_e1_gateway_server(const e1_cu_sctp_gateway_config& params); +std::unique_ptr create_e1_gateway_server(const e1_cu_cp_sctp_gateway_config& params); } // namespace srsran diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp index a4396f11b5..4713bf89f7 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp @@ -88,10 +88,12 @@ async_task cu_up_processor_repository::remove_cu_up(cu_up_index_t cu_up_in // Stop CU-UP activity, eliminating pending transactions for the CU-UP and respective UEs. // TODO + + // Remove CU-UP removed_cu_up_db.insert(std::make_pair(cu_up_index, std::move(cu_up_db.at(cu_up_index)))); cu_up_db.erase(cu_up_index); - // Remove DU + // Remove CU-UP logger.info("Removed CU-UP {}", cu_up_index); CORO_RETURN(); diff --git a/lib/e1ap/gateways/e1_local_connector_factory.cpp b/lib/e1ap/gateways/e1_local_connector_factory.cpp index 6749fa46fc..985fa45b88 100644 --- a/lib/e1ap/gateways/e1_local_connector_factory.cpp +++ b/lib/e1ap/gateways/e1_local_connector_factory.cpp @@ -66,7 +66,7 @@ class e1_local_connector_impl final : public e1_local_connector { report_fatal_error_if_not(cu_cp_e1_mng != nullptr, "CU-CP has not been attached to E1 gateway."); - // Decorate DU RX notifier with pcap writing. + // Decorate CU-UP RX notifier with pcap writing. if (pcap_writer.is_write_enabled()) { cu_up_notifier = std::make_unique( std::move(cu_up_notifier), pcap_writer, srslog::fetch_basic_logger("CU-UP-E1")); @@ -89,7 +89,7 @@ class e1_local_connector_impl final : public e1_local_connector srs_cu_cp::cu_cp_e1_handler* cu_cp_e1_mng = nullptr; }; -/// Implementation of a CU-UP and CU-CP E1 SCTP-based gateway for the case that the DU and CU-CP are co-located. +/// Implementation of a CU-UP and CU-CP E1 SCTP-based gateway for the case that the CU-UP and CU-CP are co-located. /// /// Note: This class should only be used for testing purposes. class e1_sctp_connector_impl final : public e1_local_connector @@ -103,8 +103,8 @@ class e1_sctp_connector_impl final : public e1_local_connector sctp.ppid = E1AP_PPID; sctp.bind_address = "127.0.0.1"; // Use any bind port available. - sctp.bind_port = 0; - server = create_e1_gateway_server(e1_cu_sctp_gateway_config{sctp, broker, pcap_writer}); + sctp.bind_port = cfg.bind_port; + server = create_e1_gateway_server(e1_cu_cp_sctp_gateway_config{sctp, broker, pcap_writer}); } void attach_cu_cp(srs_cu_cp::cu_cp_e1_handler& cu_e1_handler_) override @@ -119,7 +119,7 @@ class e1_sctp_connector_impl final : public e1_local_connector sctp_client.connect_port = server->get_listen_port().value(); sctp_client.ppid = E1AP_PPID; // Note: We only need to save the PCAPs in one side of the connection. - client = create_e1_gateway_client(e1_du_sctp_gateway_config{sctp_client, broker, *null_pcap_writer}); + client = create_e1_gateway_client(e1_cu_up_sctp_gateway_config{sctp_client, broker, *null_pcap_writer}); } std::optional get_listen_port() const override { return server->get_listen_port(); } diff --git a/lib/e1ap/gateways/e1_network_client_factory.cpp b/lib/e1ap/gateways/e1_network_client_factory.cpp index a1991fc3e2..de3a1d85a3 100644 --- a/lib/e1ap/gateways/e1_network_client_factory.cpp +++ b/lib/e1ap/gateways/e1_network_client_factory.cpp @@ -24,10 +24,10 @@ namespace { class sctp_to_e1_pdu_notifier final : public sctp_association_sdu_notifier { public: - sctp_to_e1_pdu_notifier(std::unique_ptr du_rx_pdu_notifier_, + sctp_to_e1_pdu_notifier(std::unique_ptr cu_up_rx_pdu_notifier_, dlt_pcap& pcap_writer_, srslog::basic_logger& logger_) : - du_rx_pdu_notifier(std::move(du_rx_pdu_notifier_)), pcap_writer(pcap_writer_), logger(logger_) + cu_up_rx_pdu_notifier(std::move(cu_up_rx_pdu_notifier_)), pcap_writer(pcap_writer_), logger(logger_) { } @@ -47,13 +47,13 @@ class sctp_to_e1_pdu_notifier final : public sctp_association_sdu_notifier } // Forward unpacked Rx PDU to the CU-UP. - du_rx_pdu_notifier->on_new_message(msg); + cu_up_rx_pdu_notifier->on_new_message(msg); return true; } private: - std::unique_ptr du_rx_pdu_notifier; + std::unique_ptr cu_up_rx_pdu_notifier; dlt_pcap& pcap_writer; srslog::basic_logger& logger; }; @@ -98,7 +98,7 @@ class e1_to_sctp_pdu_notifier final : public e1ap_message_notifier class e1_sctp_gateway_client final : public srs_cu_up::e1_connection_client { public: - e1_sctp_gateway_client(const e1_du_sctp_gateway_config& params) : + e1_sctp_gateway_client(const e1_cu_up_sctp_gateway_config& params) : pcap_writer(params.pcap), broker(params.broker), sctp_params(params.sctp) { // Create SCTP network adapter. @@ -152,7 +152,7 @@ class e1_sctp_gateway_client final : public srs_cu_up::e1_connection_client } // namespace std::unique_ptr -srsran::create_e1_gateway_client(const e1_du_sctp_gateway_config& params) +srsran::create_e1_gateway_client(const e1_cu_up_sctp_gateway_config& params) { return std::make_unique(params); } diff --git a/lib/e1ap/gateways/e1_network_server_factory.cpp b/lib/e1ap/gateways/e1_network_server_factory.cpp index 07e290da14..e1f9c83107 100644 --- a/lib/e1ap/gateways/e1_network_server_factory.cpp +++ b/lib/e1ap/gateways/e1_network_server_factory.cpp @@ -98,7 +98,7 @@ class gw_to_e1_pdu_notifier final : public sctp_association_sdu_notifier class e1_sctp_server final : public srs_cu_cp::e1_connection_server, public sctp_network_association_factory { public: - e1_sctp_server(const e1_cu_sctp_gateway_config& params_) : params(params_) + e1_sctp_server(const e1_cu_cp_sctp_gateway_config& params_) : params(params_) { // Create SCTP server. sctp_server = create_sctp_network_server(sctp_network_server_config{params.sctp, params.broker, *this}); @@ -138,16 +138,17 @@ class e1_sctp_server final : public srs_cu_cp::e1_connection_server, public sctp } private: - const e1_cu_sctp_gateway_config params; - srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP-E1"); - srs_cu_cp::cu_cp_e1_handler* cu_e1_handler = nullptr; + const e1_cu_cp_sctp_gateway_config params; + srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP-E1"); + srs_cu_cp::cu_cp_e1_handler* cu_e1_handler = nullptr; std::unique_ptr sctp_server; }; } // namespace -std::unique_ptr srsran::create_e1_gateway_server(const e1_cu_sctp_gateway_config& cfg) +std::unique_ptr +srsran::create_e1_gateway_server(const e1_cu_cp_sctp_gateway_config& cfg) { return std::make_unique(cfg); } diff --git a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp index 307861f7d4..517e84180b 100644 --- a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp +++ b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp @@ -83,7 +83,7 @@ class e1_link : public srs_cu_cp::cu_cp_e1_handler // Note: May be called from io broker thread. cu_cp_tx_pdu_notifier = std::move(e1ap_tx_pdu_notifier); std::promise eof_signal; - cu_gw_assoc_close_signaled = eof_signal.get_future(); + cu_cp_gw_assoc_close_signaled = eof_signal.get_future(); logger.info("CU-CP handled new DU connection"); connection_complete_signal.set_value(); @@ -97,21 +97,21 @@ class e1_link : public srs_cu_cp::cu_cp_e1_handler srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); blocking_queue cu_rx_pdus{128}; - blocking_queue du_rx_pdus{128}; + blocking_queue cu_up_rx_pdus{128}; - std::future cu_gw_assoc_close_signaled; - std::future du_gw_assoc_close_signaled; + std::future cu_cp_gw_assoc_close_signaled; + std::future cu_up_gw_assoc_close_signaled; std::unique_ptr cu_cp_tx_pdu_notifier; - std::unique_ptr du_tx_pdu_notifier; + std::unique_ptr cu_up_tx_pdu_notifier; protected: void connect_client() { // Connect client to server. std::promise eof_signal; - du_gw_assoc_close_signaled = eof_signal.get_future(); - du_tx_pdu_notifier = connector->handle_cu_up_connection_request( - std::make_unique("CU-UP", du_rx_pdus, std::move(eof_signal))); + cu_up_gw_assoc_close_signaled = eof_signal.get_future(); + cu_up_tx_pdu_notifier = connector->handle_cu_up_connection_request( + std::make_unique("CU-UP", cu_up_rx_pdus, std::move(eof_signal))); // Wait for server to receive connection. std::future connection_completed = connection_complete_signal.get_future(); @@ -143,7 +143,7 @@ class e1_gateway_link_test : public ::testing::TestWithParam void send_to_cu_up(const e1ap_message& msg) { link->cu_cp_tx_pdu_notifier->on_new_message(msg); } - void send_to_cu_cp(const e1ap_message& msg) { link->du_tx_pdu_notifier->on_new_message(msg); } + void send_to_cu_cp(const e1ap_message& msg) { link->cu_up_tx_pdu_notifier->on_new_message(msg); } bool pop_cu_rx_pdu(e1ap_message& msg) { @@ -152,10 +152,10 @@ class e1_gateway_link_test : public ::testing::TestWithParam return res; } - bool pop_du_rx_pdu(e1ap_message& msg) + bool pop_cu_up_rx_pdu(e1ap_message& msg) { bool res; - msg = link->du_rx_pdus.pop_blocking(&res); + msg = link->cu_up_rx_pdus.pop_blocking(&res); return res; } @@ -190,7 +190,7 @@ static bool is_equal(const e1ap_message& lhs, const e1ap_message& rhs) return lhs_pdu == rhs_pdu; } -TEST_P(e1_gateway_link_test, when_du_sends_msg_then_cu_receives_msg) +TEST_P(e1_gateway_link_test, when_cu_up_sends_msg_then_cu_receives_msg) { create_link(); @@ -202,7 +202,7 @@ TEST_P(e1_gateway_link_test, when_du_sends_msg_then_cu_receives_msg) ASSERT_TRUE(is_equal(orig_msg, dest_msg)); } -TEST_P(e1_gateway_link_test, when_cu_sends_msg_then_du_receives_msg) +TEST_P(e1_gateway_link_test, when_cu_cp_sends_msg_then_cu_up_receives_msg) { create_link(); @@ -210,7 +210,7 @@ TEST_P(e1_gateway_link_test, when_cu_sends_msg_then_du_receives_msg) send_to_cu_up(orig_msg); e1ap_message dest_msg; - ASSERT_TRUE(pop_du_rx_pdu(dest_msg)); + ASSERT_TRUE(pop_cu_up_rx_pdu(dest_msg)); ASSERT_TRUE(is_equal(orig_msg, dest_msg)); } @@ -221,7 +221,7 @@ TEST_P(e1_gateway_link_test, when_pcap_writer_disabled_then_no_pcap_is_written) e1ap_message orig_msg = create_test_message(); send_to_cu_up(orig_msg); e1ap_message dest_msg; - ASSERT_TRUE(pop_du_rx_pdu(dest_msg)); + ASSERT_TRUE(pop_cu_up_rx_pdu(dest_msg)); byte_buffer sdu; ASSERT_FALSE(link->pcap.last_sdus.try_pop(sdu)); @@ -238,7 +238,7 @@ TEST_P(e1_gateway_link_test, when_pcap_writer_enabled_then_pcap_is_written) send_to_cu_up(orig_msg); e1ap_message dest_msg; - ASSERT_TRUE(pop_du_rx_pdu(dest_msg)); + ASSERT_TRUE(pop_cu_up_rx_pdu(dest_msg)); bool popped = false; byte_buffer sdu = link->pcap.last_sdus.pop_blocking(&popped); ASSERT_TRUE(popped); @@ -260,8 +260,8 @@ TEST_P(e1_gateway_link_test, when_cu_tx_pdu_notifier_is_closed_then_connection_c logger.info("Closing CU-CP Tx path..."); link->cu_cp_tx_pdu_notifier.reset(); - // Wait for GW to report to DU that the association is closed. - link->du_gw_assoc_close_signaled.wait(); + // Wait for GW to report to CU-UP that the association is closed. + link->cu_up_gw_assoc_close_signaled.wait(); } TEST_P(e1_gateway_link_test, when_cu_up_tx_pdu_notifier_is_closed_then_connection_closes) @@ -270,10 +270,10 @@ TEST_P(e1_gateway_link_test, when_cu_up_tx_pdu_notifier_is_closed_then_connectio // The CU-UP resets its E1 Tx notifier. logger.info("Closing CU-UP Tx path..."); - link->du_tx_pdu_notifier.reset(); + link->cu_up_tx_pdu_notifier.reset(); // Wait for GW to report to CU that the association is closed. - link->cu_gw_assoc_close_signaled.wait(); + link->cu_cp_gw_assoc_close_signaled.wait(); } INSTANTIATE_TEST_SUITE_P(e1_gateway_link_tests, e1_gateway_link_test, ::testing::Values(true, false)); From dc16d6d92426c979a063d7db5c6f5dadf0e52573 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 15 Jul 2024 12:14:47 +0200 Subject: [PATCH 11/34] fix race condition in DRB stop --- lib/du_manager/du_ue/du_ue_adapters.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/du_manager/du_ue/du_ue_adapters.h b/lib/du_manager/du_ue/du_ue_adapters.h index 6ccfafdfde..a17346a1be 100644 --- a/lib/du_manager/du_ue/du_ue_adapters.h +++ b/lib/du_manager/du_ue/du_ue_adapters.h @@ -229,10 +229,9 @@ class rlc_tx_mac_buffer_state_updater : public rlc_tx_lower_layer_notifier void disconnect() { - lcid_t prev_lcid = lcid.exchange(INVALID_LCID); - if (prev_lcid != INVALID_LCID) { + if (connected.exchange(false, std::memory_order_relaxed)) { // Push an empty buffer state update to MAC, so the scheduler doesn't keep allocating grants for this bearer. - mac->handle_dl_buffer_state_update(mac_dl_buffer_state_indication_message{ue_index, prev_lcid, 0}); + mac->handle_dl_buffer_state_update(mac_dl_buffer_state_indication_message{ue_index, lcid, 0}); } } @@ -241,18 +240,19 @@ class rlc_tx_mac_buffer_state_updater : public rlc_tx_lower_layer_notifier srsran_assert(mac != nullptr, "RLC Tx Buffer State notifier is disconnected"); mac_dl_buffer_state_indication_message bs{}; bs.ue_index = ue_index; - bs.lcid = lcid.load(std::memory_order_relaxed); + bs.lcid = lcid; bs.bs = bsr; - if (SRSRAN_UNLIKELY(bs.lcid == INVALID_LCID)) { + if (SRSRAN_UNLIKELY(not connected.load(std::memory_order_relaxed))) { // Discard. - return; + bs.bs = 0; } mac->handle_dl_buffer_state_update(bs); } private: du_ue_index_t ue_index = INVALID_DU_UE_INDEX; - std::atomic lcid{INVALID_LCID}; + std::atomic connected{true}; + lcid_t lcid; mac_ue_control_information_handler* mac = nullptr; }; From 78e0cd20835693a382cafbf9f1f4593d24b75107 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 10:40:57 +0200 Subject: [PATCH 12/34] du-high: fix du-high unit test --- tests/integrationtests/du_high/du_high_test.cpp | 11 +++++++++-- tests/unittests/du_manager/du_ue/ue_manager_test.cpp | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index 27d9a53151..230059e817 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -158,12 +158,19 @@ TEST_F(du_high_tester, when_ue_context_setup_release_starts_then_drb_activity_st this->test_logger.info("STATUS: RRC Release started being scheduled..."); // Ensure that DRBs stop being scheduled at this point, even if it takes a while for the UE release to complete. + unsigned drb_data_count = 0; while (cu_notifier.last_f1ap_msgs.empty()) { run_slot(); const dl_msg_alloc* pdsch = find_ue_pdsch(rnti, phy.cells[0].last_dl_res.value().dl_res->ue_grants); if (pdsch != nullptr) { - // PDSCH scheduled. Ensure it was for SRB1 (DRB1 might fill the rest of the TB though). - ASSERT_NE(find_ue_pdsch_with_lcid(rnti, LCID_SRB1, phy.cells[0].last_dl_res.value().dl_res->ue_grants), nullptr); + // PDSCH scheduled. Ensure it was for SRB1. + // Note: There might be at most one single DRB1 PDSCH that smuggles in after the RRC Release due to race + // conditions. + auto* drb_pdsch = find_ue_pdsch_with_lcid(rnti, LCID_MIN_DRB, phy.cells[0].last_dl_res.value().dl_res->ue_grants); + if (drb_pdsch != nullptr) { + drb_data_count++; + ASSERT_LT(drb_data_count, 2) << "More than 1 PDSCH grant for DRB data was scheduled after RRC Release"; + } } } } 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 a87e7e4d0c..29d1724997 100644 --- a/tests/unittests/du_manager/du_ue/ue_manager_test.cpp +++ b/tests/unittests/du_manager/du_ue/ue_manager_test.cpp @@ -277,7 +277,7 @@ TEST_F(du_ue_manager_tester, when_ue_is_being_removed_then_ue_notifiers_get_disc // TEST: UE notifiers are disconnected. mac_dummy.last_dl_bs.reset(); srb1.on_buffer_state_update(10); - ASSERT_FALSE(mac_dummy.last_dl_bs.has_value()); + ASSERT_TRUE(not mac_dummy.last_dl_bs.has_value() or mac_dummy.last_dl_bs.value().bs == 0); } class du_ue_manager_rlf_tester : public du_ue_manager_tester From 289a26fdc149ffa92e34da512f128b30500f2f46 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 16 Jul 2024 11:33:55 +0200 Subject: [PATCH 13/34] sched: do not allocate remaining RBs if the PUSCH grant is for a pending SR --- lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index b559d85598..a5937ceabe 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -691,7 +691,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra if (not is_retx) { // [Implementation-defined] Check whether max. UL grants per slot is reached if PUSCH for current UE succeeds. If // so, allocate remaining RBs to the current UE only if it's a new Tx. - if (pusch_pdu_rem_space == 1) { + if (pusch_pdu_rem_space == 1 and not u.has_pending_sr()) { mcs_prbs.n_prbs = rb_helper::find_empty_interval_of_length(used_crbs, used_crbs.size(), 0).length(); } // Due to the pre-allocated UCI bits, MCS 0 and PRB 1 would not leave any space for the payload on the TBS, as From d7048d540483996c0b64ec0863ac10cc212cccb6 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 16 Jul 2024 11:34:54 +0200 Subject: [PATCH 14/34] unittest: add test to verify PUSCH grant for a pending SR is not allocated with all remaining RBs --- .../ue_scheduling/ue_grid_allocator_test.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) 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 2deeb02594..4e9d40f1f3 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -317,6 +317,30 @@ TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_n ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), grant1.max_nof_rbs); } +TEST_P(ue_grid_allocator_tester, does_not_allocate_pusch_with_all_remaining_rbs_if_its_a_sr_indication) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + ue& u1 = add_ue(ue_creation_req); + // Trigger a SR indication. + u1.handle_sr_indication(); + + const ue_pusch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .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).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()); +} + TEST_P(ue_grid_allocator_tester, no_two_pdschs_are_allocated_in_same_slot_for_a_ue) { static const unsigned nof_bytes_to_schedule = 400U; From c20be7b35e8e9afbd7e3cd54fbca813ff2999297 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 16 Jul 2024 13:38:53 +0200 Subject: [PATCH 15/34] cu_cp,f1ap: add function to return 5g-s-tmsi as number --- include/srsran/cu_cp/cu_cp_types.h | 2 ++ lib/f1ap/cu_cp/f1ap_asn1_converters.h | 8 -------- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/include/srsran/cu_cp/cu_cp_types.h b/include/srsran/cu_cp/cu_cp_types.h index f376dda83b..63d12ef1d1 100644 --- a/include/srsran/cu_cp/cu_cp_types.h +++ b/include/srsran/cu_cp/cu_cp_types.h @@ -150,6 +150,8 @@ struct cu_cp_five_g_s_tmsi { return (five_g_s_tmsi.value().to_uint64() & 0xffffffff); }; + uint64_t to_number() const { return five_g_s_tmsi->to_uint64(); } + std::optional> five_g_s_tmsi; }; diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 2b98ad38e4..01b652f04b 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -557,14 +557,6 @@ f1ap_rrc_recfg_complete_ind_to_asn1(const f1ap_rrc_recfg_complete_ind& rrc_recfg return asn1_rrc_recfg_complete_ind; } -/// \brief Calculate the 5G-S-TMSI from the common type 5G-S-TMSI struct. -inline uint64_t five_g_s_tmsi_struct_to_number(const cu_cp_five_g_s_tmsi& five_g_s_tmsi) -{ - // 5G-S-TMSI is a 48 bit string consisting of <5G-TMSI (32 bit)> - return ((uint64_t)five_g_s_tmsi.get_amf_set_id() << 38) + ((uint64_t)five_g_s_tmsi.get_amf_pointer() << 32) + - five_g_s_tmsi.get_five_g_tmsi(); -} - /// \brief Convert F1AP ASN.1 to \c cu_cp_tx_bw. /// \param[in] asn1_tx_bw The ASN.1 type tx bw. /// \return The common type tx bw. diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index c705698f14..57cab185a3 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -468,7 +468,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat inline void fill_asn1_paging_message(asn1::f1ap::paging_s& asn1_paging, const cu_cp_paging_message& paging) { // Add ue id idx value - uint64_t five_g_s_tmsi = five_g_s_tmsi_struct_to_number(paging.ue_paging_id); + uint64_t five_g_s_tmsi = paging.ue_paging_id.to_number(); // UE Identity Index value is defined as: UE_ID 5G-S-TMSI mod 1024 (see TS 38.304 section 7.1) asn1_paging->ue_id_idx_value.set_idx_len10().from_number(five_g_s_tmsi % 1024); From 7dc1daaa44ba051d5a215c29e48ace322cca372c Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 16 Jul 2024 14:26:22 +0200 Subject: [PATCH 16/34] cu_cp,ngap: add constructors to cu_cp_five_g_s_tmsi --- include/srsran/cu_cp/cu_cp_types.h | 15 +++++++++++++++ lib/ngap/ngap_asn1_converters.h | 10 +++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/srsran/cu_cp/cu_cp_types.h b/include/srsran/cu_cp/cu_cp_types.h index 63d12ef1d1..af7f69daf1 100644 --- a/include/srsran/cu_cp/cu_cp_types.h +++ b/include/srsran/cu_cp/cu_cp_types.h @@ -132,6 +132,20 @@ struct cu_cp_amf_identifier_t { }; struct cu_cp_five_g_s_tmsi { + cu_cp_five_g_s_tmsi() = default; + + cu_cp_five_g_s_tmsi(const bounded_bitset<48>& five_g_s_tmsi_) : five_g_s_tmsi(five_g_s_tmsi_) + { + srsran_assert(five_g_s_tmsi_.size() == 48, "Invalid size for 5G-S-TMSI ({})", five_g_s_tmsi_.size()); + } + + cu_cp_five_g_s_tmsi(uint64_t amf_set_id, uint64_t amf_pointer, uint64_t five_g_tmsi) + { + five_g_s_tmsi.emplace(); + five_g_s_tmsi->resize(48); + five_g_s_tmsi->from_uint64((amf_set_id << 38U) + (amf_pointer << 32U) + five_g_tmsi); + } + uint16_t get_amf_set_id() const { srsran_assert(five_g_s_tmsi.has_value(), "five_g_s_tmsi is not set"); @@ -152,6 +166,7 @@ struct cu_cp_five_g_s_tmsi { uint64_t to_number() const { return five_g_s_tmsi->to_uint64(); } +private: std::optional> five_g_s_tmsi; }; diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index 85f0444b8a..47e4f3fc4b 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -844,13 +844,9 @@ inline cu_cp_five_g_s_tmsi ngap_asn1_to_ue_paging_id(const asn1::ngap::ue_paging srsran_assert(asn1_ue_id.type() == asn1::ngap::ue_paging_id_c::types_opts::five_g_s_tmsi, "Invalid UE paging ID type"); - bounded_bitset<48> five_g_s_tmsi(48); - - five_g_s_tmsi.from_uint64(((uint64_t)asn1_ue_id.five_g_s_tmsi().amf_set_id.to_number() << 38U) + - ((uint64_t)asn1_ue_id.five_g_s_tmsi().amf_pointer.to_number() << 32U) + - asn1_ue_id.five_g_s_tmsi().five_g_tmsi.to_number()); - - return cu_cp_five_g_s_tmsi{five_g_s_tmsi}; + return cu_cp_five_g_s_tmsi{asn1_ue_id.five_g_s_tmsi().amf_set_id.to_number(), + asn1_ue_id.five_g_s_tmsi().amf_pointer.to_number(), + asn1_ue_id.five_g_s_tmsi().five_g_tmsi.to_number()}; } } // namespace srs_cu_cp From 2d053e15f7bc3fe8b65c525753c33467fffb557c Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 16 Jul 2024 11:51:49 +0200 Subject: [PATCH 17/34] ci,e2e: increase default e2e timeout --- .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 c1fd386e63..407f2eda3a 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -110,7 +110,7 @@ e2e request and config validation: .e2e-run: resource_group: e2e-${GROUP} - timeout: 2h + timeout: 3 hours image: name: ${RETINA_REGISTRY_PREFIX}/launcher:${RETINA_VERSION} entrypoint: ["/bin/sh", "-c"] From 10ade3d930c46707407d0994ef9790044fb9890a Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 16 Jul 2024 11:52:11 +0200 Subject: [PATCH 18/34] ci,e2e: verbose print of e2e artifacts to discover big files --- .gitlab/ci/e2e.yml | 23 ++++++++++++++++++++++- .gitlab/ci/e2e/retina_request_viavi.yml | 4 ++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 407f2eda3a..dc66bc7f9b 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -178,11 +178,32 @@ e2e request and config validation: find . -iname "test_metrics.csv" -exec \ influx write --host $INFLUXDB_URL --token $INFLUXDB_TOKEN --org $INFLUXDB_ORG \ --bucket ci --file {} \; + # Artifact size + - echo -e "\e[0Ksection_start:`date +%s`:e2e_folder_section[collapsed=true]\r\e[0KLog folder's tree" + - | + print_tree() { + local dir="$1" + local prefix="$2" + + # List directories first + find "$dir" -mindepth 1 -maxdepth 1 -type d | while read -r subdir; do + local size=$(du -sh "$subdir" | awk '{print $1}') + echo "${prefix}├── $(basename "$subdir") [$size]" + print_tree "$subdir" "$prefix│ " + done + + # List files afterwards + find "$dir" -mindepth 1 -maxdepth 1 -type f | while read -r file; do + local size=$(du -sh "$file" | awk '{print $1}') + echo "${prefix}├── $(basename "$file") [$size]" + done + } + print_tree "tests/e2e/log/" "" + - echo -e "\e[0Ksection_end:`date +%s`:e2e_folder_section\r\e[0K" - | echo "*******************************************************************************************************************************" echo "Test report ---> https://softwareradiosystems.gitlab.io/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/tests/e2e/log//report.html" echo "*******************************************************************************************************************************" - - du -hs tests/e2e/log/ needs: - *retina-needs diff --git a/.gitlab/ci/e2e/retina_request_viavi.yml b/.gitlab/ci/e2e/retina_request_viavi.yml index 31b2774f3b..169c43cad7 100644 --- a/.gitlab/ci/e2e/retina_request_viavi.yml +++ b/.gitlab/ci/e2e/retina_request_viavi.yml @@ -21,8 +21,8 @@ requests: 4Gi limits: 4Gi ephemeral-storage: - requests: "20G" - limits: "20G" + requests: "50G" + limits: "50G" taints: ["purpose=ci-amd64-avx512-onprem"] resources: - type: emulator From 238c7d371697f7140f4d10f6cdff82aaf61ab41c Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 15 Jul 2024 18:05:12 +0200 Subject: [PATCH 19/34] phy: move PHY helpers phy: add missing headers --- .../pucch => include/srsran/phy/upper}/pucch_helper.h | 0 lib/phy/upper/channel_processors/pucch_detector_format0.h | 2 +- lib/phy/upper/channel_processors/pucch_detector_impl.h | 2 +- .../pucch/dmrs_pucch_processor_format1_impl.cpp | 2 +- .../signal_processors/pucch/dmrs_pucch_processor_format1_impl.h | 2 +- .../upper/signal_processors/pucch/pucch_orthogonal_sequence.h | 2 ++ 6 files changed, 6 insertions(+), 4 deletions(-) rename {lib/phy/upper/signal_processors/pucch => include/srsran/phy/upper}/pucch_helper.h (100%) diff --git a/lib/phy/upper/signal_processors/pucch/pucch_helper.h b/include/srsran/phy/upper/pucch_helper.h similarity index 100% rename from lib/phy/upper/signal_processors/pucch/pucch_helper.h rename to include/srsran/phy/upper/pucch_helper.h diff --git a/lib/phy/upper/channel_processors/pucch_detector_format0.h b/lib/phy/upper/channel_processors/pucch_detector_format0.h index 96e23841e8..80c687079f 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_format0.h +++ b/lib/phy/upper/channel_processors/pucch_detector_format0.h @@ -10,8 +10,8 @@ #pragma once -#include "../signal_processors/pucch/pucch_helper.h" #include "srsran/phy/upper/channel_processors/pucch_detector.h" +#include "srsran/phy/upper/pucch_helper.h" #include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" #include "srsran/ran/pucch/pucch_constants.h" diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.h b/lib/phy/upper/channel_processors/pucch_detector_impl.h index 9a221a6ad7..765b6cc2ef 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.h +++ b/lib/phy/upper/channel_processors/pucch_detector_impl.h @@ -13,13 +13,13 @@ #pragma once -#include "../signal_processors/pucch/pucch_helper.h" #include "pucch_detector_format0.h" #include "srsran/phy/support/re_buffer.h" #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/upper/channel_processors/pucch_detector.h" #include "srsran/phy/upper/equalization/channel_equalizer.h" #include "srsran/phy/upper/equalization/dynamic_ch_est_list.h" +#include "srsran/phy/upper/pucch_helper.h" #include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp index f012b63c51..39ba731f5a 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp @@ -9,7 +9,7 @@ */ #include "dmrs_pucch_processor_format1_impl.h" -#include "pucch_helper.h" +#include "srsran/phy/upper/pucch_helper.h" #include "srsran/srsvec/add.h" #include "srsran/srsvec/sc_prod.h" diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h index cfadfd69f1..9bdaab4ba1 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h @@ -10,8 +10,8 @@ #pragma once -#include "pucch_helper.h" #include "pucch_orthogonal_sequence.h" +#include "srsran/phy/upper/pucch_helper.h" #include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" #include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" #include "srsran/phy/upper/signal_processors/port_channel_estimator.h" diff --git a/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h b/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h index 1c8ea7f2de..5b45a30506 100644 --- a/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h +++ b/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h @@ -10,7 +10,9 @@ #pragma once +#include "srsran/adt/complex.h" #include "srsran/ran/pucch/pucch_constants.h" +#include "srsran/support/math_utils.h" #include "srsran/support/srsran_assert.h" #include From d78abf999bba3a1ee6c99dd475f6af95541f0637 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 13:42:52 +0200 Subject: [PATCH 20/34] du-high: make all du_cell queues synchronous in zmq mode --- apps/services/worker_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager.cpp index 2f197a6f44..05e731b038 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager.cpp @@ -249,7 +249,8 @@ void worker_manager::create_du_executors(bool is_blocking_m for (unsigned cell_id = 0; cell_id != nof_cells; ++cell_id) { const std::string cell_id_str = std::to_string(cell_id); - slot_workers[cell_id].executors.emplace_back("cell_exec#" + cell_id_str, task_priority::max - 1); + slot_workers[cell_id].executors.push_back( + {"cell_exec#" + cell_id_str, task_priority::max - 1, {}, std::nullopt, is_blocking_mode_active}); slot_workers[cell_id].executors.push_back( {"slot_exec#" + cell_id_str, task_priority::max, {}, std::nullopt, is_blocking_mode_active}); From aac3a9f6c6bcea1365843361ddea6380e032906a Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 15 Jul 2024 13:50:59 +0200 Subject: [PATCH 21/34] f1ap-du: initialize pending transmission event pool --- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 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 188a5b4eba..ed20ff81bd 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -126,8 +126,11 @@ f1c_other_srb_du_bearer::f1c_other_srb_du_bearer(f1ap_ue_context& ue_ctxt_ logger(srslog::fetch_basic_logger("DU-F1")) { // Mark all event entries as free. - for (unsigned i = 0; i != pending_delivery_event_pool.size(); ++i) { - pending_delivery_event_pool[i].first = -1; + for (auto& event : pending_delivery_event_pool) { + event.first = -1; + } + for (auto& event : pending_transmission_event_pool) { + event.first = -1; } } From d63b7a3b280cdcb497a19237f528ef943e1827b9 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 12:25:33 +0200 Subject: [PATCH 22/34] f1ap-du: fix ue context setup tests --- tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp | 5 +++++ .../f1ap/du/f1ap_du_ue_context_modification_test.cpp | 4 +++- tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp | 4 +++- .../f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp | 5 ++++- .../f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp | 5 ++++- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index 843b229f04..f022088269 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -15,6 +15,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/pdcp/pdcp_sn_util.h" #include "srsran/support/async/async_test_utils.h" #include "srsran/support/test_utils.h" @@ -368,6 +369,10 @@ void f1ap_du_test::run_ue_context_setup_procedure(du_ue_index_t ue_index, const for (const auto& created_srb : f1ap_du_cfg_handler.last_ue_cfg_response->f1c_bearers_added) { ue.f1c_bearers[srb_id_to_uint(created_srb.srb_id)].bearer = created_srb.bearer; } + + // 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()); } f1ap_ue_configuration_response f1ap_du_test::update_f1ap_ue_config(du_ue_index_t ue_index, 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 77b59c3f73..da0948ca8c 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 @@ -25,7 +25,9 @@ class f1ap_du_ue_context_modification_test : public f1ap_du_test // Test Preamble. run_f1_setup_procedure(); run_f1ap_ue_create(test_ue_index); - run_ue_context_setup_procedure(test_ue_index, generate_ue_context_setup_request({})); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}); + run_ue_context_setup_procedure(test_ue_index, msg); } void start_procedure(const std::initializer_list& drbs, byte_buffer rrc_container = {}) diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp index b966224da9..1c7adef5b5 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp @@ -25,7 +25,9 @@ class f1ap_du_ue_context_release_test : public f1ap_du_test run_f1_setup_procedure(); du_ue_index_t ue_index = to_du_ue_index(test_rgen::uniform_int(0, MAX_DU_UE_INDEX)); test_ue = run_f1ap_ue_create(ue_index); - run_ue_context_setup_procedure(ue_index, generate_ue_context_setup_request({})); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}); + run_ue_context_setup_procedure(ue_index, msg); } void start_procedure(const f1ap_message& msg = generate_ue_context_release_command()) 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 8f21c1d7a0..977cb3e0c9 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 @@ -9,6 +9,7 @@ */ #include "f1ap_du_test_helpers.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "srsran/support/test_utils.h" #include @@ -145,7 +146,9 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_the_rrc_co TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_new_srbs_become_active) { du_creates_f1_logical_connection(); - run_ue_context_setup_procedure(test_ue->ue_index, generate_ue_context_setup_request({drb_id_t::drb1})); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); + run_ue_context_setup_procedure(test_ue->ue_index, msg); // UL data through created SRB2 reaches F1-C. ASSERT_EQ(this->f1ap_du_cfg_handler.last_ue_cfg_response->f1c_bearers_added.size(), 1); diff --git a/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp index 6c5de35b67..69422c465e 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp @@ -10,6 +10,7 @@ #include "f1ap_du_test_helpers.h" #include "lib/f1ap/du/ue_context/f1c_du_bearer_impl.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/support/test_utils.h" #include @@ -23,7 +24,9 @@ TEST_F(f1ap_du_test, when_sdu_is_received_then_sdu_is_forwarded_to_tx_pdu_notifi // Run Test Preamble. run_f1_setup_procedure(); ue_test_context* ue = run_f1ap_ue_create(to_du_ue_index(0)); - run_ue_context_setup_procedure(ue->ue_index, generate_ue_context_setup_request({})); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}); + run_ue_context_setup_procedure(ue->ue_index, msg); this->f1c_gw.last_tx_f1ap_pdu.pdu = {}; std::vector bytes = test_rgen::random_vector(test_rgen::uniform_int(1, 4000)); From cdfaa4d520e39e6ee00fc9fd0b7cf84714c193b5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 12:56:16 +0200 Subject: [PATCH 23/34] f1ap-du: remove redundant test function --- .../f1ap/du/f1ap_du_test_helpers.cpp | 32 ------------------- .../unittests/f1ap/du/f1ap_du_test_helpers.h | 3 -- ...1ap_du_ue_context_setup_procedure_test.cpp | 18 +++++++---- 3 files changed, 12 insertions(+), 41 deletions(-) diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index f022088269..69d48131a1 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -74,38 +74,6 @@ asn1::f1ap::drbs_to_be_setup_item_s srsran::srs_du::generate_drb_am_setup_item(d return drb; } -f1ap_message srsran::srs_du::generate_ue_context_setup_request(const std::initializer_list& drbs_to_add) -{ - using namespace asn1::f1ap; - f1ap_message msg; - - msg.pdu.set_init_msg().load_info_obj(ASN1_F1AP_ID_UE_CONTEXT_SETUP); - ue_context_setup_request_s& dl_msg = msg.pdu.init_msg().value.ue_context_setup_request(); - dl_msg->gnb_cu_ue_f1ap_id = 0; - dl_msg->gnb_du_ue_f1ap_id_present = true; - dl_msg->gnb_du_ue_f1ap_id = 0; - dl_msg->srbs_to_be_setup_list_present = true; - dl_msg->srbs_to_be_setup_list.resize(1); - dl_msg->srbs_to_be_setup_list[0].load_info_obj(ASN1_F1AP_ID_SRBS_SETUP_ITEM); - srbs_to_be_setup_item_s& srb2 = dl_msg->srbs_to_be_setup_list[0]->srbs_to_be_setup_item(); - srb2.srb_id = 2; - - dl_msg->drbs_to_be_setup_list_present = drbs_to_add.size() > 0; - dl_msg->drbs_to_be_setup_list.resize(drbs_to_add.size()); - unsigned count = 0; - for (drb_id_t drbid : drbs_to_add) { - dl_msg->drbs_to_be_setup_list[count].load_info_obj(ASN1_F1AP_ID_DRB_INFO); - dl_msg->drbs_to_be_setup_list[count]->drbs_to_be_setup_item() = generate_drb_am_setup_item(drbid); - ++count; - } - - dl_msg->rrc_container_present = true; - EXPECT_TRUE( - dl_msg->rrc_container.append(test_rgen::random_vector(test_rgen::uniform_int(3, 100)))); - - return msg; -} - asn1::f1ap::drbs_to_be_setup_mod_item_s srsran::srs_du::generate_drb_am_mod_item(drb_id_t drbid) { using namespace asn1::f1ap; diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.h b/tests/unittests/f1ap/du/f1ap_du_test_helpers.h index c16450cefa..e1eefa4529 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.h +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.h @@ -133,9 +133,6 @@ f1_setup_request_message generate_f1_setup_request_message(); /// \brief Generate F1AP ASN.1 DRB AM Setup configuration. asn1::f1ap::drbs_to_be_setup_item_s generate_drb_am_setup_item(drb_id_t drbid); -/// \brief Generate an F1AP UE Context Setup Request message with specified list of DRBs. -f1ap_message generate_ue_context_setup_request(const std::initializer_list& drbs_to_add); - /// \brief Generate F1AP ASN.1 DRB AM Setup configuration. asn1::f1ap::drbs_to_be_setup_mod_item_s generate_drb_am_mod_item(drb_id_t drbid); 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 977cb3e0c9..47da7262d6 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 @@ -87,7 +87,8 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notifies_du_of_ue_context_update) { du_creates_f1_logical_connection(); - start_procedure(generate_ue_context_setup_request({drb_id_t::drb1})); + start_procedure(test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1})); // DU manager receives UE Context Update Request. ASSERT_TRUE(this->f1ap_du_cfg_handler.last_ue_context_update_req.has_value()); @@ -105,7 +106,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notif TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_responds_back_with_ue_context_setup_response) { du_creates_f1_logical_connection(); - auto msg = generate_ue_context_setup_request({drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); start_procedure(msg); // F1AP sends UE CONTEXT SETUP RESPONSE to CU-CP. @@ -135,7 +137,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_respo TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_the_rrc_container_is_sent_dl_via_srb1) { du_creates_f1_logical_connection(); - f1ap_message msg = generate_ue_context_setup_request({drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); start_procedure(msg); // F1AP sends RRC Container present in UE CONTEXT SETUP REQUEST via SRB1. @@ -165,7 +168,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_new_srbs_b TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_is_created) { - f1ap_message msg = generate_ue_context_setup_request({drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); msg.pdu.init_msg().value.ue_context_setup_request()->gnb_du_ue_f1ap_id_present = false; start_procedure(msg); @@ -176,7 +180,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_context_is_updated) { - f1ap_message msg = generate_ue_context_setup_request({drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); msg.pdu.init_msg().value.ue_context_setup_request()->gnb_du_ue_f1ap_id_present = false; start_procedure(msg); @@ -194,7 +199,8 @@ TEST_F( f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_context_setup_response_is_sent_to_cu_cp_with_crnti_ie) { - f1ap_message msg = generate_ue_context_setup_request({drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); msg.pdu.init_msg().value.ue_context_setup_request()->gnb_du_ue_f1ap_id_present = false; start_procedure(msg); From a834f69336c4221f623899b6089d55d279cc5bdb Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 14:56:18 +0200 Subject: [PATCH 24/34] f1ap-du: fix unit tests for ue context setup --- .../f1ap_du_ue_context_setup_procedure.cpp | 13 +++++++- .../f1ap_du_ue_context_setup_procedure.h | 2 ++ ...1ap_du_ue_context_setup_procedure_test.cpp | 32 +++++++++++++------ 3 files changed, 37 insertions(+), 10 deletions(-) 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 22331376c7..16ac0c7c4c 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 @@ -14,6 +14,7 @@ #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" using namespace srsran; using namespace srs_du; @@ -91,7 +92,7 @@ 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(ue->bearers.find_srb(srb_id_t::srb1)->handle_pdu_and_await_transmission(msg->rrc_container.copy())); + CORO_AWAIT(handle_rrc_container()); } // Respond back to CU-CP with success. @@ -100,6 +101,16 @@ void f1ap_du_ue_context_setup_procedure::operator()(coro_context 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()); + } + logger.error("{}: Failed to find SRB1 bearer to send RRC container.", f1ap_log_prefix{ue->context, name()}); + return launch_no_op_task(); +} + async_task f1ap_du_ue_context_setup_procedure::request_du_ue_config() { // Construct DU request. 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 f53ede20c2..911df08465 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,6 +39,8 @@ 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(); + const char* name() const { return "UE Context Setup"; } const asn1::f1ap::ue_context_setup_request_s msg; 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 47da7262d6..875de5bce5 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 @@ -79,6 +79,18 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test } f1ap->handle_message(msg); + + if (not ue_ctx_setup.gnb_du_ue_f1ap_id_present) { + report_fatal_error_if_not(this->f1ap_du_cfg_handler.last_ue_creation_response.has_value(), + "UE should have been created"); + test_ue->f1c_bearers[srb_id_to_uint(srb_id_t::srb1)].bearer = + this->f1ap_du_cfg_handler.last_ue_creation_response.value().f1c_bearers_added[0]; + } + } + + void on_rrc_container_transmitted(uint32_t highest_pdcp_sn) + { + this->test_ue->f1c_bearers[LCID_SRB1].bearer->handle_transmit_notification(highest_pdcp_sn); } ue_test_context* test_ue = nullptr; @@ -110,6 +122,10 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_respo gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); start_procedure(msg); + // Lower layers handle RRC container. + this->f1c_gw.last_tx_f1ap_pdu = {}; + on_rrc_container_transmitted(1); + // F1AP sends UE CONTEXT SETUP RESPONSE to CU-CP. ASSERT_EQ(this->f1c_gw.last_tx_f1ap_pdu.pdu.type().value, f1ap_pdu_c::types_opts::successful_outcome); ASSERT_EQ(this->f1c_gw.last_tx_f1ap_pdu.pdu.successful_outcome().value.type().value, @@ -168,9 +184,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_new_srbs_b TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_is_created) { - f1ap_message msg = test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); - msg.pdu.init_msg().value.ue_context_setup_request()->gnb_du_ue_f1ap_id_present = false; + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}); start_procedure(msg); @@ -180,9 +195,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_context_is_updated) { - f1ap_message msg = test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); - msg.pdu.init_msg().value.ue_context_setup_request()->gnb_du_ue_f1ap_id_present = false; + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}); start_procedure(msg); @@ -199,11 +213,11 @@ TEST_F( f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_context_setup_response_is_sent_to_cu_cp_with_crnti_ie) { - f1ap_message msg = test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); - msg.pdu.init_msg().value.ue_context_setup_request()->gnb_du_ue_f1ap_id_present = false; + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}); start_procedure(msg); + on_rrc_container_transmitted(1); // F1AP sends UE CONTEXT SETUP RESPONSE to CU-CP. ASSERT_EQ(this->f1c_gw.last_tx_f1ap_pdu.pdu.type().value, f1ap_pdu_c::types_opts::successful_outcome); From 7e03996ce6064e2eda34b0be13e691202752e5dd Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 16 Jul 2024 18:01:10 +0200 Subject: [PATCH 25/34] f1ap-du: defer transmit notifications to UE executor --- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 ed20ff81bd..a6ab5db22b 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -212,7 +212,10 @@ void f1c_other_srb_du_bearer::handle_transmit_notification(uint32_t highest_pdcp void f1c_other_srb_du_bearer::handle_delivery_notification(uint32_t highest_pdcp_sn) { - handle_notification(highest_pdcp_sn, false); + if (not ue_exec.defer([this, highest_pdcp_sn]() { handle_notification(highest_pdcp_sn, false); })) { + logger.warning("Discarded delivery notification for SRB{} because the task executor queue is full.", + srb_id_to_uint(srb_id)); + } } async_task f1c_other_srb_du_bearer::handle_pdu_and_await(byte_buffer pdu, bool tx_or_delivery) From bad01194b7566565a3ebb1301b06e9c7964809be Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 10:00:37 +0200 Subject: [PATCH 26/34] f1ap-du: defer delivery notifications to UE executor --- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 a6ab5db22b..b8c00b5add 100644 --- a/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp +++ b/lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp @@ -207,7 +207,10 @@ async_task f1c_other_srb_du_bearer::handle_pdu_and_await_delivery(byte_buf void f1c_other_srb_du_bearer::handle_transmit_notification(uint32_t highest_pdcp_sn) { - handle_notification(highest_pdcp_sn, true); + 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.", + srb_id_to_uint(srb_id)); + } } void f1c_other_srb_du_bearer::handle_delivery_notification(uint32_t highest_pdcp_sn) From b00a878ba53daf29ab741c04be6729a811bdf5c2 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 11:09:02 +0200 Subject: [PATCH 27/34] f1ap-du: fix unit tests for ue context setup. Issue: correctly handle transmit notification --- tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp | 1 + .../f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index 69d48131a1..8d0e176c43 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -341,6 +341,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()); + this->ctrl_worker.run_pending_tasks(); } f1ap_ue_configuration_response f1ap_du_test::update_f1ap_ue_config(du_ue_index_t ue_index, 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 875de5bce5..947a068d9c 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 @@ -91,6 +91,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->ctrl_worker.run_pending_tasks(); } ue_test_context* test_ue = nullptr; From 7b25e4941b38160a60bf6ae0e123e65cdf860c7e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 15 Jul 2024 17:06:51 +0200 Subject: [PATCH 28/34] phy: fix LDPC decoder clamping --- lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b9a2ae7d2d..5f70b651ce 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h @@ -178,9 +178,9 @@ class ldpc_decoder_impl : public ldpc_decoder private: /// Soft bits clamp lower bound. - static constexpr log_likelihood_ratio soft_bits_clamp_low = -32; + static constexpr log_likelihood_ratio soft_bits_clamp_low = -64; /// Soft bits clamp higher bound. - static constexpr log_likelihood_ratio soft_bits_clamp_high = 32; + static constexpr log_likelihood_ratio soft_bits_clamp_high = 64; /// Pointer to the Tanner graph (~ parity check matrix) used by the encoding algorithm. const ldpc_graph_impl* current_graph = nullptr; /// Total number of base graph variable nodes in the current graph. From 3ee54c48f8157b2c771dfe249cf60c3570644c8a Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 12 Jul 2024 15:49:11 +0200 Subject: [PATCH 29/34] cu_cp: handle rrc reconfiguration outcome in calling procedure --- lib/cu_cp/cu_cp_impl.cpp | 8 ++- .../cu_cp_routine_manager.cpp | 37 ++++++++--- .../routine_managers/cu_cp_routine_manager.h | 10 ++- ..._session_resource_modification_routine.cpp | 8 +++ ...du_session_resource_modification_routine.h | 6 ++ .../pdu_session_resource_release_routine.cpp | 13 ++-- .../pdu_session_resource_release_routine.h | 8 +-- .../pdu_session_resource_setup_routine.cpp | 7 +++ .../pdu_session_resource_setup_routine.h | 6 ++ ...blishment_context_modification_routine.cpp | 7 +++ ...tablishment_context_modification_routine.h | 6 ++ .../rrc_reconfiguration_procedure.cpp | 7 --- .../rrc_reconfiguration_procedure.h | 10 +-- lib/rrc/ue/rrc_ue_message_handlers.cpp | 3 +- .../cu_cp_routine_manager_test_helpers.h | 2 +- ...ion_resource_modification_routine_test.cpp | 6 ++ ..._session_resource_release_routine_test.cpp | 4 +- ...du_session_resource_setup_routine_test.cpp | 2 + tests/unittests/cu_cp/test_helpers.h | 63 +++++++++++++++++++ 19 files changed, 171 insertions(+), 42 deletions(-) diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 2463e28322..ac3b91c855 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -235,6 +235,8 @@ async_task cu_cp_impl::handle_rrc_reestablishment_context_modification_req 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_interface().get_f1ap_ue_context_manager(), ue->get_rrc_ue_notifier(), + get_cu_cp_rrc_ue_interface(), + ue->get_task_sched(), ue->get_up_resource_manager()); } @@ -415,6 +417,8 @@ cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_reso 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_interface().get_f1ap_ue_context_manager(), ue->get_rrc_ue_notifier(), + get_cu_cp_rrc_ue_interface(), + ue->get_task_sched(), ue->get_up_resource_manager()); } @@ -432,6 +436,8 @@ cu_cp_impl::handle_new_pdu_session_resource_modify_request(const cu_cp_pdu_sessi 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_interface().get_f1ap_ue_context_manager(), ue->get_rrc_ue_notifier(), + get_cu_cp_rrc_ue_interface(), + ue->get_task_sched(), ue->get_up_resource_manager()); } @@ -448,8 +454,8 @@ cu_cp_impl::handle_new_pdu_session_resource_release_command(const cu_cp_pdu_sess 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_interface().get_f1ap_ue_context_manager(), - ngap_entity->get_ngap_control_message_handler(), ue->get_rrc_ue_notifier(), + get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), ue->get_up_resource_manager()); } diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp b/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp index 61ed41ff45..d8cb064551 100644 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp +++ b/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp @@ -58,6 +58,8 @@ async_task cu_cp_routine_manager::sta 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, @@ -67,6 +69,8 @@ async_task cu_cp_routine_manager::sta e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, + cu_cp_notifier, + ue_task_sched, up_resource_mng, logger); } @@ -77,10 +81,18 @@ cu_cp_routine_manager::start_pdu_session_resource_modification_routine( 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, up_resource_mng, logger); + 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 @@ -88,17 +100,17 @@ 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, - ngap_control_message_handler& ngap_handler, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - ue_task_scheduler& task_sched, + 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, - ngap_handler, rrc_ue_ctrl_notifier, - task_sched, + cu_cp_notifier, + ue_task_sched, up_resource_mng, logger); } @@ -119,10 +131,19 @@ async_task cu_cp_routine_manager::start_reestablishment_context_modificati 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, ue_up_resource_manager, logger); + 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 diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h index b7b79089ec..f9769a500d 100644 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h +++ b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h @@ -44,15 +44,17 @@ class cu_cp_routine_manager : public common_task_scheduler 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, - ngap_control_message_handler& ngap_handler, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - ue_task_scheduler& task_sched, + cu_cp_rrc_ue_interface& cu_cp_notifier, + ue_task_scheduler& ue_task_sched, up_resource_manager& up_resource_mng); async_task @@ -60,6 +62,8 @@ class cu_cp_routine_manager : public common_task_scheduler 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 @@ -74,6 +78,8 @@ class cu_cp_routine_manager : public common_task_scheduler 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 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 1dfd0eeb90..2e45dd72f4 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -10,6 +10,7 @@ #include "pdu_session_resource_modification_routine.h" #include "pdu_session_routine_helpers.h" +#include "srsran/cu_cp/ue_task_scheduler.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -45,12 +46,16 @@ pdu_session_resource_modification_routine::pdu_session_resource_modification_rou 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_) : modify_request(modify_request_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), rrc_ue_notifier(rrc_ue_notifier_), + cu_cp_notifier(cu_cp_notifier_), + ue_task_sched(ue_task_sched_), up_resource_mng(up_resource_mng_), logger(logger_) { @@ -170,6 +175,9 @@ void pdu_session_resource_modification_routine::operator()( // Handle RRC Reconfiguration result. if (handle_procedure_response(response_msg, modify_request, rrc_reconfig_result, logger) == false) { logger.warning("ue={}: \"{}\" RRC reconfiguration failed", modify_request.ue_index, name()); + // Notify NGAP to request UE context release from AMF + ue_task_sched.schedule_async_task(cu_cp_notifier.handle_ue_context_release( + {modify_request.ue_index, {}, ngap_cause_radio_network_t::release_due_to_ngran_generated_reason})); CORO_EARLY_RETURN(generate_pdu_session_resource_modify_response(false)); } } 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 c5c2f29e6c..44b56be8fd 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.h @@ -10,8 +10,10 @@ #pragma once +#include "../cu_cp_impl_interface.h" #include "../du_processor/du_processor.h" #include "../up_resource_manager/up_resource_manager_impl.h" +#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/support/async/async_task.h" @@ -27,6 +29,8 @@ class pdu_session_resource_modification_routine 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_); @@ -48,6 +52,8 @@ class pdu_session_resource_modification_routine 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; 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 dfabd06def..0af073ffde 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -19,16 +19,16 @@ 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_, - ngap_control_message_handler& ngap_handler_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& task_sched_, up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_) : release_cmd(release_cmd_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), - ngap_handler(ngap_handler_), rrc_ue_notifier(rrc_ue_notifier_), + cu_cp_notifier(cu_cp_notifier_), task_sched(task_sched_), up_resource_mng(up_resource_mng_), logger(logger_) @@ -178,13 +178,8 @@ pdu_session_resource_release_routine::handle_pdu_session_resource_release_respon logger.info("ue={}: \"{}\" failed", release_cmd.ue_index, name()); // Trigger UE context release request. - cu_cp_ue_context_release_request req{release_cmd.ue_index}; - req.cause = ngap_cause_radio_network_t::radio_conn_with_ue_lost; - task_sched.schedule_async_task(launch_async([ngap_notif = &ngap_handler, req](coro_context>& ctx) { - CORO_BEGIN(ctx); - CORO_AWAIT(ngap_notif->handle_ue_context_release_request(req)); - CORO_RETURN(); - })); + task_sched.schedule_async_task(cu_cp_notifier.handle_ue_context_release( + {release_cmd.ue_index, {}, ngap_cause_radio_network_t::radio_conn_with_ue_lost})); } return response_msg; 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 c2ccca03d2..3eeb4ec344 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.h @@ -10,11 +10,11 @@ #pragma once +#include "../cu_cp_impl_interface.h" #include "../du_processor/du_processor.h" #include "../up_resource_manager/up_resource_manager_impl.h" #include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" -#include "srsran/ngap/ngap.h" #include "srsran/support/async/async_task.h" namespace srsran { @@ -28,8 +28,8 @@ 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_, - ngap_control_message_handler& ngap_handler_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, + cu_cp_rrc_ue_interface& cu_cp_notifier_, ue_task_scheduler& task_sched_, up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_); @@ -50,9 +50,9 @@ class pdu_session_resource_release_routine 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 - ngap_control_message_handler& ngap_handler; // to request UE release du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - ue_task_scheduler& task_sched; // to schedule UE release request (over NGAP) + 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; 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 87fe379b7f..674a2a0def 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -60,6 +60,8 @@ pdu_session_resource_setup_routine::pdu_session_resource_setup_routine( 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_) : setup_msg(setup_msg_), @@ -69,6 +71,8 @@ pdu_session_resource_setup_routine::pdu_session_resource_setup_routine( e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), rrc_ue_notifier(rrc_ue_notifier_), + cu_cp_notifier(cu_cp_notifier_), + ue_task_sched(ue_task_sched_), up_resource_mng(up_resource_mng_), logger(logger_) { @@ -227,6 +231,9 @@ void pdu_session_resource_setup_routine::operator()( // Handle RRC Reconfiguration Response if (!handle_procedure_response(response_msg, setup_msg, rrc_reconfig_result, logger)) { logger.warning("ue={}: \"{}\" RRC reconfiguration failed", setup_msg.ue_index, name()); + // Notify NGAP to request UE context release from AMF + ue_task_sched.schedule_async_task(cu_cp_notifier.handle_ue_context_release( + {setup_msg.ue_index, {}, ngap_cause_radio_network_t::release_due_to_ngran_generated_reason})); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } } 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 e8b1674b0f..eae1bb21e8 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.h @@ -10,9 +10,11 @@ #pragma once +#include "../cu_cp_impl_interface.h" #include "../du_processor/du_processor.h" #include "../up_resource_manager/up_resource_manager_impl.h" #include "srsran/cu_cp/ue_configuration.h" +#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/support/async/async_task.h" @@ -46,6 +48,8 @@ class pdu_session_resource_setup_routine 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_); @@ -69,6 +73,8 @@ class pdu_session_resource_setup_routine 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; diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 7fae5fd507..b0c1d1d3c6 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -22,6 +22,8 @@ reestablishment_context_modification_routine::reestablishment_context_modificati 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(ue_index_), @@ -29,6 +31,8 @@ reestablishment_context_modification_routine::reestablishment_context_modificati e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), rrc_ue_notifier(rrc_ue_notifier_), + cu_cp_notifier(cu_cp_notifier_), + ue_task_sched(ue_task_sched_), up_resource_mng(up_resource_mng_), logger(logger_) { @@ -136,6 +140,9 @@ void reestablishment_context_modification_routine::operator()(coro_context>& c procedure_result = true; } else { logger.log_warning("\"{}\" timed out after {}ms", name(), context.cfg.rrc_procedure_timeout_ms.count()); - // Notify NGAP to request UE context release from AMF - cu_cp_ue_notifier.schedule_async_task(cu_cp_notifier.on_ue_release_required( - {context.ue_index, {}, ngap_cause_radio_network_t::release_due_to_ngran_generated_reason})); } CORO_RETURN(procedure_result); diff --git a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h index 1c47fdee4d..665dac38a2 100644 --- a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h +++ b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.h @@ -28,8 +28,6 @@ class rrc_reconfiguration_procedure rrc_reconfiguration_procedure(rrc_ue_context_t& context_, const rrc_reconfiguration_procedure_request& args_, rrc_ue_reconfiguration_proc_notifier& rrc_ue_notifier_, - rrc_ue_context_update_notifier& cu_cp_notifier_, - rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, rrc_ue_event_manager& event_mng_, rrc_ue_srb_handler& srb_notifier_, rrc_ue_logger& logger_); @@ -45,11 +43,9 @@ class rrc_reconfiguration_procedure rrc_ue_context_t& context; const rrc_reconfiguration_procedure_request args; - rrc_ue_reconfiguration_proc_notifier& rrc_ue; // handler to the parent RRC UE object - rrc_ue_context_update_notifier& cu_cp_notifier; // to release the UE if the reconfiguration fails - rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier; // to schedule the UE release - rrc_ue_event_manager& event_mng; // event manager for the RRC UE entity - rrc_ue_srb_handler& srb_notifier; // For creating SRBs + 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_logger& logger; rrc_transaction transaction; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 1aedc5a413..e0bc24a1c6 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -370,8 +370,7 @@ 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, cu_cp_notifier, cu_cp_ue_notifier, *event_mng, get_rrc_ue_srb_handler(), logger); + return launch_async(context, msg, *this, *event_mng, get_rrc_ue_srb_handler(), logger); } rrc_ue_handover_reconfiguration_context 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 index 054ea97203..448d0eca0a 100644 --- 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 @@ -44,7 +44,7 @@ class cu_cp_routine_manager_test : public ::testing::Test 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_ngap_ue_context_removal_handler ngap_ue_removal_handler; + 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; }; 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 index 6186201f61..37d69d4039 100644 --- 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 @@ -40,6 +40,8 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi 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); } @@ -70,6 +72,8 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi 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); @@ -120,6 +124,8 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi 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); 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 index 315b8b7c0b..4be3a44cc7 100644 --- 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 @@ -34,8 +34,8 @@ class pdu_session_resource_release_test : public pdu_session_resource_routine_te msg, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, - ngap_control_handler, 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); @@ -82,6 +82,8 @@ class pdu_session_resource_release_test : public pdu_session_resource_routine_te 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); } 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 index bd1ba6be04..b061741e6f 100644 --- 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 @@ -40,6 +40,8 @@ class pdu_session_resource_setup_test : public pdu_session_resource_routine_test 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); } diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index cea4bf57f3..6c470a83ec 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -695,5 +695,68 @@ struct dummy_ue_task_scheduler : public ue_task_scheduler { timer_manager& timer_db; task_executor& exec; }; + +class dummy_cu_cp_rrc_ue_interface : public cu_cp_rrc_ue_interface +{ +public: + void add_ue_context(rrc_ue_reestablishment_context_response context) { reest_context = context; } + + bool next_ue_setup_response = true; + + rrc_ue_reestablishment_context_response + handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, ue_index_t ue_index) override + { + logger.info("ue={} old_pci={} old_c-rnti={}: Received RRC Reestablishment Request", ue_index, old_pci, old_c_rnti); + + return reest_context; + } + + async_task handle_rrc_reestablishment_context_modification_required(ue_index_t ue_index) override + { + logger.info("ue={}: Received Reestablishment Context Modification Required"); + + return launch_async([](coro_context>& ctx) mutable { + CORO_BEGIN(ctx); + CORO_RETURN(true); + }); + } + + void handle_rrc_reestablishment_failure(const cu_cp_ue_context_release_request& request) override + { + logger.info("ue={}: Received RRC Reestablishment failure notification", request.ue_index); + } + + void handle_rrc_reestablishment_complete(ue_index_t old_ue_index) override + { + logger.info("ue={}: Received RRC Reestablishment complete notification", old_ue_index); + } + + async_task handle_ue_context_transfer(ue_index_t ue_index, ue_index_t old_ue_index) override + { + logger.info("ue={}: Requested a UE context transfer from old_ue={}", ue_index, old_ue_index); + return launch_async([](coro_context>& ctx) mutable { + CORO_BEGIN(ctx); + CORO_RETURN(true); + }); + } + + async_task handle_ue_context_release(const cu_cp_ue_context_release_request& request) override + { + logger.info("ue={}: Requested a UE release", request.ue_index); + last_cu_cp_ue_context_release_request = request; + + return launch_async([](coro_context>& ctx) mutable { + CORO_BEGIN(ctx); + CORO_RETURN(); + }); + } + + cu_cp_ue_context_release_request last_cu_cp_ue_context_release_request; + +private: + rrc_ue_reestablishment_context_response reest_context = {}; + srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST"); +}; + } // namespace srs_cu_cp } // namespace srsran From 7e1681a9be6516a319f2d38a8c96561734500a26 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 12 Jul 2024 16:57:55 +0200 Subject: [PATCH 30/34] phy: optimize precoding for PDSCH DM-RS fix NEON compilation phy: fix compilation --- .../precoding/channel_precoder.h | 2 +- .../srsran/phy/support/resource_grid_writer.h | 2 +- .../precoding/channel_precoder_avx2.cpp | 43 +++++++-------- .../precoding/channel_precoder_avx2.h | 2 +- .../precoding/channel_precoder_avx512.cpp | 52 +++++++++---------- .../precoding/channel_precoder_avx512.h | 2 +- .../precoding/channel_precoder_generic.cpp | 7 +-- .../precoding/channel_precoder_generic.h | 2 +- .../precoding/channel_precoder_impl.cpp | 4 +- .../precoding/channel_precoder_impl.h | 7 +-- .../precoding/channel_precoder_neon.cpp | 52 ++++++++++--------- .../precoding/channel_precoder_neon.h | 2 +- lib/phy/support/resource_grid_mapper_impl.cpp | 30 +++-------- lib/phy/support/resource_grid_writer_impl.cpp | 10 ++-- lib/phy/support/resource_grid_writer_impl.h | 2 +- lib/phy/support/support_factories.cpp | 2 +- .../dmrs_pbch_processor_impl.cpp | 8 ++- .../precoding/channel_precoder_benchmark.cpp | 7 ++- tests/unittests/ofh/receiver/helpers.h | 2 +- .../ofh_uplink_request_handler_impl_test.cpp | 4 +- .../precoding/channel_precoder_test.cpp | 15 ++---- .../phy/support/resource_grid_test_doubles.h | 6 +-- 22 files changed, 123 insertions(+), 140 deletions(-) diff --git a/include/srsran/phy/generic_functions/precoding/channel_precoder.h b/include/srsran/phy/generic_functions/precoding/channel_precoder.h index fd26cfdfff..c48126b71a 100644 --- a/include/srsran/phy/generic_functions/precoding/channel_precoder.h +++ b/include/srsran/phy/generic_functions/precoding/channel_precoder.h @@ -34,7 +34,7 @@ class channel_precoder /// of RE per layer of the input buffer. /// \remark An assertion is triggered if the precoding matrix dimensions do not match the number of layers of the /// input buffer and the number of antenna ports of the output buffer. - virtual void apply_precoding(re_buffer_writer<>& output, + virtual void apply_precoding(re_buffer_writer& output, const re_buffer_reader<>& input, const precoding_weight_matrix& precoding) const = 0; diff --git a/include/srsran/phy/support/resource_grid_writer.h b/include/srsran/phy/support/resource_grid_writer.h index cf23567363..2e61bf6015 100644 --- a/include/srsran/phy/support/resource_grid_writer.h +++ b/include/srsran/phy/support/resource_grid_writer.h @@ -85,7 +85,7 @@ class resource_grid_writer : public resource_grid_base /// \param[in] symbols Symbols to be written into the resource grid. /// \note The RE positions given \c k_init, the number of elements in \c symbols and the \c stride shall be within the /// resource grid number of subcarriers. - virtual void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) = 0; + virtual void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) = 0; /// \brief Gets a read-write view of an OFDM symbol for a given port. /// diff --git a/lib/phy/generic_functions/precoding/channel_precoder_avx2.cpp b/lib/phy/generic_functions/precoding/channel_precoder_avx2.cpp index 6f93ee4e38..c04627fb4d 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_avx2.cpp +++ b/lib/phy/generic_functions/precoding/channel_precoder_avx2.cpp @@ -43,9 +43,26 @@ simd_cf_interleaved operator*(const simd_cf_interleaved& re, const simd_cf_t& we return _mm256_fmaddsub_ps(re, weight.re, _mm256_mul_ps(_mm256_shuffle_ps(re, re, 0xb1), weight.im)); } +inline __m128i ps_to_cbf16(simd_cf_interleaved in) +{ + const __m256i bias = _mm256_set1_epi32(0x7fff); + const __m256i one = _mm256_set1_epi32(0x1); + + __m256i a_i32 = _mm256_castps_si256(in); + + // Round to nearest even. + a_i32 = _mm256_add_epi32(a_i32, _mm256_add_epi32(bias, _mm256_and_si256(_mm256_srli_epi32(a_i32, 16), one))); + + // Shift right 16 bits. + a_i32 = _mm256_srai_epi32(a_i32, 16); + + // Pack both parts in 32-bit registers. + return _mm_packs_epi32(_mm256_extractf128_si256(a_i32, 0), _mm256_extractf128_si256(a_i32, 1)); +} + } // namespace -void channel_precoder_avx2::apply_precoding_port(span port_re, +void channel_precoder_avx2::apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const { @@ -84,15 +101,16 @@ void channel_precoder_avx2::apply_precoding_port(span port_ } // Store. - _mm256_storeu_ps(reinterpret_cast(&port_re[i_re]), re_out); + _mm_storeu_si128(reinterpret_cast<__m128i*>(&port_re[i_re]), ps_to_cbf16(re_out)); } for (; i_re != nof_re; ++i_re) { - port_re[i_re] = layer_re_view_list[0][i_re] * port_weights[0]; + cf_t sum = layer_re_view_list[0][i_re] * port_weights[0]; for (unsigned i_layer = 1; i_layer != nof_layers; ++i_layer) { - port_re[i_re] += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; + sum += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; } + port_re[i_re] = sum; } } @@ -181,23 +199,6 @@ static inline void layer4_map_and_ci8_to_cf(simd_cf_interleaved& out_l0, from_ci8_to_cf(out_l0, out_l1, out_l2, out_l3, tmp); } -inline __m128i ps_to_cbf16(simd_cf_interleaved in) -{ - const __m256i bias = _mm256_set1_epi32(0x7fff); - const __m256i one = _mm256_set1_epi32(0x1); - - __m256i a_i32 = _mm256_castps_si256(in); - - // Round to nearest even. - a_i32 = _mm256_add_epi32(a_i32, _mm256_add_epi32(bias, _mm256_and_si256(_mm256_srli_epi32(a_i32, 16), one))); - - // Shift right 16 bits. - a_i32 = _mm256_srai_epi32(a_i32, 16); - - // Pack both parts in 32-bit registers. - return _mm_packs_epi32(_mm256_extractf128_si256(a_i32, 0), _mm256_extractf128_si256(a_i32, 1)); -} - void channel_precoder_avx2::apply_layer_map_and_precoding(re_buffer_writer& output, span input, const precoding_weight_matrix& precoding) const diff --git a/lib/phy/generic_functions/precoding/channel_precoder_avx2.h b/lib/phy/generic_functions/precoding/channel_precoder_avx2.h index 23cb0dc593..dc44ea1cdb 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_avx2.h +++ b/lib/phy/generic_functions/precoding/channel_precoder_avx2.h @@ -22,7 +22,7 @@ class channel_precoder_avx2 : public channel_precoder_impl { public: // See interface for documentation. - void apply_precoding_port(span port_re, + void apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const override; diff --git a/lib/phy/generic_functions/precoding/channel_precoder_avx512.cpp b/lib/phy/generic_functions/precoding/channel_precoder_avx512.cpp index 8cffcb9572..f1fc01ad00 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_avx512.cpp +++ b/lib/phy/generic_functions/precoding/channel_precoder_avx512.cpp @@ -37,6 +37,27 @@ struct simd_cf_t { // Type to hold a set of complex numbers using an AVX512 register, with interleaved real and imaginary parts. using simd_cf_interleaved = __m512; +inline __m256i ps_to_cbf16(simd_cf_interleaved in) +{ +#if __AVX512BF16__ + return (__m256i)_mm512_cvtneps_pbh(in); +#else // __AVX512BF16__ + const __m512i bias = _mm512_set1_epi32(0x7fff); + const __m512i one = _mm512_set1_epi32(0x1); + + __m512i a_i32 = _mm512_castps_si512(in); + + // Round to nearest even. + a_i32 = _mm512_add_epi32(a_i32, _mm512_add_epi32(bias, _mm512_and_si512(_mm512_srli_epi32(a_i32, 16), one))); + + // Shift right 16 bits. + a_i32 = _mm512_srli_epi32(a_i32, 16); + + // Pack both parts in 32-bit registers. + return _mm512_cvtepi32_epi16(a_i32); +#endif // __AVX512BF16__ +} + } // namespace // Multiplication operator for the precoding weights. @@ -203,28 +224,7 @@ static inline void layer4_map_and_ci8_to_cf(simd_cf_interleaved& out0, from_ci8_to_cf(out0, out1, out2, out3, tmp); } -inline __m256i ps_to_cbf16(simd_cf_interleaved in) -{ -#if __AVX512BF16__ - return (__m256i)_mm512_cvtneps_pbh(in); -#else // __AVX512BF16__ - const __m512i bias = _mm512_set1_epi32(0x7fff); - const __m512i one = _mm512_set1_epi32(0x1); - - __m512i a_i32 = _mm512_castps_si512(in); - - // Round to nearest even. - a_i32 = _mm512_add_epi32(a_i32, _mm512_add_epi32(bias, _mm512_and_si512(_mm512_srli_epi32(a_i32, 16), one))); - - // Shift right 16 bits. - a_i32 = _mm512_srli_epi32(a_i32, 16); - - // Pack both parts in 32-bit registers. - return _mm512_cvtepi32_epi16(a_i32); -#endif // __AVX512BF16__ -} - -void channel_precoder_avx512::apply_precoding_port(span port_re, +void channel_precoder_avx512::apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const { @@ -263,15 +263,15 @@ void channel_precoder_avx512::apply_precoding_port(span por } // Store. - _mm512_storeu_ps(reinterpret_cast(&port_re[i_re]), re_out); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(&port_re[i_re]), ps_to_cbf16(re_out)); } for (; i_re != nof_re; ++i_re) { - port_re[i_re] = layer_re_view_list[0][i_re] * port_weights[0]; - + cf_t sum = layer_re_view_list[0][i_re] * port_weights[0]; for (unsigned i_layer = 1; i_layer != nof_layers; ++i_layer) { - port_re[i_re] += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; + sum += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; } + port_re[i_re] = sum; } } diff --git a/lib/phy/generic_functions/precoding/channel_precoder_avx512.h b/lib/phy/generic_functions/precoding/channel_precoder_avx512.h index 8fb0c575ca..b55d3da6d0 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_avx512.h +++ b/lib/phy/generic_functions/precoding/channel_precoder_avx512.h @@ -21,7 +21,7 @@ namespace srsran { class channel_precoder_avx512 : public channel_precoder_impl { // See interface for documentation. - void apply_precoding_port(span port_re, + void apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const override; diff --git a/lib/phy/generic_functions/precoding/channel_precoder_generic.cpp b/lib/phy/generic_functions/precoding/channel_precoder_generic.cpp index 359c3ac30c..ceb605d307 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_generic.cpp +++ b/lib/phy/generic_functions/precoding/channel_precoder_generic.cpp @@ -12,7 +12,7 @@ using namespace srsran; -void channel_precoder_generic::apply_precoding_port(span port_re, +void channel_precoder_generic::apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const { @@ -26,12 +26,13 @@ void channel_precoder_generic::apply_precoding_port(span po for (unsigned i_re = 0; i_re != nof_re; ++i_re) { // Set the port RE to the contribution of the first layer. - port_re[i_re] = layer_re_view_list[0][i_re] * port_weights[0]; + cf_t sum = layer_re_view_list[0][i_re] * port_weights[0]; for (unsigned i_layer = 1; i_layer != nof_layers; ++i_layer) { // Accumulate the contributions of all other layers. - port_re[i_re] += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; + sum += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; } + port_re[i_re] = sum; } } diff --git a/lib/phy/generic_functions/precoding/channel_precoder_generic.h b/lib/phy/generic_functions/precoding/channel_precoder_generic.h index 1a85dce551..7bb74f6e81 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_generic.h +++ b/lib/phy/generic_functions/precoding/channel_precoder_generic.h @@ -21,7 +21,7 @@ namespace srsran { class channel_precoder_generic : public channel_precoder_impl { // See interface for documentation. - void apply_precoding_port(span port_re, + void apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const override; diff --git a/lib/phy/generic_functions/precoding/channel_precoder_impl.cpp b/lib/phy/generic_functions/precoding/channel_precoder_impl.cpp index 105bb18e06..336426b102 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_impl.cpp +++ b/lib/phy/generic_functions/precoding/channel_precoder_impl.cpp @@ -12,7 +12,7 @@ using namespace srsran; -void channel_precoder_impl::apply_precoding(re_buffer_writer<>& output, +void channel_precoder_impl::apply_precoding(re_buffer_writer& output, const re_buffer_reader<>& input, const precoding_weight_matrix& precoding) const { @@ -46,7 +46,7 @@ void channel_precoder_impl::apply_precoding(re_buffer_writer<>& outpu for (unsigned i_port = 0; i_port != nof_tx_ports; ++i_port) { // View of the output RE for a single antenna port. - span port_re_view = output.get_slice(i_port); + span port_re_view = output.get_slice(i_port); // View of the precoding weights applicable to a single antenna port, i.e., the coefficients applied to each // layer for the antenna port. diff --git a/lib/phy/generic_functions/precoding/channel_precoder_impl.h b/lib/phy/generic_functions/precoding/channel_precoder_impl.h index 11e697dc4a..d7b1f5b13c 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_impl.h +++ b/lib/phy/generic_functions/precoding/channel_precoder_impl.h @@ -25,7 +25,7 @@ class channel_precoder_impl : public channel_precoder explicit channel_precoder_impl() = default; // See interface for documentation. - void apply_precoding(re_buffer_writer<>& output, + void apply_precoding(re_buffer_writer& output, const re_buffer_reader<>& input, const precoding_weight_matrix& precoding) const override; @@ -35,8 +35,9 @@ class channel_precoder_impl : public channel_precoder /// \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. - virtual void - apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const = 0; + virtual void apply_precoding_port(span port_re, + const re_buffer_reader<>& input_re, + span port_weights) const = 0; }; } // namespace srsran diff --git a/lib/phy/generic_functions/precoding/channel_precoder_neon.cpp b/lib/phy/generic_functions/precoding/channel_precoder_neon.cpp index 23669f14c6..6f5302f5bb 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_neon.cpp +++ b/lib/phy/generic_functions/precoding/channel_precoder_neon.cpp @@ -62,9 +62,30 @@ simd_cf_interleaved add_mul(const simd_cf_interleaved& sum, const simd_cf_interl return ret; } +inline uint16x8_t cf_to_cbf16(simd_cf_interleaved in) +{ + const uint32x4_t bias = vdupq_n_u32(0x7fff); + const uint32x4_t one = vdupq_n_u32(0x1); + + // Reinterpret the 32-bit single-precision input as unsigned 32-bit integer. + uint32x4_t a_u32 = vreinterpretq_u32_f32(in.val[0]); + uint32x4_t b_u32 = vreinterpretq_u32_f32(in.val[1]); + + // Round to nearest even. + a_u32 = vaddq_u32(a_u32, vaddq_u32(bias, vandq_u32(vshrq_n_u32(a_u32, 16), one))); + b_u32 = vaddq_u32(b_u32, vaddq_u32(bias, vandq_u32(vshrq_n_u32(b_u32, 16), one))); + + // Remove the 16 least significant bits of the fractional part. + a_u32 = vshrq_n_u32(a_u32, 16); + b_u32 = vandq_u32(b_u32, vdupq_n_u32(0xffff0000)); + + // Combine real and imaginary parts. + return vreinterpretq_u16_u32(vorrq_u32(a_u32, b_u32)); +} + } // namespace -void channel_precoder_neon::apply_precoding_port(span port_re, +void channel_precoder_neon::apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const { @@ -103,15 +124,17 @@ void channel_precoder_neon::apply_precoding_port(span port_ } // Store. - vst2q_f32(reinterpret_cast(&port_re[i_re]), re_out); + vst1q_u16(reinterpret_cast(&port_re[i_re]), cf_to_cbf16(re_out)); } for (; i_re != nof_re; ++i_re) { - port_re[i_re] = layer_re_view_list[0][i_re] * port_weights[0]; + cf_t sum = layer_re_view_list[0][i_re] * port_weights[0]; for (unsigned i_layer = 1; i_layer != nof_layers; ++i_layer) { - port_re[i_re] += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; + sum += layer_re_view_list[i_layer][i_re] * port_weights[i_layer]; } + + port_re[i_re] = sum; } } @@ -162,27 +185,6 @@ static inline void from_ci8_to_cf(simd_cf_interleaved& out0, from_ci32_to_cf(out3, in_ci32_3); } -inline uint16x8_t cf_to_cbf16(simd_cf_interleaved in) -{ - const uint32x4_t bias = vdupq_n_u32(0x7fff); - const uint32x4_t one = vdupq_n_u32(0x1); - - // Reinterpret the 32-bit single-precision input as unsigned 32-bit integer. - uint32x4_t a_u32 = vreinterpretq_u32_f32(in.val[0]); - uint32x4_t b_u32 = vreinterpretq_u32_f32(in.val[1]); - - // Round to nearest even. - a_u32 = vaddq_u32(a_u32, vaddq_u32(bias, vandq_u32(vshrq_n_u32(a_u32, 16), one))); - b_u32 = vaddq_u32(b_u32, vaddq_u32(bias, vandq_u32(vshrq_n_u32(b_u32, 16), one))); - - // Remove the 16 least significant bits of the fractional part. - a_u32 = vshrq_n_u32(a_u32, 16); - b_u32 = vandq_u32(b_u32, vdupq_n_u32(0xffff0000)); - - // Combine real and imaginary parts. - return vreinterpretq_u16_u32(vorrq_u32(a_u32, b_u32)); -} - // Applies layer mapping for two layers and converts the symbols to cf_t. static inline void layer2_map_and_ci8_to_cf(simd_cf_interleaved& out0_l0, simd_cf_interleaved& out0_l1, diff --git a/lib/phy/generic_functions/precoding/channel_precoder_neon.h b/lib/phy/generic_functions/precoding/channel_precoder_neon.h index 96503c750d..58eed2eeb3 100644 --- a/lib/phy/generic_functions/precoding/channel_precoder_neon.h +++ b/lib/phy/generic_functions/precoding/channel_precoder_neon.h @@ -22,7 +22,7 @@ class channel_precoder_neon : public channel_precoder_impl { public: // See interface for documentation. - void apply_precoding_port(span port_re, + void apply_precoding_port(span port_re, const re_buffer_reader<>& input_re, span port_weights) const override; diff --git a/lib/phy/support/resource_grid_mapper_impl.cpp b/lib/phy/support/resource_grid_mapper_impl.cpp index 7cb9557a26..68cf3da2a0 100644 --- a/lib/phy/support/resource_grid_mapper_impl.cpp +++ b/lib/phy/support/resource_grid_mapper_impl.cpp @@ -15,7 +15,7 @@ using namespace srsran; -using precoding_buffer_type = static_re_buffer; +using precoding_buffer_type = static_re_buffer; // Resource element allocation patterns within a resource block for PDSCH DM-RS type 1. static const re_prb_mask& get_re_mask_type_1(unsigned cdm_group_id) @@ -46,7 +46,6 @@ static void map_dmrs_type1_contiguous(resource_grid_writer& writer, static constexpr unsigned re_stride = 2; static constexpr unsigned nof_dmrs_re_prb = NRE / re_stride; - unsigned nof_layers = precoding.get_nof_layers(); unsigned nof_precoding_ports = precoding.get_nof_ports(); // PRG size in number of RB. @@ -78,19 +77,6 @@ static void map_dmrs_type1_contiguous(resource_grid_writer& writer, continue; } - // Bypass precoding if it has no effect on the signal. - if ((nof_layers == 1) && (nof_precoding_ports == 1) && (precoding.get_nof_prg() == 1) && - (precoding.get_coefficient(0, 0, 0) == 1.0F)) { - // View over the input RE belonging to the current symbol. - re_buffer_reader_view input_re_symbol(input, i_re_buffer, nof_re_symbol); - - // Map directly to the grid. - span port_data = input_re_symbol.get_slice(0); - writer.put(0, i_symbol, first_subcarrier, re_stride, port_data); - i_re_buffer += nof_re_symbol; - continue; - } - // Counter for the number of precoded REs for the current symbol. unsigned i_precoding_buffer = 0; // First PRG in the allocation pattern. @@ -109,8 +95,8 @@ static void map_dmrs_type1_contiguous(resource_grid_writer& writer, unsigned nof_re_prg = (prg_prb_end - prg_prb_start) * nof_dmrs_re_prb; // Views of the input and precoder buffers for the REs belonging to the current PRG. - re_buffer_reader_view input_re_prg(input, i_re_buffer, nof_re_prg); - re_buffer_writer_view output_re_prg(precoding_buffer, i_precoding_buffer, nof_re_prg); + re_buffer_reader_view input_re_prg(input, i_re_buffer, nof_re_prg); + re_buffer_writer_view output_re_prg(precoding_buffer, i_precoding_buffer, nof_re_prg); // Apply precoding. precoder.apply_precoding(output_re_prg, input_re_prg, prg_weights); @@ -128,7 +114,7 @@ static void map_dmrs_type1_contiguous(resource_grid_writer& writer, for (unsigned i_tx_port = 0; i_tx_port != nof_precoding_ports; ++i_tx_port) { // Map the precoded REs to each port for the current symbol. - span port_data = precoding_buffer.get_slice(i_tx_port); + span port_data = precoding_buffer.get_slice(i_tx_port); writer.put(i_tx_port, i_symbol, first_subcarrier, re_stride, port_data); } } @@ -243,8 +229,8 @@ void resource_grid_mapper_impl::map(const re_buffer_reader<>& input, unsigned nof_re_prg = prg_re_mask.count(); // Views of the input and precoder buffers for the REs belonging to the current PRG. - re_buffer_reader_view input_re_prg(input, i_re_buffer, nof_re_prg); - re_buffer_writer_view output_re_prg(precoding_buffer, i_precoding_buffer, nof_re_prg); + re_buffer_reader_view input_re_prg(input, i_re_buffer, nof_re_prg); + re_buffer_writer_view output_re_prg(precoding_buffer, i_precoding_buffer, nof_re_prg); // Apply precoding. precoder->apply_precoding(output_re_prg, input_re_prg, prg_weights); @@ -265,8 +251,8 @@ void resource_grid_mapper_impl::map(const re_buffer_reader<>& input, for (unsigned i_tx_port = 0; i_tx_port != nof_precoding_ports; ++i_tx_port) { // Map the precoded REs to each port for the current symbol. - span port_data = precoding_buffer.get_slice(i_tx_port); - span unmapped = writer.put(i_tx_port, i_symbol, 0, symbol_re_mask, port_data); + span port_data = precoding_buffer.get_slice(i_tx_port); + span unmapped = writer.put(i_tx_port, i_symbol, 0, symbol_re_mask, port_data); srsran_assert(unmapped.empty(), "Not all REs have been mapped to the grid."); } } diff --git a/lib/phy/support/resource_grid_writer_impl.cpp b/lib/phy/support/resource_grid_writer_impl.cpp index 92e82efd67..5bb2aa9394 100644 --- a/lib/phy/support/resource_grid_writer_impl.cpp +++ b/lib/phy/support/resource_grid_writer_impl.cpp @@ -133,11 +133,11 @@ void resource_grid_writer_impl::put(unsigned port, unsigned l, unsigned k_init, clear_empty(port); } -void resource_grid_writer_impl::put(unsigned port, - unsigned l, - unsigned k_init, - unsigned stride, - span symbols) +void resource_grid_writer_impl::put(unsigned port, + unsigned l, + unsigned k_init, + unsigned stride, + span symbols) { unsigned nof_symbols = symbols.size(); srsran_assert( diff --git a/lib/phy/support/resource_grid_writer_impl.h b/lib/phy/support/resource_grid_writer_impl.h index c66aef938f..26d5d34514 100644 --- a/lib/phy/support/resource_grid_writer_impl.h +++ b/lib/phy/support/resource_grid_writer_impl.h @@ -50,7 +50,7 @@ class resource_grid_writer_impl : public resource_grid_writer void put(unsigned port, unsigned l, unsigned k_init, span symbols) override; // See interface for documentation. - void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override; + void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override; // See interface for documentation. span get_view(unsigned port, unsigned l) override; diff --git a/lib/phy/support/support_factories.cpp b/lib/phy/support/support_factories.cpp index f1b0a4dbb5..639b2fe1bb 100644 --- a/lib/phy/support/support_factories.cpp +++ b/lib/phy/support/support_factories.cpp @@ -133,7 +133,7 @@ class channel_precoder_dummy : public channel_precoder { public: // See interface for documentation. - void apply_precoding(re_buffer_writer<>& output, + void apply_precoding(re_buffer_writer& output, const re_buffer_reader<>& input, const precoding_weight_matrix& precoding) const override { diff --git a/lib/phy/upper/signal_processors/dmrs_pbch_processor_impl.cpp b/lib/phy/upper/signal_processors/dmrs_pbch_processor_impl.cpp index 78d879ba7b..14353fd6cb 100644 --- a/lib/phy/upper/signal_processors/dmrs_pbch_processor_impl.cpp +++ b/lib/phy/upper/signal_processors/dmrs_pbch_processor_impl.cpp @@ -10,7 +10,7 @@ #include "dmrs_pbch_processor_impl.h" #include "srsran/phy/support/resource_grid_writer.h" -#include "srsran/srsvec/sc_prod.h" +#include "srsran/srsvec/conversion.h" using namespace srsran; @@ -48,8 +48,12 @@ void dmrs_pbch_processor_impl::mapping(const std::array& r, // For each port... for (unsigned port : args.ports) { + // Convert symbols to complex BF16. + std::array symbols_cbf16; + srsvec::convert(symbols_cbf16, r); + // Create view with the symbols. - span symbols = r; + span symbols = symbols_cbf16; // Put sequence in symbol 1 (0 + v , 4 + v , 8 + v ,..., 236 + v). grid.put(port, l0 + 1, k0 + v, stride, symbols.first(nof_dmrs_full_symbol)); diff --git a/tests/benchmarks/phy/upper/precoding/channel_precoder_benchmark.cpp b/tests/benchmarks/phy/upper/precoding/channel_precoder_benchmark.cpp index a4b89a2211..b6bd2faa16 100644 --- a/tests/benchmarks/phy/upper/precoding/channel_precoder_benchmark.cpp +++ b/tests/benchmarks/phy/upper/precoding/channel_precoder_benchmark.cpp @@ -96,8 +96,7 @@ int main(int argc, char** argv) // Create input and output RE buffers. dynamic_re_buffer input_re(nof_layers, nof_re); - dynamic_re_buffer precoded_re(nof_ports, nof_re); - dynamic_re_buffer precoded_re_cbf16(nof_ports, nof_re); + dynamic_re_buffer precoded_re(nof_ports, nof_re); std::vector input_symbols(nof_layers * nof_re); precoding_weight_matrix weights(nof_layers, nof_ports); @@ -129,8 +128,8 @@ int main(int argc, char** argv) precoder->apply_precoding(precoded_re, input_re, weights); }); - perf_meas_ci8.new_measure(meas_descr, nof_re, [&precoded_re_cbf16, &input_symbols, &weights, &precoder]() { - precoder->apply_layer_map_and_precoding(precoded_re_cbf16, input_symbols, weights); + perf_meas_ci8.new_measure(meas_descr, nof_re, [&precoded_re, &input_symbols, &weights, &precoder]() { + precoder->apply_layer_map_and_precoding(precoded_re, input_symbols, weights); }); } diff --git a/tests/unittests/ofh/receiver/helpers.h b/tests/unittests/ofh/receiver/helpers.h index 08bba7eafa..6346b8adab 100644 --- a/tests/unittests/ofh/receiver/helpers.h +++ b/tests/unittests/ofh/receiver/helpers.h @@ -98,7 +98,7 @@ class resource_grid_writer_bool_spy : public resource_grid_writer nof_prbs_written += symbols.size() / NOF_SUBCARRIERS_PER_RB; } - void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override + void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override { grid_written = true; nof_prbs_written += divide_ceil(symbols.size() * stride, NOF_SUBCARRIERS_PER_RB); 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 279ab3e99b..082919e009 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 @@ -115,8 +115,8 @@ class resource_grid_dummy : public resource_grid 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 {} + 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 {}; } }; diff --git a/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp b/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp index ad2432761b..4884cdec33 100644 --- a/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp +++ b/tests/unittests/phy/generic_functions/precoding/channel_precoder_test.cpp @@ -32,21 +32,12 @@ using MultiplePRGParams = std::tuple< namespace srsran { -static float ASSERT_MAX_ERROR = 1e-4; - static std::ostream& operator<<(std::ostream& os, span data) { fmt::print(os, "{}", data); return os; } -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); - }); -} - static bool operator==(span lhs, span rhs) { static constexpr float max_relative_error_cbf16 = 1.0F / 256.0F; @@ -232,8 +223,8 @@ TEST_P(PrecodingFixture, RandomWeightsCft) unsigned nof_re = nof_rb * NRE; // Buffer to hold the precoded RE. - static_re_buffer precoding_buffer(nof_ports, - nof_re); + static_re_buffer precoding_buffer( + nof_ports, nof_re); for (unsigned nof_layers = 1; nof_layers <= nof_ports; ++nof_layers) { // Generate random RE arranged by layers. const re_buffer_reader<>& input_data = generate_random_data(nof_layers, nof_re); @@ -249,7 +240,7 @@ TEST_P(PrecodingFixture, RandomWeightsCft) // For each antenna port, compare the precoded RE with the golden sequence for all RE and PRG. for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { - ASSERT_EQ(span(golden.get_slice(i_port)), span(precoding_buffer.get_slice(i_port))); + ASSERT_EQ(span(golden.get_slice(i_port)), span(precoding_buffer.get_slice(i_port))); } } } diff --git a/tests/unittests/phy/support/resource_grid_test_doubles.h b/tests/unittests/phy/support/resource_grid_test_doubles.h index 459a9570bc..405074c5fd 100644 --- a/tests/unittests/phy/support/resource_grid_test_doubles.h +++ b/tests/unittests/phy/support/resource_grid_test_doubles.h @@ -127,13 +127,11 @@ class resource_grid_writer_spy : public resource_grid_writer } } - void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override + void put(unsigned port, unsigned l, unsigned k_init, unsigned stride, span symbols) override { ++count; for (unsigned i_symb = 0; i_symb != symbols.size(); ++i_symb) { - if ((symbols[i_symb].real() != 0) || (symbols[i_symb].imag() != 0)) { - put(port, l, k_init + (i_symb * stride), symbols[i_symb]); - } + data[{k_init + i_symb * stride, l, port}] = symbols[i_symb]; } } From 91e7ac1f78c13effb29dce5e823c093ce4e2e458 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 17 Jul 2024 12:54:58 +0100 Subject: [PATCH 31/34] cu_cp: fix incorrect sctp parameters --- include/srsran/support/io/sctp_socket.h | 31 +++++++++++++++++++ .../gateways/n2_connection_client_factory.cpp | 20 +++++++----- lib/support/network/sctp_socket.cpp | 14 +++------ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/include/srsran/support/io/sctp_socket.h b/include/srsran/support/io/sctp_socket.h index 3441b6b241..4b82e6cebd 100644 --- a/include/srsran/support/io/sctp_socket.h +++ b/include/srsran/support/io/sctp_socket.h @@ -75,3 +75,34 @@ class sctp_socket }; } // namespace srsran + +namespace fmt { +template <> +struct formatter { + template + auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template + auto format(const srsran::sctp_socket_params& cfg, FormatContext& ctx) + { + return format_to(ctx.out(), + "if_name={} ai_family={} ai_socktype={} reuse_addr={} non_blockin_mode={} rx_timeout={} " + "rto_initial={} rto_min={} rto_max={} init_max_attempts={} max_init_timeo={} no_delay={}", + cfg.if_name, + cfg.ai_family, + cfg.ai_socktype, + cfg.reuse_addr, + cfg.non_blocking_mode, + cfg.rx_timeout.count(), + cfg.rto_initial, + cfg.rto_min, + cfg.rto_max, + cfg.init_max_attempts, + cfg.max_init_timeo, + cfg.nodelay); + } +}; +} // namespace fmt diff --git a/lib/ngap/gateways/n2_connection_client_factory.cpp b/lib/ngap/gateways/n2_connection_client_factory.cpp index 96e542a70c..671edc479f 100644 --- a/lib/ngap/gateways/n2_connection_client_factory.cpp +++ b/lib/ngap/gateways/n2_connection_client_factory.cpp @@ -232,6 +232,7 @@ class n2_sctp_gateway_client : public n2_connection_client sctp_cfg.connect_address, sctp_cfg.connect_port, std::make_unique(std::move(cu_cp_rx_pdu_notifier), pcap_writer, logger)); + if (sctp_sender == nullptr) { logger.error( "Failed to establish N2 TNL connection to AMF on {}:{}.\n", sctp_cfg.connect_address, sctp_cfg.connect_port); @@ -275,12 +276,17 @@ srsran::srs_cu_cp::create_n2_connection_client(const n2_connection_client_config // Connection to AMF through SCTP. const auto& nw_mode = std::get(params.mode); srsran::sctp_network_connector_config sctp_cfg; - sctp_cfg.dest_name = "AMF"; - sctp_cfg.if_name = "N2"; - sctp_cfg.connect_address = nw_mode.amf_address; - sctp_cfg.connect_port = nw_mode.amf_port; - sctp_cfg.bind_address = nw_mode.bind_address; - sctp_cfg.bind_interface = nw_mode.bind_interface; - sctp_cfg.ppid = NGAP_PPID; + sctp_cfg.dest_name = "AMF"; + sctp_cfg.if_name = "N2"; + sctp_cfg.connect_address = nw_mode.amf_address; + sctp_cfg.connect_port = nw_mode.amf_port; + sctp_cfg.bind_address = nw_mode.bind_address; + sctp_cfg.bind_interface = nw_mode.bind_interface; + sctp_cfg.rto_initial = nw_mode.rto_initial; + sctp_cfg.rto_min = nw_mode.rto_min; + sctp_cfg.rto_max = nw_mode.rto_max; + sctp_cfg.init_max_attempts = nw_mode.init_max_attempts; + sctp_cfg.max_init_timeo = nw_mode.max_init_timeo; + sctp_cfg.ppid = NGAP_PPID; return std::make_unique(nw_mode.broker, sctp_cfg, params.pcap); } diff --git a/lib/support/network/sctp_socket.cpp b/lib/support/network/sctp_socket.cpp index ab0bc5a2fc..f221483e40 100644 --- a/lib/support/network/sctp_socket.cpp +++ b/lib/support/network/sctp_socket.cpp @@ -9,10 +9,11 @@ */ #include "srsran/support/io/sctp_socket.h" +#include "srsran/adt/optional.h" #include "srsran/srslog/srslog.h" #include "srsran/support/error_handling.h" -#include "srsran/support/format_utils.h" #include "srsran/support/io/sockets.h" +#include "srsran/support/srsran_assert.h" #include #include #include @@ -31,10 +32,7 @@ bool sctp_subscribe_to_events(const unique_fd& fd) events.sctp_shutdown_event = 1; events.sctp_association_event = 1; - if (::setsockopt(fd.value(), IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)) != 0) { - return false; - } - return true; + return ::setsockopt(fd.value(), IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)) == 0; } /// \brief Modify SCTP default parameters for quicker detection of broken links. @@ -143,10 +141,7 @@ bool sctp_set_nodelay(const unique_fd& fd, std::optional nodelay) } int optval = nodelay.value() ? 1 : 0; - if (::setsockopt(fd.value(), IPPROTO_SCTP, SCTP_NODELAY, &optval, sizeof(optval)) != 0) { - return false; - } - return true; + return ::setsockopt(fd.value(), IPPROTO_SCTP, SCTP_NODELAY, &optval, sizeof(optval)) == 0; } } // namespace @@ -299,6 +294,7 @@ bool sctp_socket::set_non_blocking() bool sctp_socket::set_sockopts(const sctp_socket_params& params) { + logger.debug("Setting socket options. params=[{}]", params); if (not sctp_subscribe_to_events(sock_fd)) { logger.error( "{}: SCTP failed to be created. Cause: Subscribing to SCTP events failed: {}", if_name, strerror(errno)); From 41d02a6a9c2aaced2112f8aab263232e45842bb3 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Fri, 12 Jul 2024 12:09:31 +0200 Subject: [PATCH 32/34] services: added buffer pool service, that will add the configuration, cli11 parsing and manager --- apps/cu/cu.cpp | 3 +- apps/cu/cu_appconfig.h | 1 + apps/cu/cu_appconfig_cli11_schema.cpp | 16 +++------- apps/du/du.cpp | 3 +- apps/du/du_appconfig.h | 2 +- apps/du/du_appconfig_cli11_schema.cpp | 17 ++++------- apps/gnb/gnb.cpp | 5 ++-- apps/gnb/gnb_appconfig.h | 8 +---- apps/gnb/gnb_appconfig_cli11_schema.cpp | 17 ++++------- apps/services/CMakeLists.txt | 3 +- apps/services/buffer_pool/CMakeLists.txt | 13 +++++++++ .../buffer_pool/buffer_pool_appconfig.h | 23 +++++++++++++++ .../buffer_pool_appconfig_cli11_schema.cpp | 29 +++++++++++++++++++ .../buffer_pool_appconfig_cli11_schema.h | 22 ++++++++++++++ .../buffer_pool/buffer_pool_manager.h | 29 +++++++++++++++++++ 15 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 apps/services/buffer_pool/CMakeLists.txt create mode 100644 apps/services/buffer_pool/buffer_pool_appconfig.h create mode 100644 apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.cpp create mode 100644 apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h create mode 100644 apps/services/buffer_pool/buffer_pool_manager.h diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 676cca2469..51321c0acf 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -59,6 +59,7 @@ #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" +#include "apps/services/buffer_pool/buffer_pool_manager.h" #include "apps/services/stdin_command_dispatcher.h" #include "apps/units/cu_cp/cu_cp_unit_config_yaml_writer.h" #include "apps/units/cu_up/cu_up_unit_config_yaml_writer.h" @@ -241,7 +242,7 @@ int main(int argc, char** argv) // TODO // Setup size of byte buffer pool. - init_byte_buffer_segment_pool(cu_cfg.buffer_pool_config.nof_segments, cu_cfg.buffer_pool_config.segment_size); + app_services::buffer_pool_manager buffer_pool_service(cu_cfg.buffer_pool_config); // Log CPU architecture. // TODO diff --git a/apps/cu/cu_appconfig.h b/apps/cu/cu_appconfig.h index 9dce29e844..5c5ab00f65 100644 --- a/apps/cu/cu_appconfig.h +++ b/apps/cu/cu_appconfig.h @@ -11,6 +11,7 @@ #pragma once #include "apps/gnb/gnb_appconfig.h" +#include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/logger/logger_appconfig.h" #include diff --git a/apps/cu/cu_appconfig_cli11_schema.cpp b/apps/cu/cu_appconfig_cli11_schema.cpp index d8d2aee8c5..fc27a9f27f 100644 --- a/apps/cu/cu_appconfig_cli11_schema.cpp +++ b/apps/cu/cu_appconfig_cli11_schema.cpp @@ -9,6 +9,7 @@ */ #include "cu_appconfig_cli11_schema.h" +#include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" #include "cu_appconfig.h" #include "srsran/support/cli11_utils.h" @@ -31,19 +32,14 @@ static void configure_cli11_nru_args(CLI::App& app, srs_cu::cu_nru_appconfig& nr add_option(app, "--udp_max_rx_msgs", nru_cfg.udp_rx_max_msgs, "Maximum amount of messages RX in a single syscall"); } -static void configure_cli11_buffer_pool_args(CLI::App& app, buffer_pool_appconfig& config) -{ - app.add_option("--nof_segments", config.nof_segments, "Number of segments allocated by the buffer pool") - ->capture_default_str(); - app.add_option("--segment_size", config.segment_size, "Size of each buffer pool segment in bytes") - ->capture_default_str(); -} - void srsran::configure_cli11_with_cu_appconfig_schema(CLI::App& app, cu_appconfig& cu_cfg) { // Logging section. configure_cli11_with_logger_appconfig_schema(app, cu_cfg.log_cfg); + // Buffer pool section. + configure_cli11_with_buffer_pool_appconfig_schema(app, cu_cfg.buffer_pool_config); + // F1AP section. CLI::App* cu_cp_subcmd = add_subcommand(app, "cu_cp", "CU-UP parameters")->configurable(); CLI::App* f1ap_subcmd = add_subcommand(*cu_cp_subcmd, "f1ap", "F1AP parameters")->configurable(); @@ -53,8 +49,4 @@ void srsran::configure_cli11_with_cu_appconfig_schema(CLI::App& app, cu_appconfi CLI::App* cu_up_subcmd = add_subcommand(app, "cu_up", "CU-UP parameters")->configurable(); CLI::App* nru_subcmd = add_subcommand(*cu_up_subcmd, "nru", "NR-U parameters")->configurable(); configure_cli11_nru_args(*nru_subcmd, cu_cfg.nru_cfg); - - // Buffer pool section. - CLI::App* buffer_pool_subcmd = app.add_subcommand("buffer_pool", "Buffer pool configuration")->configurable(); - configure_cli11_buffer_pool_args(*buffer_pool_subcmd, cu_cfg.buffer_pool_config); } diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 3ce5249249..4e1edb8867 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -49,6 +49,7 @@ #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" +#include "apps/services/buffer_pool/buffer_pool_manager.h" #include "apps/services/core_isolation_manager.h" #include "apps/services/metrics_plotter_json.h" #include "apps/services/metrics_plotter_stdout.h" @@ -228,7 +229,7 @@ int main(int argc, char** argv) #endif // Setup size of byte buffer pool. - init_byte_buffer_segment_pool(du_cfg.buffer_pool_config.nof_segments, du_cfg.buffer_pool_config.segment_size); + app_services::buffer_pool_manager buffer_pool_service(du_cfg.buffer_pool_config); // Log CPU architecture. cpu_architecture_info::get().print_cpu_info(du_logger); diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index 5a2a691696..e1a684a8fb 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -11,9 +11,9 @@ #pragma once #include "../gnb/gnb_appconfig.h" // TODO: Remove +#include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/logger/logger_appconfig.h" #include "apps/services/os_sched_affinity_manager.h" -#include "srsran/adt/byte_buffer.h" #include "srsran/support/executors/unique_thread.h" #include diff --git a/apps/du/du_appconfig_cli11_schema.cpp b/apps/du/du_appconfig_cli11_schema.cpp index 5fa84ecb60..105c90c40d 100644 --- a/apps/du/du_appconfig_cli11_schema.cpp +++ b/apps/du/du_appconfig_cli11_schema.cpp @@ -9,8 +9,10 @@ */ #include "du_appconfig_cli11_schema.h" +#include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" #include "du_appconfig.h" +#include "srsran/adt/interval.h" #include "srsran/support/cli11_utils.h" using namespace srsran; @@ -67,14 +69,6 @@ static void configure_cli11_e2_args(CLI::App& app, e2_appconfig& e2_params) add_option(app, "--e2sm_rc_enabled", e2_params.e2sm_rc_enabled, "Enable RC service module")->capture_default_str(); } -static void configure_cli11_buffer_pool_args(CLI::App& app, buffer_pool_appconfig& config) -{ - app.add_option("--nof_segments", config.nof_segments, "Number of segments allocated by the buffer pool") - ->capture_default_str(); - app.add_option("--segment_size", config.segment_size, "Size of each buffer pool segment in bytes") - ->capture_default_str(); -} - static error_type is_valid_cpu_index(unsigned cpu_idx) { std::string error_message = fmt::format("Invalid CPU core selected '{}'. Valid CPU ids: {}", @@ -256,6 +250,9 @@ void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfi // Loggers section. configure_cli11_with_logger_appconfig_schema(app, du_cfg.log_cfg); + // Buffer pool section. + configure_cli11_with_buffer_pool_appconfig_schema(app, du_cfg.buffer_pool_config); + // F1-C section. CLI::App* f1ap_subcmd = app.add_subcommand("f1ap", "F1AP interface configuration")->configurable(); configure_cli11_f1ap_args(*f1ap_subcmd, du_cfg.f1ap_cfg); @@ -272,10 +269,6 @@ void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfi CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); configure_cli11_e2_args(*e2_subcmd, du_cfg.e2_cfg); - // Buffer pool section. - CLI::App* buffer_pool_subcmd = app.add_subcommand("buffer_pool", "Buffer pool configuration")->configurable(); - configure_cli11_buffer_pool_args(*buffer_pool_subcmd, du_cfg.buffer_pool_config); - // Expert section. CLI::App* expert_subcmd = app.add_subcommand("expert_execution", "Expert execution configuration")->configurable(); configure_cli11_expert_execution_args(*expert_subcmd, du_cfg.expert_execution_cfg); diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index b4c45c1e40..4c86583b24 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -60,6 +60,7 @@ #include #include "apps/services/application_message_banners.h" +#include "apps/services/buffer_pool/buffer_pool_manager.h" #include "apps/services/core_isolation_manager.h" #include "apps/services/metrics_plotter_json.h" #include "apps/services/metrics_plotter_stdout.h" @@ -283,8 +284,8 @@ int main(int argc, char** argv) } #endif - // Setup size of byte buffer pool. - init_byte_buffer_segment_pool(gnb_cfg.buffer_pool_config.nof_segments, gnb_cfg.buffer_pool_config.segment_size); + // Buffer pool service. + app_services::buffer_pool_manager buffer_pool_service(gnb_cfg.buffer_pool_config); // Log CPU architecture. cpu_architecture_info::get().print_cpu_info(gnb_logger); diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 43f42687ee..bcce88e704 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -10,10 +10,9 @@ #pragma once +#include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/logger/logger_appconfig.h" #include "apps/services/os_sched_affinity_manager.h" -#include "srsran/adt/byte_buffer.h" -#include "srsran/ran/direct_current_offset.h" #include "srsran/ran/gnb_id.h" #include "srsran/support/executors/unique_thread.h" #include @@ -54,11 +53,6 @@ struct metrics_appconfig { unsigned stdout_metrics_period = 1000; // Statistics report period in milliseconds }; -struct buffer_pool_appconfig { - std::size_t nof_segments = 1048576; - std::size_t segment_size = byte_buffer_segment_pool_default_segment_size(); -}; - /// CPU affinities configuration for the gNB app. struct cpu_affinities_appconfig { /// CPUs isolation. diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 93cc7b9c40..9ba7c98f1b 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -9,8 +9,10 @@ */ #include "gnb_appconfig_cli11_schema.h" +#include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" #include "gnb_appconfig.h" +#include "srsran/adt/interval.h" #include "srsran/support/cli11_utils.h" #include "srsran/support/error_handling.h" #include "CLI/CLI11.hpp" @@ -72,14 +74,6 @@ static void configure_cli11_e2_args(CLI::App& app, e2_appconfig& e2_params) add_option(app, "--e2sm_rc_enabled", e2_params.e2sm_rc_enabled, "Enable RC service module")->capture_default_str(); } -static void configure_cli11_buffer_pool_args(CLI::App& app, buffer_pool_appconfig& config) -{ - app.add_option("--nof_segments", config.nof_segments, "Number of segments allocated by the buffer pool") - ->capture_default_str(); - app.add_option("--segment_size", config.segment_size, "Size of each buffer pool segment in bytes") - ->capture_default_str(); -} - static void configure_cli11_hal_args(CLI::App& app, std::optional& config) { config.emplace(); @@ -262,6 +256,9 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon // Loggers section. configure_cli11_with_logger_appconfig_schema(app, gnb_cfg.log_cfg); + // Buffer pool section. + configure_cli11_with_buffer_pool_appconfig_schema(app, gnb_cfg.buffer_pool_config); + // Metrics section. CLI::App* metrics_subcmd = app.add_subcommand("metrics", "Metrics configuration")->configurable(); configure_cli11_metrics_args(*metrics_subcmd, gnb_cfg.metrics_cfg); @@ -270,10 +267,6 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); configure_cli11_e2_args(*e2_subcmd, gnb_cfg.e2_cfg); - // Buffer pool section. - CLI::App* buffer_pool_subcmd = app.add_subcommand("buffer_pool", "Buffer pool configuration")->configurable(); - configure_cli11_buffer_pool_args(*buffer_pool_subcmd, gnb_cfg.buffer_pool_config); - // Expert section. CLI::App* expert_subcmd = app.add_subcommand("expert_execution", "Expert execution configuration")->configurable(); configure_cli11_expert_execution_args(*expert_subcmd, gnb_cfg.expert_execution_cfg); diff --git a/apps/services/CMakeLists.txt b/apps/services/CMakeLists.txt index 101324a794..406c0bde0f 100644 --- a/apps/services/CMakeLists.txt +++ b/apps/services/CMakeLists.txt @@ -6,6 +6,7 @@ # the distribution. # +add_subdirectory(buffer_pool) add_subdirectory(logger) set(SOURCES @@ -20,4 +21,4 @@ set(SOURCES add_library(srsran_app_services STATIC ${SOURCES}) target_include_directories(srsran_app_services PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_app_services srsran_logger_app_service) +target_link_libraries(srsran_app_services srsran_logger_app_service srsran_buffer_pool_app_service) diff --git a/apps/services/buffer_pool/CMakeLists.txt b/apps/services/buffer_pool/CMakeLists.txt new file mode 100644 index 0000000000..1afb8842d6 --- /dev/null +++ b/apps/services/buffer_pool/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# 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 + buffer_pool_appconfig_cli11_schema.cpp) + +add_library(srsran_buffer_pool_app_service STATIC ${SOURCES}) +target_include_directories(srsran_buffer_pool_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/buffer_pool/buffer_pool_appconfig.h b/apps/services/buffer_pool/buffer_pool_appconfig.h new file mode 100644 index 0000000000..d5f86d3417 --- /dev/null +++ b/apps/services/buffer_pool/buffer_pool_appconfig.h @@ -0,0 +1,23 @@ +/* + * + * 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" + +namespace srsran { + +/// Buffer pool application configuration. +struct buffer_pool_appconfig { + std::size_t nof_segments = 1048576; + std::size_t segment_size = byte_buffer_segment_pool_default_segment_size(); +}; + +} // namespace srsran diff --git a/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.cpp b/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.cpp new file mode 100644 index 0000000000..7960c52a25 --- /dev/null +++ b/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.cpp @@ -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. + * + */ + +#include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" +#include "apps/services/buffer_pool/buffer_pool_appconfig.h" + +using namespace srsran; + +static void configure_cli11_buffer_pool_args(CLI::App& app, buffer_pool_appconfig& config) +{ + app.add_option("--nof_segments", config.nof_segments, "Number of segments allocated by the buffer pool") + ->capture_default_str(); + app.add_option("--segment_size", config.segment_size, "Size of each buffer pool segment in bytes") + ->capture_default_str(); +} + +void srsran::configure_cli11_with_buffer_pool_appconfig_schema(CLI::App& app, buffer_pool_appconfig& config) +{ + // Buffer pool section. + CLI::App* buffer_pool_subcmd = app.add_subcommand("buffer_pool", "Buffer pool configuration")->configurable(); + configure_cli11_buffer_pool_args(*buffer_pool_subcmd, config); +} diff --git a/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h b/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h new file mode 100644 index 0000000000..fc0053ea71 --- /dev/null +++ b/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.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 + +namespace srsran { + +struct buffer_pool_appconfig; + +/// Configures the given CLI11 application with the logger application configuration schema. +void configure_cli11_with_buffer_pool_appconfig_schema(CLI::App& app, buffer_pool_appconfig& config); + +} // namespace srsran diff --git a/apps/services/buffer_pool/buffer_pool_manager.h b/apps/services/buffer_pool/buffer_pool_manager.h new file mode 100644 index 0000000000..cd71834227 --- /dev/null +++ b/apps/services/buffer_pool/buffer_pool_manager.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 + +#include "apps/services/buffer_pool/buffer_pool_appconfig.h" + +namespace srsran { +namespace app_services { + +/// Buffer pool manager for the applications. +class buffer_pool_manager +{ +public: + explicit buffer_pool_manager(const buffer_pool_appconfig& config) + { + init_byte_buffer_segment_pool(config.nof_segments, config.segment_size); + } +}; + +} // namespace app_services +} // namespace srsran From f379a0a50b68799da9bbba4343a8f3a1faa84d57 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 17 Jul 2024 11:30:00 +0200 Subject: [PATCH 33/34] ci: modify viavi bitrate thresholds --- tests/e2e/tests/viavi/test_declaration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 081c54df64..111217b473 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -21,8 +21,8 @@ campaign_filename: &campaign_filename "C:\\ci\\CI 4x4 ORAN-FH-complete.xml" gnb_extra_commands: &gnb_extra_commands "" -expected_dl_bitrate_high: &expected_dl_bitrate_high 1400000000 -expected_ul_bitrate_high: &expected_ul_bitrate_high 100000000 +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 expected_ul_bitrate_low: &expected_ul_bitrate_low 1000 test_timeout: &test_timeout 2700 # 45 * 60 From 24126794432962f25b199f00e43c6410a51dea47 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 17 Jul 2024 17:36:05 +0200 Subject: [PATCH 34/34] ci,e2e: update amari agent to include a wait before closing --- .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 1e88bf0e34..d185555c50 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.7 +RETINA_VERSION=0.51.8 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11